// Il s'agit du fichier DLL principal.

#include "WIAClient.h"

//#define USE_PTHREAD_MUTEX
#ifdef USE_PTHREAD_MUTEX
#include <pthread.h>
#endif

#define BUFSEND_LENGTH 200
#define BUFRCV_LENGTH 1024

static SOCKET WIASocket; //Socket handle
static BYTE sbuf[BUFSEND_LENGTH];
static BYTE rcvbuf[BUFRCV_LENGTH];
static BYTE jpegbuf[BUFJPEG_LENGTH];
static int ircvbuf;
static int ibeginjpegrcvbuf;
static BYTE *ptbeginjpegrcvbuf;
static int maxrcvbuf;
static BYTE *ptrcvbuf;
static int ijpegbuf;
static BYTE *ptjpegbuf;
static int len_jpegbuf;


#ifdef USE_PTHREAD_MUTEX
static pthread_mutex_t mutexWIAData;
#endif

//--------------------------------------------------
void WIAClient::ClearRcvbuf()
{
	ptrcvbuf = rcvbuf;
	for (int i=0;i< BUFRCV_LENGTH; i++)
	{
		*ptrcvbuf = 0;
		ptrcvbuf ++;
	}
	ptrcvbuf = rcvbuf;
	ircvbuf = 0;
	maxrcvbuf = 0;
	ibeginjpegrcvbuf = 0;
	ptbeginjpegrcvbuf = rcvbuf;

}

//--------------------------------------------------
bool WIAClient::FeedRcvbuf( )
{
	int nReceived;
#ifdef WIACLIENT_TRACE_ON
	printf("WIACLient::FeedRcvbuf, begin.");
#endif

	if ((nReceived = recv(WIASocket, (char *)rcvbuf, BUFRCV_LENGTH, 0)) == SOCKET_ERROR)
	{
#ifdef WIACLIENT_TRACE_ON
		printf("WIAClient::FeedRcvbuf() recv error, %d!!!",  WSAGetLastError( ));
#endif
		maxrcvbuf = 0;
		return false;
	}
	maxrcvbuf = nReceived;
	ptrcvbuf = rcvbuf;
	ircvbuf = 0;
	ibeginjpegrcvbuf = 0;
	ptbeginjpegrcvbuf = rcvbuf;
#ifdef WIACLIENT_TRACE_ON
	printf("WIACLient::FeedRcvbuf, end, maxrcvbuf=%d\n", maxrcvbuf);
#endif
	return true;
}

//--------------------------------------------------
bool WIAClient::FindInRcvbuf( BYTE car)
{
	bool flag_found=false;

#ifdef WIACLIENT_TRACE_ON
	printf("WIACLient::FindInRcvbuf(), begin. ircvbuf=%d, maxrcvbuf=%d\n", ircvbuf, maxrcvbuf);
#endif

	while (ircvbuf < maxrcvbuf && flag_found == false)
	{
		if (*ptrcvbuf == car)
			flag_found = true;
		ircvbuf++;
		ptrcvbuf++;
	}

#ifdef WIACLIENT_TRACE_ON
	printf("WIACLient::FindInRcvbuf(), end. ircvbuf=%d, maxrcvbuf=%d\n", ircvbuf, maxrcvbuf);
#endif

	return flag_found;
}
//--------------------------------------------------
bool WIAClient::FindNextInRcvbuf(BYTE car )
{
	bool flag_found=false;
#ifdef WIACLIENT_TRACE_ON
	printf("WIACLient::FindNextInRcvbuf(). ircvbuf=%d, maxrcvbuf=%d\n", ircvbuf, maxrcvbuf);
#endif
	if (ircvbuf < maxrcvbuf)
	{
#ifdef WIACLIENT_TRACE_ON
		printf("WIACLient::FindNextInRcvbuf() car found=%00x\n", *ptrcvbuf);
#endif
		if (*ptrcvbuf == car)
			flag_found = true;
		ircvbuf++;
		ptrcvbuf++;
	}


	return flag_found;
}
//--------------------------------------------------

