/*********************************************************************//**
*	Binding.
*	Databaze prikazu prirazenych ke klavese. Uklada do mapy
*			prikazy, ktere vyuziva hlavni menu k nastaveni ovladani.
*
*	author: Michal Jirous
*	date: 14.7.2008
*	file: ctrl_binding.cpp
**********************************************************************/

#include "ctrl_binding.h"
#include "sys_console.h"
#include "mathematic.h"
#include "ctrl_keydatabase.h"
#include "parsing.h"
#include "textLibrary.h"
#include <fstream>

using namespace systemConsole;
using namespace binding;
using namespace std;
using namespace parsing;

struct Bind
{
	string commands;
};

Bind g_fieldBinds[MAX_KEYS + 1];
map<string, Keys> g_mapWatchedCommands;
map<string,string> g_mapWatchedCommandsNames;
list<string> g_rightOrder;
//prirazeni prikazu ke klavese
void binding::setBind( int key, string commands )
{
	if( !isInRange( key, 0, MAX_KEYS ) )
	{
		console << "Error while binding: Key of bind is out of range." << endline;
		return;
	}

	updateWatchedCommands( commands, key, g_mapWatchedCommands, g_fieldBinds[ key ].commands );
	
	g_fieldBinds[ key ].commands = commands;
}

void binding::copyMapTo( std::map<std::string,Keys> &targetMap )
{
	targetMap = g_mapWatchedCommands;
}
void binding::setMap( std::map<std::string,Keys> &commandMap )
{
	g_mapWatchedCommands = commandMap;
}

//vraci prikazy prirazene ke klavese ci tlacitku mysi
string binding::getBind( int key )
{
	if( !isInRange( key, 0, MAX_KEYS ) )
	{
		console << "Error while checking bind: Key of bind is out of range." << endline;
		return "";
	}
	return g_fieldBinds[key].commands;
}

void binding::setBindsFromWatchedCommandMap( std::map<std::string, Keys> *bindMap )
{
	if( bindMap == NULL )
		bindMap = &g_mapWatchedCommands;

	for(map<string,Keys>::iterator iter = bindMap->begin(); iter != bindMap->end(); iter++ )
	{
		if( isInRange( iter->second.key_one, 0, MAX_KEYS ) )
			g_fieldBinds[ iter->second.key_one ].commands = iter->first;
		if( isInRange( iter->second.key_two , 0, MAX_KEYS ) )
			g_fieldBinds[ iter->second.key_two ].commands = iter->first;
	}
}
std::string binding::getWatchedCommandName( std::string command )
{
	map<string,string>::iterator iter =	g_mapWatchedCommandsNames.find( command );
	if( iter != g_mapWatchedCommandsNames.end() )
		return iter->second;
	return "";
}

//nacteni database ze souboru
bool binding::loadDatabase( const char * filename, map<std::string, Keys> *bindMap )
{
	if( bindMap == NULL )
		bindMap = &g_mapWatchedCommands;
	bindMap->clear();
	console << "Opening watched commands database file '" << filename << "'" << endline;
	ifstream fin( filename );
	if( !fin.is_open() )
	{
		console << "Error while opening watched commands database: file '" << filename << "'" << endline;
		return false;
	}

	string command;
	Keys newKeys;

	g_rightOrder.clear();
	g_mapWatchedCommandsNames.clear();

	while( true )
	{
		command = readField( fin );	//nacteni prikazu
		if( fin.eof() )
			break;

		//nacteni klaves
		newKeys.key_one = key_database::getKey( readField( fin ) );
		newKeys.key_two = key_database::getKey( readField( fin ) );
		int nameIndex = atoi(readField( fin ).c_str());
		g_mapWatchedCommandsNames.insert( make_pair( command, textLibrary::getText(nameIndex) ) );
		g_rightOrder.push_back( command );
		bindMap->insert( make_pair( command, newKeys ) );
	}

	console << "Watched commands database successfuly loaded" << endline;
	return true;
}

//ulozi novy sledovany prikaz
void binding::addWatchedCommand( std::string command )
{
	g_mapWatchedCommands.insert( make_pair( command, Keys() ) );
}

//vraci klavesu sledovaneho prikazu
Keys *binding::getKeyOfWatchedCommand( std::string command, std::map<std::string, Keys> *bindMap )
{
	if( bindMap == NULL )
		bindMap = &g_mapWatchedCommands;
	map<string,Keys>::iterator iter = bindMap->find( command );
	if( iter == bindMap->end() )
		return NULL;
	return &iter->second;
}

//aktualizuje databazi sledovanych prikazu
bool binding::updateWatchedCommands( std::string commands, int key, map<std::string,Keys> &commandMap, std::string lastKeyCommand, bool alternative )
{
	map<string,Keys>::iterator iter = commandMap.find( commands );

	bool value = false;

	//hledam prikaz v mape
	if( iter != commandMap.end() )
	{
		if( iter->second.key_one == key || iter->second.key_two == key )
			return false;
		//pokud tam je, tak priradim novou hodnotu
		if( !alternative )
		{
			if(  iter->second.key_one != NO_KEY )
			iter->second.key_two = iter->second.key_one;
			iter->second.key_one = key;
		}
		else
			iter->second.key_two = key;
		value = true;
	}

	//jeste je treba zkontrolovat predchozi prikaz na teto klavese
	iter = commandMap.find( lastKeyCommand );
	if( iter != commandMap.end() )	//pokud existuje v mape
	{
		if( iter->second.key_two == key )
			iter->second.key_two = NO_KEY;				//tak mu musime resetovat klavesu, protoze na ni je novy prikaz
		else if( iter->second.key_one == key )
			iter->second.key_one = NO_KEY;
		value = true;
	}
	return value;
}

std::list<std::string> *binding::getRightOrderList()
{
	return &g_rightOrder;
}
