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

#include <sstream>

#include "auxiliary/functions.h"
#include "sys/sys.h"
#include "core/player.h"
#include "core/cvar.h"

namespace core
{

Player::Player()
{
	player_control = 0;
	clear();
}

Player::~Player()
{
	clear();
}

void Player::clear()
{
	player_id = 0;
	player_zone = 0;
	player_name.clear();
	player_dirty = false;
	player_zonechange = false;
	player_rcon = false;
	player_mute = false;
	player_mission_target = 0;

	clear_assets();
	player_control = 0;
}

void Player::set_control(EntityControlable *entitycontrolable)
{
	player_control = entitycontrolable;

	if (entitycontrolable) {
		set_zone(entitycontrolable->zone());
	}
	player_dirty = true;
}

void Player::set_zone(Zone *zone) 
{
	if (zone != player_zone) {
		player_zone = zone;
		player_zonechange = true;
	}
}

void Player::set_mission_target(Entity *new_mission_target)
{
	if (new_mission_target != player_mission_target) {
		player_mission_target = new_mission_target;
		player_dirty = true;
	}
}

void Player::update_info()
{
	Cvar *cl_name = Cvar::find("cl_name");
	if (cl_name) {
		if (cl_name->str().size()) {
			player_name = cl_name->str();
			aux::strip_quotes(player_name);
			(*cl_name) = player_name;
		}
	}

	Cvar *cl_color = Cvar::find("cl_color");
	math::Color color(1.0, 1.0, 1.0, 1.0);
	if (cl_color) {
		std::istringstream is(cl_color->str());
		if (is >> color)
			player_color.assign(color);
	}

	Cvar *cl_color_second = Cvar::find("cl_colorsecond");
	math::Color color_second(1.0, 1.0, 1.0, 1.0);
	if (cl_color_second) {
		std::istringstream is(cl_color_second->str());
		if (is >> color_second)
			player_color_second.assign(color_second);
	}
}

void Player::serialize_client_update(std::ostream & os)
{
	os << " " << player_color << " " << player_color_second << " \"" << player_name << "\"";
}

void Player::receive_client_update(std::istream &is)
{
	is >> player_color;
	is >> player_color_second;

	std::string n;
	char c;
	while ( (is.get(c)) && (c != '"'));
	while ( (is.get(c)) && (c != '"'))
		n += c;

	if (n.size())
		player_name = n;	
}

void Player::serialize_server_update(std::ostream & os) const
{
	unsigned int zo = (zone() ? zone()->id() : 0);
	unsigned int co = (player_control ?  player_control->id() : 0);
	unsigned int mission = (player_mission_target ? player_mission_target->id() : 0);

	os << player_id <<  " " << zo << " " << co << " " << mission << " " << player_color << " \"" << player_name << "\"";
}

void Player::receive_server_update(std::istream &is)
{
	is >> player_id;

	unsigned int zo = 0;
	is >> zo;
	set_zone(Zone::find(zo));

	unsigned int co = 0;
	is >> co;
	if (co) { 
		Entity *e = Entity::find(co);
		if (e && e->type() == Entity::Controlable) {
			player_control = static_cast<EntityControlable *>(e);
		} else {
			player_control = 0;
			con_warn << "control set to unknown entity " << co << "\n";
		}	
	} else {
		player_control = 0;
	}

	unsigned int mission = 0;
	is >> mission;
	if (mission) { 
		player_mission_target = Entity::find(mission);
		if (!player_mission_target) {
			con_warn << "mission target set to unknown entity " << co << "\n";
		}
	} else {
		player_mission_target  = 0;
	}
	is >> player_color;

	std::string n;
	char c;
	while ( (is.get(c)) && (c != '"'));
	while ( (is.get(c)) && (c != '"'))
		n += c;

	if (n.size())
		player_name = n;
}

void Player::add_asset(EntityControlable *entity)
{
	entity->entity_owner = this;
	assets.push_back(entity);
	//con_debug << "  adding asset " << entity->id() << " to player " << id() << std::endl;
}

void Player::remove_asset(EntityControlable *entity)
{
	if (!entity)
		return;

	for (std::list<EntityControlable*>::iterator asset = assets.begin(); asset != assets.end(); asset++) {
		if (((*asset)  == entity) && (entity->owner() == this)) {
			//con_debug << "  removing asset " << (*asset)->id() << " from player " << id() << std::endl;

			if ((*asset) == player_control)
				player_control = 0;
			(*asset)->entity_owner = 0;
			(*asset)->die();
			assets.erase(asset);
			player_dirty = true;
			return;
		}
	}
	con_warn << "Could not remove asset " << entity->id() << " from player " << this->id() << "\n";
}

void Player::remove_asset(unsigned int id)
{
	if (!id)
		return;

	for (std::list<EntityControlable*>::iterator asset = assets.begin(); asset != assets.end(); asset++) {
		if ( ((*asset)->id()  == id) && ((*asset)->owner() == this) ) {
			//con_debug << "  removing asset " << (*asset)->id() << " from player " << this->id() << std::endl;

			if ((*asset) == player_control)
				player_control = 0;

			(*asset)->entity_owner = 0;
			(*asset)->die();
			assets.erase(asset);
			player_dirty = true;
			return;
		}
	}
	con_warn << "Could not remove asset " << id << " from player " << this->id() << "\n";
}

void Player::clear_assets()
{
	// clear assets
	for (std::list<EntityControlable*>::iterator asset = assets.begin(); asset != assets.end(); asset++) {
		//con_debug << "  removing asset " << (*asset)->id() << " from player " << id() << std::endl;

		(*asset)->entity_owner = 0;
		(*asset)->die();
	}
	assets.clear();

	player_control = 0;
}

}