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

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

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

void RSIServer::init(RaytracerParameters& RTParams, SocketClient& socketClient)
{
	m_pClient = &socketClient;
	m_pRTParams = &RTParams;
}

bool RSIServer::run(Task& task)
{
	m_uServerState = CLIENT_READY;

	// Sendint
	while(m_uServerState != CLIENT_RESULT)
	{
		if(getResponse()) return true;

		switch(m_uServerState)
		{
		case CLIENT_REQUEST:
			clientRequest();
			break;
		case CLIENT_READY:
			clientTask(task);
			break;
		case CLIENT_RESULT:
			clientResult(task);
			break;
		case CLIENT_END:
			return true;
		}
	}

	return false;
}

bool RSIServer::getResponse()
{
	PacketHeader header;

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

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

void RSIServer::clientRequest()
{
	char name[] = "Scenes/room/room.brs";
	PacketRaytracerParams serverFilename = { { SERVER_SCENE_NAME, sizeof(PacketRaytracerParams) }, { sizeof(RaytracerParameters) } };

	m_pClient->sendRequest(&serverFilename, sizeof(serverFilename));
	m_pClient->sendRequest(m_pRTParams, sizeof(*m_pRTParams));

	NLogMessage("Server ready for tasks\n");
}

void RSIServer::clientTask(Task& task)
{
	PacketTask packetTask = 
	{ 
		{ SERVER_TASK, sizeof(packetTask) }, 
		{ task.uTaskIndex, task.uPackX, task.uPackY, task.uWidth, task.uHeight, m_pRTParams->uPackSize } 
	};
	
	m_pClient->sendRequest(&packetTask, sizeof(packetTask));
}

void RSIServer::clientResult(Task& task)
{
	PacketResultTail resultTail;

	m_pClient->getResponse(&resultTail, sizeof(resultTail));

	NDynamicTable<NUint8> buffer;
	buffer.Create(resultTail.uResultSize);	// TODO: check it in client and allocate once for entire object

	m_pClient->getResponse(buffer.GetBuffer(), buffer.GetSize());	// Firstly need to unblock socket

	if(resultTail.uTaskIndex == task.uTaskIndex)
	{
		NLogMessage("task %d result received\n", resultTail.uTaskIndex);
		// writing to bitmap
		for(NUint32 y = 0, i = 0; y < task.uHeight; y++)
		{
			NUint8* pDest = task.pDestination + y * task.uPitch;

			for(NUint32 x = 0; x < task.uWidth; x++)
			{
				pDest[3 * x] = buffer[i++];
				pDest[3 * x + 1] = buffer[i++];
				pDest[3 * x + 2] = buffer[i++];
			}
		}

		buffer.Release();

		task.bDone = true;
	}
	else
	{
		m_uServerState = CLIENT_READY;
		clientTask(task); // repeat
	}
}

void RSIServer::done()
{
	PacketHeader packetDone = { SERVER_END, sizeof(packetDone) };
	m_pClient->sendRequest(&packetDone, sizeof(packetDone));

	m_uServerState = SERVER_END;
}
