/*********************************************************************//**
*	Game variables library.
*	Modul uziva mapu pro ukladani promenych a tvori 
*			databazi vsech promenych. Promenna ma pristupova prava,
*			minimalni, maximalni a standardni hodnotu.  
*
*	author: Michal Jirous
*	date: 23.7.2008
*	file: ctrl_gamevars.cpp
**********************************************************************/

#include "ctrl_gamevars.h"
#include <map>
#include "sys_config.h"
#include "sys_console.h"
#include "mathematic.h"
#include "ctrl_var_definition.h"

using namespace vardef;
using namespace systemConsole;
using namespace std;

using namespace gamevarsLibrary;

map<string,variable> g_variableMap;

void gamevarsLibrary::init()
{
	console << "Initializing game variables...";
	initVariables();
	console << "done" << endline;
}

void gamevarsLibrary::initVariables()
{
	//definice ingame promenych
	gamevarsLibrary::addVar( MAXSPEED_NAME, MAXSPEED_DEFAULT, MAXSPEED_DEVELOPER_STATUS, MAXSPEED_MIN, MAXSPEED_MAX);
	gamevarsLibrary::addVar(ACCELERATION_NAME, ACCELERATION_DEFAULT, ACCELERATION_DEVELOPER_STATUS, ACCELERATION_MIN, ACCELERATION_MAX);
	gamevarsLibrary::addVar("cl_up", 0.3f);
	gamevarsLibrary::addVar("cl_down", 0.3f);
	gamevarsLibrary::addVar( NAME_NAME, NAME_DEFAULT, NAME_DEVELOPER_STATUS, NAME_MAXLENGHT);
	gamevarsLibrary::addVar("cl_camera", 0);
	gamevarsLibrary::addVar( SENSITIVITY_NAME, SENSITIVITY_DEFAULT, SENSITIVITY_DEVELOPER_STATUS, SENSITIVITY_MIN, SENSITIVITY_MAX);
	gamevarsLibrary::addVar( GRAVITY_NAME, GRAVITY_DEFAULT, GRAVITY_DEVELOPER_STATUS, GRAVITY_MIN, GRAVITY_MAX);
	gamevarsLibrary::addVar( FRICTION_NAME, FRICTION_DEFAULT, false, 0.0f,1000.0f );
	gamevarsLibrary::addVar( MAX_DISTANCE_NAME, MAX_DISTANCE_DEFAULT, MAX_DISTANCE_DEVELOPER_STATUS, MAX_DISTANCE_MIN, MAX_DISTANCE_MAX);
	gamevarsLibrary::addVar("sv_fog",1);
	gamevarsLibrary::addVar("sv_skylight",1);
	gamevarsLibrary::addVar("sv_sunlight",1);
	gamevarsLibrary::addVar("cl_flashlight",0);
	gamevarsLibrary::addVar("cl_menu",0);
	gamevarsLibrary::addVar("cl_flashcolor",0);
	gamevarsLibrary::addVar(USE_DISTANCE_NAME, USE_DISTANCE_DEFAULT, USE_DISTANCE_DEVELOPER_STATUS, USE_DISTANCE_MIN, USE_DISTANCE_MAX );
	gamevarsLibrary::addVar(JUMPHEIGHT_NAME, JUMPHEIGHT_DEFAULT, JUMPHEIGHT_DEVELOPER_STATUS, JUMPHEIGHT_MIN, JUMPHEIGHT_MAX );
	gamevarsLibrary::addVar("mapname","");
	gamevarsLibrary::addVar( DEFAULT_FOV_NAME, DEFAULT_FOV_DEFAULT, DEFAULT_DEVELOPER_STATUS, DEFAULT_FOV_MIN, DEFAULT_FOV_MAX);
	gamevarsLibrary::addVar("leveldetail", 2, PUBLIC);
	gamevarsLibrary::addVar( REVERSE_MOUSE_H_NAME, REVERSE_MOUSE_H_DEFAULT, REVERSE_MOUSE_H_DEVELOPER_STATUS);
	gamevarsLibrary::addVar( REVERSE_MOUSE_V_NAME, REVERSE_MOUSE_V_DEFAULT, REVERSE_MOUSE_V_DEVELOPER_STATUS);
	gamevarsLibrary::addVar( OCTREE_MIN_RANGE_NAME, OCTREE_MIN_RANGE_DEFAULT, OCTREE_MIN_RANGE_DEVELOPER_STATUS, OCTREE_MIN_RANGE_MIN, OCTREE_MIN_RANGE_MAX);
	gamevarsLibrary::addVar( FALLDAMAGE_NAME, FALLDAMAGE_DEFAULT, FALLDAMAGE_DEVELOPER_STATUS, FALLDAMAGE_MIN, FALLDAMAGE_MAX);
	gamevarsLibrary::addVar( POINTING_DISTANCE_NAME, POINTING_DISTANCE_DEFAULT, POINTING_DISTANCE_DEVELOPER_STATUS, POINTING_DISTANCE_MIN, POINTING_DISTANCE_MAX);	
	gamevarsLibrary::addVar( DETAIL_DISTANCE_NAME, DETAIL_DISTANCE_DEFAULT, DETAIL_DISTANCE_DEVELOPER_STATUS, DETAIL_DISTANCE_MIN, DETAIL_DISTANCE_MAX);

	//HUD health window
	gamevarsLibrary::addVar( HUD_HEALTH_WIN_X, HUD_HEALTH_WIN_X_DEFAULT, HUD_HEALTH_WIN_X_STATUS, HUD_HEALTH_WIN_X_MIN, HUD_HEALTH_WIN_X_MAX);
	gamevarsLibrary::addVar( HUD_HEALTH_WIN_Y, HUD_HEALTH_WIN_Y_DEFAULT, HUD_HEALTH_WIN_Y_STATUS, HUD_HEALTH_WIN_Y_MIN, HUD_HEALTH_WIN_Y_MAX);

	//HUD oxygen window
	gamevarsLibrary::addVar( HUD_OXYGEN_WIN_X, HUD_OXYGEN_WIN_X_DEFAULT, HUD_OXYGEN_WIN_X_STATUS, HUD_OXYGEN_WIN_X_MIN, HUD_OXYGEN_WIN_X_MAX);
	gamevarsLibrary::addVar( HUD_OXYGEN_WIN_Y, HUD_OXYGEN_WIN_Y_DEFAULT, HUD_OXYGEN_WIN_Y_STATUS, HUD_OXYGEN_WIN_Y_MIN, HUD_OXYGEN_WIN_Y_MAX);
	
	//HUD crosshair window
	gamevarsLibrary::addVar( HUD_CROSSHAIR_WIN_X, HUD_CROSSHAIR_WIN_X_DEFAULT, HUD_CROSSHAIR_WIN_X_STATUS, HUD_CROSSHAIR_WIN_X_MIN, HUD_CROSSHAIR_WIN_X_MAX);
	gamevarsLibrary::addVar( HUD_CROSSHAIR_WIN_Y, HUD_CROSSHAIR_WIN_Y_DEFAULT, HUD_CROSSHAIR_WIN_Y_STATUS, HUD_CROSSHAIR_WIN_Y_MIN, HUD_CROSSHAIR_WIN_Y_MAX);

	//HUD Ammo window
	gamevarsLibrary::addVar( HUD_AMMO_WIN_X, HUD_AMMO_WIN_X_DEFAULT, HUD_AMMO_WIN_X_STATUS, HUD_AMMO_WIN_X_MIN, HUD_AMMO_WIN_X_MAX);
	gamevarsLibrary::addVar( HUD_AMMO_WIN_Y, HUD_AMMO_WIN_Y_DEFAULT, HUD_AMMO_WIN_Y_STATUS, HUD_AMMO_WIN_Y_MIN, HUD_AMMO_WIN_Y_MAX);

	//HUD Energy window
	gamevarsLibrary::addVar( HUD_ENERGY_WIN_X, HUD_ENERGY_WIN_X_DEFAULT, HUD_ENERGY_WIN_X_STATUS, HUD_ENERGY_WIN_X_MIN, HUD_ENERGY_WIN_X_MAX);
	gamevarsLibrary::addVar( HUD_ENERGY_WIN_Y, HUD_ENERGY_WIN_Y_DEFAULT, HUD_ENERGY_WIN_Y_STATUS, HUD_ENERGY_WIN_Y_MIN, HUD_ENERGY_WIN_Y_MAX);

	//HUD Targets window
	gamevarsLibrary::addVar( HUD_TARGETS_WIN_X, HUD_TARGETS_WIN_X_DEFAULT, HUD_TARGETS_WIN_X_STATUS, HUD_TARGETS_WIN_X_MIN, HUD_TARGETS_WIN_X_MAX);
	gamevarsLibrary::addVar( HUD_TARGETS_WIN_Y, HUD_TARGETS_WIN_Y_DEFAULT, HUD_TARGETS_WIN_Y_STATUS, HUD_TARGETS_WIN_Y_MIN, HUD_TARGETS_WIN_Y_MAX);
	
	//HUD Gametime window
	gamevarsLibrary::addVar( HUD_GAMETIME_WIN_X, HUD_GAMETIME_WIN_X_DEFAULT, HUD_GAMETIME_WIN_X_STATUS, HUD_GAMETIME_WIN_X_MIN, HUD_GAMETIME_WIN_X_MAX);
	gamevarsLibrary::addVar( HUD_GAMETIME_WIN_Y, HUD_GAMETIME_WIN_Y_DEFAULT, HUD_GAMETIME_WIN_Y_STATUS, HUD_GAMETIME_WIN_Y_MIN, HUD_GAMETIME_WIN_Y_MAX);

	//HUD Level report window
	gamevarsLibrary::addVar( HUD_LEVEL_REPORT_WIN_X, HUD_LEVEL_REPORT_WIN_X_DEFAULT, HUD_LEVEL_REPORT_WIN_X_STATUS, HUD_LEVEL_REPORT_WIN_X_MIN, HUD_LEVEL_REPORT_WIN_X_MAX);
	gamevarsLibrary::addVar( HUD_LEVEL_REPORT_WIN_Y, HUD_LEVEL_REPORT_WIN_Y_DEFAULT, HUD_LEVEL_REPORT_WIN_Y_STATUS, HUD_LEVEL_REPORT_WIN_Y_MIN, HUD_LEVEL_REPORT_WIN_Y_MAX);

	//HUD health window
	gamevarsLibrary::addVar( HUD_FPS_WIN_X, HUD_FPS_WIN_X_DEFAULT, HUD_FPS_WIN_X_STATUS, HUD_FPS_WIN_X_MIN, HUD_FPS_WIN_X_MAX);
	gamevarsLibrary::addVar( HUD_FPS_WIN_Y, HUD_FPS_WIN_Y_DEFAULT, HUD_FPS_WIN_Y_STATUS, HUD_FPS_WIN_Y_MIN, HUD_FPS_WIN_Y_MAX);

	//Ammo max
	gamevarsLibrary::addVar( AMMO_9MM_NAME, AMMO_9MM_DEFAULT, AMMO_9MM_DEVELOPER_STATUS, AMMO_9MM_MIN, AMMO_9MM_MAX);
	
	
	//Weapon max ammos
	gamevarsLibrary::addVar( WEAPON_9MMPISTOL_MAX_NAME, WEAPON_9MMPISTOL_MAX_DEFAULT, WEAPON_9MMPISTOL_MAX_DEVELOPER_STATUS, WEAPON_9MMPISTOL_MAX_MIN, WEAPON_9MMPISTOL_MAX_MAX);
	gamevarsLibrary::addVar( WEAPON_MP5_MAX_NAME, WEAPON_MP5_MAX_DEFAULT, WEAPON_MP5_MAX_DEVELOPER_STATUS, WEAPON_MP5_MAX_MIN, WEAPON_MP5_MAX_MAX);

	//Weapon damages
	gamevarsLibrary::addVar( WEAPON_KNIFE_DMG_NAME, WEAPON_KNIFE_DMG_DEFAULT, WEAPON_KNIFE_DMG_DEVELOPER_STATUS, WEAPON_KNIFE_DMG_MIN, WEAPON_KNIFE_DMG_MAX);
	gamevarsLibrary::addVar( WEAPON_9MMPISTOL_DMG_NAME, WEAPON_9MMPISTOL_DMG_DEFAULT, WEAPON_9MMPISTOL_DMG_DEVELOPER_STATUS, WEAPON_9MMPISTOL_DMG_MIN, WEAPON_9MMPISTOL_DMG_MAX);
	gamevarsLibrary::addVar( WEAPON_MP5_DMG_NAME, WEAPON_MP5_DMG_DEFAULT, WEAPON_MP5_DMG_DEVELOPER_STATUS, WEAPON_MP5_DMG_MIN, WEAPON_MP5_DMG_MAX);

	

}

