/*********************************************************************

Name:		Raytracer
Author:		Kamil Szatkowski "Netrix" (C)
Website:	http://www.netrix.org.pl/
License:	GNU GPL

*********************************************************************/
#include "Client.hpp"
#include "NLib/nLogger.hpp"
using namespace NIne;


bool RSIClient::init(SocketClient& socketClient, RayTracer& raytracer)
{
	m_pClient = &socketClient;
	m_pRayTracer = &raytracer;
	m_uClientState = CLIENT_REQUEST;

	// Sending request
	return sendClientRequest();
}

bool RSIClient::sendClientRequest()
{
	PacketHeader clientRequest = { CLIENT_REQUEST, sizeof(PacketHeader) };
	return m_pClient->sendRequest(&clientRequest, sizeof(clientRequest));
}

void RSIClient::run()
{
	// Sendint
	while(m_uClientState != SERVER_END)
	{
		if(getResponse())
		{
			if(!sendClientRequest()) { continue; }
			else { break; }
		}

		switch(m_uClientState)
		{
		case SERVER_SCENE_NAME:
			serverRaytracerParams();
			break;
		case SERVER_TASK:
			serverTask();
			break;
		}
	}

	m_pRayTracer->release();
	m_pClient->release();
}

bool RSIClient::getResponse()
{
	PacketHeader header;

	if(m_pClient->getResponse(&header, sizeof(header)))
	{
    #ifdef _WIN32
		NLogFunctionError("getResponse()", WSAGetLastError());
    #else
		NLogError("getResponse() failed\n");
    #endif
	}

	if(header.uPacketType < _PACKET_TYPE_SIZE && header.uPacketSize == HEADER_SIZES[header.uPacketType])
	{
		m_uClientState = header.uPacketType;
		return false;
	}
	else { return true; }
}

void RSIClient::sendClientReady()
{
	// Ready request
	PacketHeader ready = { CLIENT_READY, sizeof(PacketHeader) };
	m_pClient->sendRequest(&ready, sizeof(ready));
}

void RSIClient::clientDone()
{
	PacketHeader end = { CLIENT_END, sizeof(PacketHeader) };
	m_pClient->sendRequest(&end, sizeof(end));
}

bool RSIClient::serverRaytracerParams()
{
	NUint32 uParametersSize;
	m_pClient->getResponse(&uParametersSize, sizeof(uParametersSize));

	if(uParametersSize != sizeof(RaytracerParameters))
	{
		NLogError("Invalid raytracer parameters");
		return true;
	}

	m_pClient->getResponse(&m_pRayTracer->parameters, sizeof(m_pRayTracer->parameters));

	if(m_pRayTracer->load())	{ return true; }

	m_pRayTracer->preprocessScene();

	// Ready request
	sendClientReady();
	return false;
}

void RSIClient::serverTask()
{
	// Getting task
	PacketTaskTail taskTail;
	m_pClient->getResponse(&taskTail, sizeof(taskTail));

	if(taskTail.uWidth > taskTail.uPackSize || taskTail.uHeight > taskTail.uPackSize)
	{
		m_uClientState = SERVER_END;
		NLogError("Invalid header\n");
		return;
	}

	NLogMessage("Task %d received, ( %d, %d ) -> ", taskTail.uTaskIndex, taskTail.uPackX, taskTail.uPackY);
	
	NDynamicTable<NUint8> packBuffer;
	packBuffer.Create(taskTail.uWidth * taskTail.uHeight * 3);

	// Calculating pack
	m_pRayTracer->calculatePack(taskTail.uPackX, taskTail.uPackY, packBuffer.GetBuffer());

	NLogAppend("Sending answer, task: %d, buffer size: %d...", taskTail.uTaskIndex, packBuffer.GetSize());

	// Sending answer
	PacketResult result = { { CLIENT_RESULT, sizeof(PacketResult) }, { taskTail.uTaskIndex, packBuffer.GetSize() } };
	m_pClient->sendRequest(&result, sizeof(result));
	m_pClient->sendRequest(packBuffer.GetBuffer(), packBuffer.GetSize());

	NLogAppend("OK\n");
	packBuffer.Release();

	// Ready request
	sendClientReady();
	m_uClientState = CLIENT_READY;
}
