/*
* TimeCastSrvr.c              (c) Bob Quinn              3/15/97
*
* Released to the public domain
*
* Description:
*  Sample multicast server (sender) application that multicasts the
*  system time for clients (receivers) to use to set their clocks.
*/
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <SFML/Audio.hpp>


#define BUFSIZE     1024
#define MAXADDRSTR  16

#define TIMECAST_ADDR   "234.5.6.7"
#define TIMECAST_PORT   8910
#define TIMECAST_TTL    2
#define TIMECAST_INTRVL 0

char achMCAddr[MAXADDRSTR] = TIMECAST_ADDR;
u_long lMCAddr;
u_short nPort              = TIMECAST_PORT;
u_long  lTTL               = TIMECAST_TTL;
u_short nInterval          = TIMECAST_INTRVL;
SYSTEMTIME stSysTime;

class MyStream : public sf::SoundStream
{
public:

	
    std::vector<sf::Int16> m_samples;
    std::size_t m_currentSample;
	HANDLE sem;

    void load(sf::Int16* buffer, size_t sampleCount, size_t sampleRate, size_t channelCount)
    {
		sem = CreateSemaphore(NULL, 1, 1, NULL);

        // extract the audio samples from the sound buffer to our own container
        m_samples.assign(buffer, buffer + sampleCount);

        // reset the current playing position 
        m_currentSample = 0;

        // initialize the base class
        initialize(channelCount, sampleRate);
    }

	void add(sf::Int16* buffer, size_t size)
	{
		// check semaphore
		WaitForSingleObject(sem, INFINITE);

		for (int i = 0; i < size; i++)
		{
			m_samples.push_back(buffer[i]);
		}
		ReleaseSemaphore(sem, 1, NULL);
	}

private:

    virtual bool onGetData(Chunk& data)
	{
		// number of samples to stream every time the function is called;
		// in a more robust implementation, it would rather be a fixed
		// amount of time rather than an arbitrary number of samples
		const int samplesToStream = 50000;

		//check semaphore
		WaitForSingleObject(sem, INFINITE);

		// set the pointer to the next audio samples to be played
		data.samples = &m_samples[m_currentSample];

		// have we reached the end of the sound?
		if (m_currentSample + samplesToStream <= m_samples.size())
		{
			// end not reached: stream the samples and continue
			data.sampleCount = samplesToStream;
			m_currentSample += samplesToStream;
			ReleaseSemaphore(sem, 1, NULL);
			return true;
		}
		else
		{
			// end of stream reached: stream the remaining samples and stop playback
			data.sampleCount = m_samples.size() - m_currentSample;
			m_currentSample = m_samples.size();
			ReleaseSemaphore(sem, 1, NULL);
			return false;
		}

	}

    virtual void onSeek(sf::Time timeOffset)
    {
        // compute the corresponding sample index according to the sample rate and channel count
        m_currentSample = static_cast<std::size_t>(timeOffset.asSeconds() * getSampleRate() * getChannelCount());
    }

};