void gamevarsLibrary::addVar(string key, int data, bool allowed_for_user, int min, int max )
{
	if( getVariable(key ) )
		return;

	variable var;
	IntData *d = new IntData();
	d->min = min;
	d->max = max;
	d->default_value = getFromRange( data, min, max );
	d->value = d->default_value;
	var.type = VAR_INT;
	var.data = d;
	var.user_allowed = allowed_for_user;
	g_variableMap.insert( make_pair( key, var ) );
}

void gamevarsLibrary::addVar(string key, float data, bool allowed_for_user, float min, float max)
{
	if( getVariable(key ) )
		return;

	variable var;
		FloatData *d = new FloatData;
		d->min = min;
		d->max = max;
		d->default_value = getFromRange( data, min, max );;
		d->value = d->default_value;
	var.data = d;
	var.type = VAR_FLOAT;
	var.user_allowed = allowed_for_user;
	g_variableMap.insert( make_pair( key, var ) );
}

void gamevarsLibrary::addVar(string key, string data, bool allowed_for_user, size_t maxlength )
{
	if( getVariable(key ) )
		return;

	variable var;
	StringData *d = new StringData();
	d->maxlength = maxlength;
	if( data.length() >  maxlength )
		data = data.substr(0,maxlength);
	d->default_value = data;
	d->value = data;
	var.data = d;	
	var.type = VAR_STRING;
	var.user_allowed = allowed_for_user;
	g_variableMap.insert( make_pair( key, var ) );
}

