#include "IUtil.h"
#include "TServerList.h"
#include "TGraalPlayer.h"
#include "TGraalServer.h"
#include "TSqlDatabase.h"
#include "TSqliteDatabase.h"

TServerList::TServerList(CSettings *pSettings)
: mGraalDatabase(0), mPlayerSocket(this), mServerSocket(this)
{
	this->initiate(pSettings);
}

TServerList::~TServerList()
{
}

bool TServerList::run()
{
	// Update our socket manager.
	mSocketManager.update(0, 5000);		// 5ms
	return true;
}

int TServerList::initiate(CSettings *pSettings)
{
	// Settings loaded..?
	if (pSettings == 0 || !pSettings->IsOpened())
		return false;

	// Create Database
	mGraalDatabase = new TSqliteDatabase(pSettings);
	if (mGraalDatabase->Initiate() != 0)
	{
		printf("[Error] Could not initialize Graal Database.\n");
		return 1;
	}

	// Set Settings
	this->mSettings = pSettings;

	// Player Socket
	if (mPlayerSocket.initiate(mSettings->getStr("clientPort", "14922").text(), "mPlayerSocket", SOCK_PLAYER))
	{
		printf("[Error] Could not initialize player socket.\n");
		return 1;
	}

	// Server Socket
	if (mServerSocket.initiate(mSettings->getStr("gserverPort", "14900").text(), "mServerSocket", SOCK_SERVER))
	{
		printf("[Error] Could not initialize server socket.\n");
		return 1;
	}

	// Register sockets with the socket manager.
	mSocketManager.registerSocket((CSocketStub *)&mPlayerSocket);
	mSocketManager.registerSocket((CSocketStub *)&mServerSocket);
	return 0;
}

void TServerList::AddSocket(CSocket *pNewSocket, int pType)
{
	if (pNewSocket == 0)
		return;

	CString connIp = pNewSocket->getRemoteIp();
	if (!VerifyIpBan(connIp, pType))
	{
		CSocketStub *newSockStub = 0;
		switch (pType)
		{
			case SOCK_PLAYER:
				mPlayerList.push_back(new TGraalPlayer(this, pNewSocket));
				newSockStub = (CSocketStub *)mPlayerList.back();
				break;

			case SOCK_SERVER:
				mServerList.push_back(new TGraalServer(this, pNewSocket));
				newSockStub = (CSocketStub *)mServerList.back();
				break;
		}
		
		if (newSockStub != 0)
		{
			mSocketManager.registerSocket((CSocketStub *)newSockStub);
			printf("Accepted %s: %s\n", (pType == SOCK_PLAYER ? "player" : (pType == SOCK_SERVER ? "server" : "unknown")), connIp.text());
		}
	}
	else printf("Rejected %s: %s matched ip ban\n", (pType == SOCK_PLAYER ? "player" : (pType == SOCK_SERVER ? "server" : "unknown")), connIp.text());
}

void TServerList::RemoveSocket(CSocketStub *pSocketStub, int pType)
{
	if (pSocketStub == 0)
		return;

	// Remove
	switch (pType)
	{
		case SOCK_PLAYER:
			vecRemove<TGraalPlayer *>(mPlayerList, (TGraalPlayer *)pSocketStub);
			break;

		case SOCK_SERVER:
			vecRemove<TGraalServer *>(mServerList, (TGraalServer *)pSocketStub);
			break;
	}

	// Delete
	delete pSocketStub;
}

CString TServerList::GetServerList(int pGraalVersion, const CString& pIp)
{
	CString outPacket = CString() >> (char)mServerList.size();
	for (std::vector<TGraalServer *>::const_iterator i = mServerList.begin(); i != mServerList.end(); ++i)
		outPacket << (*i)->GetServerPacket(pGraalVersion, pIp);
	return outPacket;
}

/*
	Serverlist Management
*/
int TServerList::CreateAccount(CString& pAccountName, const CString& pPassword)
{
	if (mGraalDatabase != 0)
		return mGraalDatabase->CreateAccount(pAccountName, pPassword);
	return 0;
}

int TServerList::VerifyAccount(CString& pAccountName, const CString& pPassword, bool pFromServer)
{
	if (mGraalDatabase != 0)
		return mGraalDatabase->VerifyAccount(pAccountName, pPassword, pFromServer);
	return 0;
}

int TServerList::VerifyGuild(const CString& pGuildName, const CString& pAccountName, const CString& pNickName)
{
	if (mGraalDatabase != 0)
		return mGraalDatabase->VerifyGuild(pGuildName, pAccountName, pNickName);
	return 0;
}

int TServerList::VerifyIpBan(const CString& pIpAddress, int pType)
{
	if (mGraalDatabase != 0)
		return mGraalDatabase->VerifyIpBan(pIpAddress, pType);
	return 0;
}