bool WIAClient::FindSOIHeader()
{
	bool flag_found_ff=false;
	bool flag_found_d8=false;
#ifdef WIACLIENT_TRACE_ON
	printf("WIACLient::FindSOIHeader(), begin.\n");
#endif
	if (! FeedRcvbuf( ))
	{
#ifdef WIACLIENT_TRACE_ON
	printf("--> WIACLient::FindSOIHeader(), ! FeedRcvbuf(), not found.\n");
#endif
		return false;
	}
	flag_found_ff =FindInRcvbuf( 0xFF);
	if (flag_found_ff)
		flag_found_d8 = FindNextInRcvbuf( 0xd8);
	
	if (flag_found_d8)
	{
		ibeginjpegrcvbuf =ircvbuf-2;
		ptbeginjpegrcvbuf = ptrcvbuf - 2;
	}

#ifdef WIACLIENT_TRACE_ON
	if (flag_found_d8)
		printf("--> WIACLient::FindSOIHeader(), FOUND!\n");
	else
		printf("--> WIACLient::FindSOIHeader(), NOT FOUND!\n");
#endif
	return flag_found_d8;
}

//--------------------------------------------------

bool WIAClient::FindEOIHeader()
{
	bool flag_found_ff=false;
	bool flag_found_d9=false;

#ifdef WIACLIENT_TRACE_ON
	printf("WIACLient::FindEOIHeader(), begin.\n");
#endif

	while (!flag_found_d9 & ircvbuf < maxrcvbuf)
	{
		flag_found_ff =FindInRcvbuf( 0xFF);
		if (flag_found_ff)
			flag_found_d9 = FindNextInRcvbuf( 0xd9);
	}
	
#ifdef WIACLIENT_TRACE_ON
	if (flag_found_d9)
		printf("WIACLient::FindEOIHeader(), end. flag_found TRUE, ircvbuf=%d, maxrcvbuf=%d\n", ircvbuf, maxrcvbuf);
	else
				printf("WIACLient::FindEOIHeader(), end. flag_found FALSE, ircvbuf=%d, maxrcvbuf=%d\n", ircvbuf, maxrcvbuf);
#endif

	return flag_found_d9;
}

//--------------------------------------------------

bool WIAClient::ToJpegbuf(int endrcvbuf)
{
	int len = endrcvbuf-ibeginjpegrcvbuf;
#ifdef WIACLIENT_TRACE_ON
	printf("bool WIAClient::ToJpegbuf(), ircvbuf=%d, ibeginjpegrcvbuf=%d, len=%d\n", endrcvbuf, ibeginjpegrcvbuf, len);
#endif
	memcpy(ptjpegbuf, ptbeginjpegrcvbuf, len);
	ptjpegbuf += len;
	ijpegbuf += len;
	return true;
}

//--------------------------------------------------

void WIAClient::ResetWIAClient_data()
{
	// TBD
}

//--------------------------------------------------

WIAClient::WIAClient( )
{
	ResetWIAClient_data();
#ifdef USE_PTHREAD_MUTEX
	printf("Initializing mutex\n");
	pthread_mutex_init (&mutexWIAData, NULL);
	printf("Done\n");
#endif
}

//--------------------------------------------------

WIAClient::~WIAClient( )
{

}

//--------------------------------------------------

bool WIAClient::Connect(int portNo, char* ipAddress)
{
	    //Start up Winsock…
    WSADATA wsadata;

    int error = WSAStartup(0x0202, &wsadata);

    //Did something happen?
    if (error)
	{
#ifdef WIACLIENT_TRACE_ON
		printf("!!! Cannot startup socket WIAClient::Connect()\n");
#endif
        return false;
	}

    //Did we get the right Winsock version?
    if (wsadata.wVersion != 0x0202)
    {
#ifdef WIACLIENT_TRACE_ON
		printf("!!! Wring version WIAClient::Connect(), verson = %d <> 0x0202\n", wsadata.wVersion);
#endif
        WSACleanup(); //Clean up Winsock
        return false;
    }

    //Fill out the information needed to initialize a socket…
    SOCKADDR_IN target; //Socket address information

    target.sin_family = AF_INET; // address family Internet
    target.sin_port = htons (portNo); //Port to connect on
    target.sin_addr.s_addr = inet_addr (ipAddress); //Target IP

    WIASocket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); //Create socket
    if (WIASocket == INVALID_SOCKET)
    {
#ifdef WIACLIENT_TRACE_ON
		printf("!!! Cannot create socket WIAClient::Connect(), ipAddress=%s, portNo=d\n", ipAddress, portNo);
#endif
        return false; //Couldn't create the socket
    }  

    //Try connecting...

    if (connect(WIASocket, (SOCKADDR *)&target, sizeof(target)) == SOCKET_ERROR)
    {
#ifdef WIACLIENT_TRACE_ON
		printf("!!! Cannot create socket WIAClient::Connect(), ipAddress=%s, portNo=d\n", ipAddress, portNo);
#endif
        return false; //Couldn't connect
    }