variable *gamevarsLibrary::getVariable(string key)
{
	//na zaklade klice vraci ukazatel na objekt tabulky
	map<string,variable>::iterator iter = g_variableMap.find( key );
	if( iter != g_variableMap.end() )
		return &iter->second;
	
	return NULL;
}

bool isChangeable( variable *var )
{
	if( !var->user_allowed && systemconf::getSystemInfo().m_iDeveloper_mode == 0 )
	{
		console << ERROR_VARIABLE_DEVELOPER_ONLY << endline;
		return false;
	}
	return true;

}

bool checkAndSetValue( IntData *d, int value )
{
	if( !isInRange( value, d->min, d->max ) )
	{
		console << ERROR_VARIABLE_OUT_OF_RANGE << d->min << "-" << d->max <<"." << endline;
		return false;
	}
	d->value = value;
	return true;
}

bool checkAndSetValue( FloatData *d, float value )
{
	if( !isInRange( value, d->min, d->max ) )
	{
		console << ERROR_VARIABLE_OUT_OF_RANGE << d->min << "-" << d->max <<"." << endline;
		return false;
	}
	d->value = value;
	return true;
}

bool gamevarsLibrary::setVariable(string key, int data)
{
	//nastavi data objektu na zaklade klice
	variable *var = getVariable(key);
	if( !var || var->type != VAR_INT || !isChangeable( var ))
	{
		console << VARIABLE_TYPE_ERROR << "INTEGER" << endline;
		return false;
	}
	
	IntData *d = (IntData*)var->data;
	return checkAndSetValue( d, data );
}

