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);
    }
}