#ifdef WIACLIENT_TRACE_ON
		printf("Connection to WIA Server Ok!, ipAddress=%s, portNo=%d\n", ipAddress, portNo);
#endif

	return WIACLIENT_ERR_NONE;
}

//--------------------------------------------------

void WIAClient::Disconnect( )
{
//Close the socket if it exists
    if (WIASocket)
        closesocket(WIASocket);

    WSACleanup(); //Clean up Winsock
}


//--------------------------------------------------

void WIAClient::GetWIAClientData( wiaclient_data *new_data)
{
#ifdef USE_PTHREAD_MUTEX
	pthread_mutex_lock (&mutexWifibotData);
#endif
	*new_data = this->data;
#ifdef USE_PTHREAD_MUTEX
	pthread_mutex_unlock (&mutexWifibotData);
#endif
}

//--------------------------------------------------

bool WIAClient::StartWIAStreaming( )
{
	int nReceived;
	sprintf((char *)sbuf, "GET /cameras/1?q=30 HTTP/1.1\r\nKeep-Alive: 300\r\nConnection: keep-alive\r\n\r\n");
#ifdef WIACLIENT_TRACE_ON
	printf("Starting communication with WIA server, data sent: %s\n", sbuf);
#endif
	if (send(WIASocket,(char*)sbuf,73,0) == SOCKET_ERROR) // On envoie la trame de 73 octets au serveur WIA
	{
#ifdef WIACLIENT_TRACE_ON
		printf("WIAClient::StartWIAStreaming() Send error, %d!!!",  WSAGetLastError( ));
#endif
		return false;
	}
	if ((nReceived = recv(WIASocket,(char *)rcvbuf,132,0)) == SOCKET_ERROR) // On attend la réponse du Wifibot et on récupère les données dans rcvbuf (voir le fichier Ethernet Wifi Protocol.PDF)
	{
#ifdef WIACLIENT_TRACE_ON
		printf("WIAClient::StartWIAStreaming() recv error, %d!!!",  WSAGetLastError( ));
#endif
		return false;
	}
#ifdef WIACLIENT_TRACE_ON
	printf("%d octets reçus!\n", nReceived);
	printf("%s\n", rcvbuf);
#endif
	return true;
}

//--------------------------------------------------

int WIAClient::GetWIANextFrame( wiaclient_data *new_data)
{
	int jpeg_stream_len;

#ifdef WIACLIENT_TRACE_ON
	printf("WIAClient::GetWIANextFrame(), begin.\n");
#endif
	ptjpegbuf = jpegbuf;
	ijpegbuf = 0;
	while (!FindSOIHeader())
		FeedRcvbuf();
	while (!FindEOIHeader() )
	{
#ifdef WIACLIENT_TRACE_ON
		printf("WIAClient::GetWIANextFrame(), ToJpegbuf, ijpegbuf=%d, ircvbuf=%d, maxrcvbuf=%d", ijpegbuf, ircvbuf, maxrcvbuf);
#endif
		ToJpegbuf(maxrcvbuf);
		FeedRcvbuf();
	}
	ToJpegbuf( ircvbuf - 1);
	jpeg_stream_len = ijpegbuf;
	new_data->jpeg_stream_len = jpeg_stream_len;
	memcpy(new_data->jpeg_stream_data, jpegbuf, jpeg_stream_len);
#ifdef WIACLIENT_TRACE_ON
	printf("WIAClient::GetWIANextFrame(), end. EOI found!!! jpeg_len=%d, ircvbuf=%d\n", jpeg_stream_len, ircvbuf);
#endif
	
	return jpeg_stream_len;
}