bool gamevarsLibrary::setVariable(string key, float data)
{
	variable *var = getVariable(key);
	if( !var || var->type != VAR_FLOAT || !isChangeable( var ) )
	{
		console << VARIABLE_TYPE_ERROR << "FLOAT" << endline;
		return false;
	}
	
	FloatData *d = (FloatData*)var->data;
	return checkAndSetValue( d, data );
}

bool gamevarsLibrary::setVariable(string key, string data)
{
	variable *var = getVariable(key);
	if( !var || var->type != VAR_STRING || !isChangeable( var ) )
	{
		console << VARIABLE_TYPE_ERROR << "STRING" << endline;
		return false;
	}
	
	StringData *d = (StringData*)var->data;
	if( data.length() > d->maxlength )
		data = data.substr(0,d->maxlength );

	d->value = data;
	return true;
}

bool gamevarsLibrary::setVariable(variable *var, int data)
{
	if( var )
	{
		if( var->type != VAR_INT )
		{
			console << VARIABLE_TYPE_ERROR << "INT" << endline;
			return false;
		}
	
		IntData *d = (IntData*)var->data;
		return checkAndSetValue( d, data );;
	}
	return false;
}

bool gamevarsLibrary::setVariable(variable *var, float data)
{
	if( var )
	{	
		if( var->type != VAR_FLOAT )
		{
			console << VARIABLE_TYPE_ERROR << "FLOAT" << endline;
			return false;
		}
	
		FloatData *d = (FloatData*)var->data;
		return checkAndSetValue( d, data );
	}
	return false;
}

