
#include "GameConnection.h"
#include <iostream>
#include "Player.h"
#include "Building.h"
#include "GameNetInterface.h"

using namespace std;
using namespace DinastyOnline::Network;

namespace DinastyOnline {
	namespace Network {
		TNL_IMPLEMENT_NETCONNECTION(GameConnection, TNL::NetClassGroupGame, true);
	
		TNL_IMPLEMENT_RPC(GameConnection, rpcGotPlayerPos,
			(bool b1, bool b2, TNL::StringTableEntry string, TNL::S32 x, TNL::S32 y), (b1, b2, string, x, y),
			TNL::NetClassGroupGameMask, TNL::RPCGuaranteedOrdered, TNL::RPCDirAny, 0) {
	
			TNL::S32 xv = x, yv = y;
			TNL::logprintf("Server acknowledged position update - %d %d %s %i %i", b1, b2, string.getString(), xv, yv);
		}
	
		TNL_IMPLEMENT_RPC(GameConnection, rpcSetPlayerPos,
			(TNL::S32 x, TNL::S32 y), (x, y),
			TNL::NetClassGroupGameMask, TNL::RPCGuaranteedOrdered, TNL::RPCDirClientToServer, 0) {
	
			Position newPosition;
			newPosition.x = x;
			newPosition.y = y;
	
			TNL::logprintf("%s - received new position (%i, %i) from client",
						getNetAddressString(),
						newPosition.x, newPosition.y);
	
			myPlayer->serverSetPosition(myPlayer->getPosition(), newPosition, 0, 0.2f);
	
			// send an RPC back the other way!
			TNL::StringTableEntry helloString("Hello World!!");
			rpcGotPlayerPos(true, false, helloString, x, y);
		};
	
		GameConnection::GameConnection() {
			return;
		}
		
		GameConnection::GameConnection(TNL::StringTableEntry login, TNL::StringTableEntry password) {
			this->login = login;
			this->password = password;
			// every connection class instance must have a net class group set
			// before it is used.
	
			//setIsAdaptive(); // <-- Uncomment me if you want to use adaptive rate instead of fixed rate...
		}
	
		bool GameConnection::isDataToTransmit() {
			if(isInitiator()) {
				//Client
			} else {
				// Server
				//TNL::logprintf("!%g", myPlayer->endPos.x);
			}
			// we always want packets to be sent.
			return true;
		}
		
		void GameConnection::writeConnectRequest(BitStream *stream) {
			Parent::writeConnectRequest(stream);
	
			stream->writeString(this->password.getString());
			stream->writeString(this->login.getString());
			TNL::logprintf("Password+name sent...");
		}
		
		bool GameConnection::readConnectRequest(BitStream *stream, const char **errorString) {
			if(!Parent::readConnectRequest(stream, errorString))
				return false;
	
			// first read out the password.
			char buf[256];
	
			stream->readString(buf);
			this->password = buf;
			// Check password
			/*if(stricmp(buf, "password") != 0) {
				// Wrong password
				*errorString = "PASSWORD";
				return false;
			}*/
	
			//now read the player name
			stream->readString(buf);
			this->login = buf;
			size_t len = strlen(buf);
	
			if(len > 30)
				len = 30;
	
			// strip leading and trailing spaces...
			char *name = buf;
			while(len && *name == ' ') {
				name++;
				len--;
			}
			while(len && name[len-1] == ' ') {
				len--;
			}
	
			// remove invisible chars
			/*for(size_t i = 0; i < len; i++) { 
				if((name[i] < ' ') || (name[i] > 127)) {
					name[i] = 'X';
				}
			}*/
			 
			name[len] = 0;
	
			mClientName = name;
			TNL::logprintf("Password+name received (%s)...", name);
			return true;
		}
	
	
		void GameConnection::onConnectTerminated(NetConnection::TerminationReason reason, const char *string) {
			if(isInitiator()) {
				logprintf("%s - %s connection terminated - reason %d.", getNetAddressString(), isConnectionToServer() ? "server" : "client", reason);
			} else {
				logprintf("%s - %s connection terminated - reason %d.", getNetAddressString(), isConnectionToServer() ? "server" : "client", reason);
			}
			
		}
	
		void GameConnection::onConnectionTerminated(NetConnection::TerminationReason reason, const char *edString)	{
			logprintf("%s - %s connection terminated - reason %d.", getNetAddressString(), isConnectionToServer() ? "server" : "client", reason);
	
			delete (Player*)myPlayer;
		}
	
		void GameConnection::onConnectionEstablished() {
			// call the parent's onConnectionEstablished.
			// by default this will set the initiator to be a connection
			// to "server" and the non-initiator to be a connection to "client"
			Parent::onConnectionEstablished();
	
			// To see how this program performs with 50% packet loss,
			// Try uncommenting the next line :)
			//setSimulatedNetParams(0.5, 0);
	
			if(isInitiator()) {
				setGhostFrom(false);
				setGhostTo(true);
				TNL::logprintf("%s - connected to server.", getNetAddressString());
				//setFixedRateParameters(50, 50, 2000, 2000);
			} else {
				// on the server, we create a player object that will be the scope object
				// for this client.			
				Player *player = new Player();
				player->setName(mClientName.getString());
				myPlayer = player;
				myPlayer->addToWorld(((GameNetInterface *) getInterface())->world);
				myPlayer->setName(this->login.getString());
				player->setScopeAlways();
				setScopeObject(myPlayer);
				setGhostFrom(true);
				setGhostTo(false);
				activateGhosting();
				TNL::logprintf("%s - client connected and player added to the world.", getNetAddressString());
				//setFixedRateParameters(50, 50, 2000, 2000);
			}
		}
	}
}
