module server;

import util;

class NetworkAudioStream : SoundStream
{
public:
	static this()
	{
		s_sync = new Object();
	}

	// Default constructor
	this()
	{
		myListener = new SocketTCP();
		myClient = new SocketTCP();
		// Set the sound parameters
		super(1, 44100);
	}

	// Destructor
	~this()
	{
		// Close the sockets
		delete myClient;
		delete myListener;
	}

	// Run the server, stream audio data from the client
	void start(int Port)
	{
		if (!myHasFinished)
		{
			// Listen to the given port for incoming connections
			if (!myListener.listen(Port))
				return;
			Cout("Listening").newline;
			myListener.accept(myClient);
			Cout("New Client").newline;
			// Start playback
			play();

			// Start receiving audio data
			receiveLoop();
		}
		else
		{
			// Start playback
			play();
		}
	}

protected:

	override bool onStart()
	{
		// Reset the playing offset
		myOffset = 0;

		return true;
	}

	override bool onGetData(out short[] data)
	{
		// We have reached the end of the buffer and all audio data have been played : we can stop playback
		if ((myOffset == mySamples.length) && myHasFinished)
			return false;
		// No new data has arrived since last update : wait until we get some
		while (myOffset == mySamples.length && !myHasFinished)
			sleep(0.01f);
				
		synchronized(s_sync)
		{
			myTempBuffer = mySamples[myOffset..mySamples.length];
			// Update the playing offset
			myOffset += myTempBuffer.length;
		}
	
		data = myTempBuffer;
		return true;
	}

private:

	void receiveLoop()
	{
		while (!myHasFinished)
		{
			// Get waiting audio data from the network
			Packet PacketIn = new Packet();
			if (myClient.receive(PacketIn) != SocketStatus.DONE)
				break;

			// Extract the message ID
			ubyte Id;
			PacketIn.get(Id);

			if (Id == AudioData)
			{
				// Extract audio samples from the packet, and append it to our samples buffer
				
				synchronized(s_sync)
				{
					byte* temp = PacketIn.getData().ptr;
					temp++;

					mySamples ~= (cast(short*)temp)[0..(PacketIn.getDataSize - byte.sizeof ) / short.sizeof];
				}
			}
			else if (Id == EndOfStream)
			{
				// End of stream reached : we stop receiving audio data
				myHasFinished = true;
			}
			else
			{
				// Something's wrong...
				myHasFinished = true;
			}
		}
	}

	SocketTCP		myListener;
	SocketTCP		myClient;
	short[]		 mySamples;
	short[]		 myTempBuffer;
	size_t		  myOffset;
	bool			myHasFinished;
	
	static Object	s_sync; 
};



// Launch a server and wait for incoming audio data from
// a connected client
void runServer(int Port)
{
	// Build an audio stream to play sound data as it is received through the network
	NetworkAudioStream audioStream = new NetworkAudioStream;
	audioStream.start(Port);

	// Loop until the sound playback is finished
	while (audioStream.getStatus() != SoundStatus.STOPPED)
	{
		// Leave some CPU time for other threads
		sleep(0.1f);
	}
	
	Cout("Enter to replay").newline;
	Cin.get();
	// Replay the sound (just to make sure replaying the received data is OK)
	audioStream.play();

	// Loop until the sound playback is finished
	while (audioStream.getStatus() != SoundStatus.STOPPED)
	{
		// Leave some CPU time for other threads
		sleep(0.1f);
	}
}