bool gamevarsLibrary::setVariable(variable *var, string data)
{
	if( var )
	{
		if( var->type != VAR_STRING )
		{
			console << VARIABLE_TYPE_ERROR << "STRING" << endline;
			return false;
		}
	
		StringData *d = (StringData*)var->data;
		if( data.length() > d->maxlength )
			data = data.substr(0,d->maxlength );
		d->value = data;
		return true;
	}
	return false;
}

int gamevarsLibrary::getiData(string key)
{
	//vraci int hodnotu objektu
	return getiData( getVariable(key ) );
}

float gamevarsLibrary::getfData(string key)
{
	return getfData( getVariable(key ) );
}

string gamevarsLibrary::getsData(string key)
{
	return getsData( getVariable(key ) );

}

int gamevarsLibrary::getiData(variable *var)
{
	//vraci int hodnotu objektu
	if( !var || var->type != VAR_INT )
		return 0;
	
	return ((IntData*)var->data)->value;
}

float gamevarsLibrary::getfData(variable *var)
{
	if( !var  || var->type != VAR_FLOAT )
		return 0;
	
	return ((FloatData*)var->data)->value;
}

std::string gamevarsLibrary::getsData(variable *var)	
{
	if( !var|| var->type != VAR_STRING )
		return "";

	return ((StringData*)var->data)->value;
}



void gamevarsLibrary::destroy()
{
	for( map<string,variable>::iterator iter = g_variableMap.begin(); iter != g_variableMap.end(); iter++)
	{

		if( iter->second.data != NULL )
		{
			switch( iter->second.type )
			{
				case VAR_INT:
					{
						IntData *d = (IntData*)iter->second.data;
						delete d;
					}
					break;
				case VAR_FLOAT:
					{
						FloatData *d = (FloatData*)iter->second.data;
						delete d;
					}
					break;
				case VAR_STRING:
					{
						StringData *d = (StringData*)iter->second.data;
						delete d;
					}
					break;
			}
		}
	}
}


void gamevarsLibrary::printVar( std::string name, variable *var )
{
	if( var )
	{
		
		switch( var->type )
			{
				case VAR_INT:
					{
						IntData *d = (IntData*)var->data;
						console << "-> '" << name << "' = '" << d->value << "'." << endline;
					}
					break;
				case VAR_FLOAT:
					{
						FloatData *d = (FloatData*)var->data;
						console << "-> '" << name << "' = '" << d->value << "'." << endline;
					}
					break;
				case VAR_STRING:
					{
						StringData *d = (StringData*)var->data;
						console << "-> '" << name << "' = '" << d->value << "'." << endline;
					}
					break;
			}
	
	
	
	
	}


}



void gamevarsLibrary::printVar( std::string var )
{
	printVar( var, gamevarsLibrary::getVariable( var ) );
}
