#include "main.h"
#include "TGraalServer.h"
#include "TServerList.h"

/*
	Create Packet-Functions
*/
bool TGraalServer::IsCreated = false;
typedef bool (TGraalServer::*P2F)(CString&);
std::vector<P2F> functions(255, &TGraalServer::msgPLI_NULL);

void TGraalServer::CreateFunctions()
{
	if (TGraalServer::IsCreated)
		return;

	//functions[PLI_PRE22]			= &TGraalPlayer::msgPLI_PRE22;
	TGraalServer::IsCreated = true;
}

/*
	Constructor | Destructor
*/
TGraalServer::TGraalServer(TServerList *pServerList, CSocket *pSocket)
: mServerList(pServerList)
{
	if (!TGraalServer::IsCreated)
		TGraalServer::CreateFunctions();

	mSocket = pSocket;

	mServerName = "Test Server";
	mServerLang = "English";
	mServerDesc = "This is the description";
	mServerUrl  = "http://www.graal.in/";
	mServerVers = "Version 2.2.2.0";
	mServerIp	= "72.11.128.183";
	mServerPort = "5050";
}


TGraalServer::~TGraalServer()
{
	delete mSocket;
}

/*
	Socket Functions
*/
bool TGraalServer::onRecv()
{
	// Socket Disconnected?
	if (mSocket == 0 || mSocket->getState() == SOCKET_STATE_DISCONNECTED)
		return false;
	
	// Socket Receive?
	unsigned int size = 0;
	char *data = mSocket->getData(&size);
	if (size != 0)
		mDataIn.write(data, size);
	else if (mSocket->getState() == SOCKET_STATE_DISCONNECTED)
		return false;

	printf("data: %s\n", data);

	// Parse Received Data
	CString unBuffer;
	mDataIn.setRead(0);
	while (mDataIn.length() > 1)
	{
		// Packet Length
		unsigned short len = (unsigned short)mDataIn.readShort();
		if ((unsigned int)len > (unsigned int)mDataIn.length() - 2)
			break;

		// Grab Packet
		unBuffer = mDataIn.readChars(len);
		mDataIn.removeI(0, len+2);

		// Uncompress Buffer
		//unBuffer.zuncompressI();

		// Well theres your buffer
		if (!ParsePacket(unBuffer))
			return false;
	}

	return true;
}

bool TGraalServer::onSend()
{
	// Socket Disconnected?
	if (mSocket == 0 || mSocket->getState() == SOCKET_STATE_DISCONNECTED)
		return false;
	
	// Socket Send
	SendCompress();
	return true;
}

void TGraalServer::onUnregister()
{
	// Clear Outgoing Data
	this->SendCompress();

	// Remove Socket
	mServerList->RemoveSocket((CSocketStub *)this, SOCK_SERVER);
}

unsigned int TGraalServer::send(CString pBuffer)
{
	unsigned int len = pBuffer.length();
	mSocket->sendData(pBuffer.text(), &len);
	return len;
}

/*
	Packet-Manipulation
*/
bool TGraalServer::ParsePacket(CString& pPacket)
{
	while (pPacket.bytesLeft() > 0)
	{
		// read id & packet
		CString str = pPacket.readString("\n");
		int id = str.readGUChar();

		// check lengths
		if (str.length() < 0) //  || id >= (int)plfunc.size()
			continue;

		// valid packet, call function
		int oldRead = str.readPos();
		msgPLI_NULL(str);
		str.setRead(oldRead);
		if (!(*this.*functions[id])(str))
			return false;
	}

	return true;
}

void TGraalServer::SendCompress()
{	
	// Empty buffer, return.
	if (mDataOut.isEmpty())
		return;

	// Compress Buffer
	// mDataOut.zcompressI();

	// Send Buffer
	send(CString() << (short)mDataOut.length() << mDataOut);
	mDataOut.clear();
}

void TGraalServer::SendPacket(CString pPacket, bool pFlush)
{
	// Empty buffer, return.
	if (pPacket.isEmpty())
		return;

	// Append 'newline' character
	if (pPacket[pPacket.length()-1] != '\n')
		pPacket.writeChar('\n');
	
	// Append buffer
	mDataOut.write(pPacket);

	// Check Buffer & Send
	if (mDataOut.length() > 4096 || pFlush)
		this->SendCompress();
}

// other stuff

CString TGraalServer::GetServerPacket(int pGraalVersion, const CString& pIp)
{
	CString playerCount(mPlayerList.size());

	return CString()
		>> (char)8
		>> (char)mServerName.length() << mServerName
		>> (char)mServerLang.length() << mServerLang
		>> (char)mServerDesc.length() << mServerDesc
		>> (char)mServerUrl.length()  << mServerUrl
		>> (char)mServerVers.length() << mServerVers
		>> (char)playerCount.length() << playerCount
		>> (char)mServerIp.length()   << mServerIp
		>> (char)mServerPort.length() << mServerPort;
}

/*
	Packet-Functions
*/
bool TGraalServer::msgPLI_NULL(CString& pPacket)
{
	pPacket.setRead(0);
	printf("Unknown Player Packet: %i (%s)\n", pPacket.readGUChar(), pPacket.text()+1);
	for (int i = 0; i < pPacket.length(); ++i) printf("%02x ", (unsigned char)((pPacket.text())[i])); printf("\n");
	return true;
}