int main(int argc, char *argv[]) {
	int nRet, i;
	BOOL  fFlag;
	SOCKADDR_IN stLclAddr, stDstAddr;
	struct ip_mreq stMreq;        /* Multicast interface structure */
	SOCKET hSocket;
	WSADATA stWSAData;

	/* Display program banner */
	printf("------------------------------------------------------\n");
	printf(" AudioStreamSrvr - multicast audio server\n");
	printf("------------------------------------------------------\n");

	/* Init WinSock */
	nRet = WSAStartup(0x0202, &stWSAData);
	if (nRet) {
		printf ("WSAStartup failed: %d\r\n", nRet);
		exit (1);
	}

	/* Display current settings */
	printf ("Multicast Address:%s, Port:%d, IP TTL:%d, Interval:%d\n",
		achMCAddr, nPort, lTTL, nInterval);

	/* Get a datagram socket */
	hSocket = socket(AF_INET, 
		SOCK_DGRAM, 
		0);
	if (hSocket == INVALID_SOCKET) {
		printf ("socket() failed, Err: %d\n", WSAGetLastError());
		exit(1);
	}

	/* Bind the socket
	* 
	* NOTE: Normally, we wouldn't need to call bind unless we were 
	*  assigning a local port number explicitly (naming the socket), 
	*  however Microsoft requires that a socket be bound before it 
	*  can join a multicast group with setsockopt() IP_ADD_MEMBERSHIP 
	*  (or fails w/ WSAEINVAL).
	*/
	stLclAddr.sin_family      = AF_INET; 
	stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* any interface */
	stLclAddr.sin_port        = 0;                 /* any port */
	nRet = bind(hSocket, 
		(struct sockaddr*) &stLclAddr, 
		sizeof(stLclAddr));
	if (nRet == SOCKET_ERROR) {
		printf ("bind() port: %d failed, Err: %d\n", nPort, 
			WSAGetLastError());
	}

	/* Join the multicast group
	* 
	* NOTE: According to RFC 1112, a sender does not need to join the 
	*  group, however Microsoft requires a socket to join a group in 
	*  order to use setsockopt() IP_MULTICAST_TTL (or fails with error
	*  WSAEINVAL).
	*/
	stMreq.imr_multiaddr.s_addr = inet_addr(achMCAddr);
	stMreq.imr_interface.s_addr = INADDR_ANY;
	nRet = setsockopt(hSocket, 
		IPPROTO_IP, 
		IP_ADD_MEMBERSHIP, 
		(char *)&stMreq, 
		sizeof(stMreq));
	if (nRet == SOCKET_ERROR) {
		printf (
			"setsockopt() IP_ADD_MEMBERSHIP address %s failed, Err: %d\n",
			achMCAddr, WSAGetLastError());
	} 

	/* Set IP TTL to traverse up to multiple routers */
	nRet = setsockopt(hSocket, 
		IPPROTO_IP, 
		IP_MULTICAST_TTL, 
		(char *)&lTTL, 
		sizeof(lTTL));
	if (nRet == SOCKET_ERROR) {
		printf ("setsockopt() IP_MULTICAST_TTL failed, Err: %d\n",
			WSAGetLastError());
	}

	/* Disable loopback */
	fFlag = FALSE;
	nRet = setsockopt(hSocket, 
		IPPROTO_IP, 
		IP_MULTICAST_LOOP, 
		(char *)&fFlag, 
		sizeof(fFlag));
	if (nRet == SOCKET_ERROR) {
		printf ("setsockopt() IP_MULTICAST_LOOP failed, Err: %d\n",
			WSAGetLastError());
	}

	/* Assign our destination address */
	stDstAddr.sin_family =      AF_INET;
	stDstAddr.sin_addr.s_addr = inet_addr(achMCAddr);
	stDstAddr.sin_port =        htons(nPort);

	int count = 0;
    // load an audio buffer from a sound file
    sf::SoundBuffer buffer;
	const sf::Int16* pSample;
	sf::Int16 * pSound;
	sf::Int16 * temp;
	size_t sampleCount, sampleRate, channelCount;
    buffer.loadFromFile("test.wav");

	sampleRate   = buffer.getSampleRate();
	channelCount = buffer.getChannelCount();
	pSample      = buffer.getSamples();
	sampleCount  = buffer.getSampleCount();


	pSound = const_cast<sf::Int16*>(pSample);
	temp   = const_cast<sf::Int16*>(pSample);

	char * test;
	MyStream stream;

	//stream.load(pSound, 250000, sampleRate, channelCount);
   // stream.play();
	//stream.setVolume(10);

	Sleep(1000);
    // initialize and play our custom stream
	for (;;) {
		test = (char *)&temp[count * sampleRate];
		printf("%d\n", &temp[count * sampleRate]);
		Sleep(100);
		/*---------------------------------------


		Read File


		----------------------------------------*/
		/* Send the time to our multicast group! */
		nRet = sendto(hSocket, 
			test, 
			sizeof(sampleRate),
			0,
			(struct sockaddr*)&stDstAddr, 
			sizeof(stDstAddr));
		if (nRet < 0) {
			printf ("sendto() failed, Error: %d\n", WSAGetLastError());
			exit(1);
		}
		//sf::Int16 * derp = reinterpret_cast<sf::Int16*>(test);
		
		//stream.add(derp, sampleRate);
		printf("Sent...\n");
		count++;
		//*temp = count*44100;	
		/* Wait for the specified interval */
		//Sleep(nInterval*1000);
		if(count * sampleRate >= sampleCount)
		{
			count = 0;
			Sleep(1000);
			printf("count reset");
		}

	} /* end for(;;) */

	/* Close the socket */
	closesocket(hSocket);

	/* Tell WinSock we're leaving */
	WSACleanup();

	return (0);
} /* end main() */