#include <sstream>
#include <fstream>

#include "GameData.h"
#include "LogicPlayer.h"
#include "Ball.h"
#include "Marionette.h"

#include "AI_Tree.h"
#include "AI_Player_Impl.h"
#include "AI_StateInspector_Impl.h"
#include "AI_ArrayHeuristic.h"

using namespace std;

LogicPlayer::LogicPlayer(GameData* _game, int _pnum) : game(_game), pnum(_pnum), pid(-1), 
state_inspector(0), search_heuristic(0), qvalues(0), ai_player(0), history(0), physics_player(0)
{
}

LogicPlayer::~LogicPlayer()
{
	if (pid != -1)
	{
		World::world()->remove(physics_player->name());

		delete state_inspector;
		delete search_heuristic;
		delete qvalues;
		delete ai_player;
		delete history;
	}
}

void LogicPlayer::save()
{
	if (pid != -1)
	{
		qvalues->save(pid);
	}
}

void LogicPlayer::load(PLAYER_ID player_id, Vector3 start_pos)
{	
	// set up id
	pid = player_id;

	ostringstream filename;
	filename << "conf\\p" << player_id << ".conf";
	ifstream conf(filename.str().c_str());

	if (!conf)
	{
		conf.close();
		conf.clear();
		conf.open("conf\\default.conf");
	}

	string buf;
	while (getline(conf, buf))
	{
		key_value kv (buf);
		if (kv.key == "NAME")
		{
			name = kv.value;
		}
	}
	
	std::cout << "LOADED " << name << std::endl;

	// set up physics player + moves
	if (physics_player == 0)
	{
		std::ostringstream player_name;
		player_name << "PLAYER" << pnum;
		physics_player_ref = PhysicsPlayer::create(player_name.str(), pnum, game->demo); 
		physics_player = static_cast<PhysicsPlayer*> (physics_player_ref.pointer());
		World::world()->insert(physics_player_ref, CoordinateFrame(Matrix3::IDENTITY, start_pos));
		physics_player->initPullPoints(physics_player->frame());
	}
	else
	{
		physics_player->setFrame(CoordinateFrame(Matrix3::IDENTITY, start_pos));
	}

	int num_moves = physics_player->loadMoves(pid).size();
	moves.resize(num_moves);
	for (int i=0; i < num_moves; i++)
		moves[i] = physics_player->getMove(i)->getId();
	sort(moves.begin(), moves.end());

	// set up inpector
	state_inspector = new AI_StateInspector_Impl(game, pnum);
	state_inspector->load(pid);

	// set up branch vars
	search_heuristic = new AI_ArrayHeuristic(this);
	search_heuristic->load(pid);
	
	// set up ai
	ai_player = new AI_Player_Impl(this);
	ai_player->load(pid);

	// set up qvalues
	qvalues = new AI_Tree(this);
	qvalues->load(pid);

	// initial state history for player + opponent
	history = new AI_History();
}

void LogicPlayer::clear()
{
	if (pid != -1)
	{
		delete state_inspector;
		delete search_heuristic;
		delete qvalues;
		delete ai_player;
		delete history;

		physics_player->stopMoving();
	}

	pid = -1;
	state_inspector = 0;
	search_heuristic = 0 ;
	qvalues = 0;
	ai_player = 0;
	history = 0;
	name = "";
	moves.clear();
}