/*
   core/gameconnection.cc
   This file is part of the Osirion project and is distributed under
   the terms of the GNU General Public License version 2
*/

#include <string>
#include <sstream>

#include "sys/sys.h"
#include "core/cvar.h"
#include "core/gameconnection.h"
#include "core/net.h"

namespace core
{

GameConnection* GameConnection::connection_instance = 0;

GameConnection::GameConnection(std::string const &connectionstr)
{
	connection_instance = this;
	connection_network = 0;
	connection_running = false;

	connection_timestamp = 0;
	connection_netframe = 0;

	unsigned int port = DEFAULTPORT;
	std::string host(connectionstr);
	size_t found = host.find(':');

	if (found != std::string::npos) {
		std::istringstream str(host.substr(found+1));
		if (str >> port) {
			host.erase(found, std::string::npos);
		} else {
			con_print << "Invalid hostname '" << host << "'\n";
			abort();
			return;
		}

	}

	connection_network = new NetConnection();
	connection_network->connect(host, port);

	if (!connection_network->connected()) {
		abort();
		return;
	}

	// send connect request
	connection_network->send_connect();
	connection_network->transmit();

	if (!connection_network->connected()) {
		abort();
		return;
	}

	game_players.push_back(localplayer());

	connection_running = true;
}

GameConnection::~GameConnection()
{
	if (connection_network) {
		connection_network->disconnect();
		delete connection_network;
	}

	connection_instance = 0;
}

void GameConnection::abort()
{
	connection_running = false;
}

void GameConnection::forward(std::string const &cmdline)
{
	if (!connection_network->connected())
		return;

	connection_network->send_command(cmdline);
}

void GameConnection::say(std::string const &args)
{
	if (!connection_network->connected())
		return;

	connection_network->send_say(args);
}

void GameConnection::private_message(std::string const &args)
{
	if (!connection_network->connected())
		return;

	connection_network->send_private_message(args);
}

void GameConnection::frame(unsigned long timestamp)
{
	if (!running())
		return;

	if (!connection_network->connected()) {
		abort();
		return;
	}

	update_clientstate();

	// get incoming messages
	connection_network->frame();

	float f = 0;
	if (core::Cvar::net_framerate->value()) {		
		f =  1000.0f / core::Cvar::net_framerate->value();
		if (connection_netframe + f > timestamp) {
			return;
		}
	}		

	connection_netframe = timestamp;

	if (connection_network->state() == NetConnection::Connected) {

		if(localcontrol() && localcontrol()->dirty()) {	
			connection_network->send_clientupdate(localcontrol());
			localcontrol()->entity_dirty = false;

		}

		if (localplayer()->dirty()) {
			connection_network->send_playerinfo();
	
		}
	}

	connection_timestamp = connection_network->timestamp();
	connection_network->transmit();
}

}