#include "Variables.h"

#include <cstdlib>
#include <iostream>

namespace Engine {

Variables* VariablesInstance = NULL;

/*
 * Inherited Module functions
 */
int Variables::OnInit (int argc, char* argv[]) {
	LogDebug ("Variables Init");

	VariablesInstance = this;

	/* This definition of a variable causes the delayed variables to be loaded,
	 * please keep it here! */
	static Variable VariableSystemUp_var ("variablesystemup", "true");

	return 0;
}

void Variables::OnDestroy () {
	LogDebug ("Variables Destroy");

	VariablesInstance = NULL;
}

/*
 * Module specific functions
 */
void Variables::RegisterVariable (const std::string &name, Variable *var) {
	LogDebug ("Registering Variable '%s'", name.c_str ());
	if (mVariablesData.find (name) != mVariablesData.end()) {
		// Variable already existing!
		mVariablesData[name] = var;

		return;
	}

	mVariablesData[name] = var;
	
	return;
}

/*
 * Variable class
 */
Variable* Variables::GetVariable (const std::string &name) {
	if (mVariablesData.find (name) == mVariablesData.end()) {
		// Variable not existing!
		return NULL;
	}

	return mVariablesData[name];
}

Variable::Variable (const std::string &name, const std::string &value) {
	static std::vector<Variable*> delayed_variables;

	mName = name;
	mStringValue = value;
	mFloatValue = atof (value.c_str());
	mBoolValue = ParseBoolValue (value);

	if (VariablesInstance == NULL) {
		delayed_variables.push_back (this);
	} else if (delayed_variables.size() > 0) {
		LogDebug ("Loading delayed Variables");
		unsigned int i; 
		for (i = 0; i < delayed_variables.size(); i ++)
			VariablesInstance->RegisterVariable (delayed_variables[i]->mName, delayed_variables[i]);

		delayed_variables.clear ();

		RegisterVariable (name);
	} else {
		RegisterVariable (name);
	}
}

void Variable::Set (const std::string &value) {
	mStringValue = value;
	mFloatValue = atof (value.c_str());
	mBoolValue = ParseBoolValue (value);
}

void Variable::RegisterVariable (const std::string &name) {
if (! VariablesInstance ) {
		LogError ("Unable to register Variable '%s': Variables System not initialized!", name.c_str());
		return;
	}

	VariablesInstance->RegisterVariable (name, this);
}

bool Variable::ParseBoolValue (std::string value) {
	float float_value = atof (value.c_str());

	if (float_value != 0.)
		return true;

	// transform to upper case
	unsigned int i;
	for (i = 0; i < value.size(); i++)
		value[i] = tolower (value[i]);

	if (value == "true"
			|| value == "yes")
		return true;

	return false;
}

/*
 * Global functions
 */
Variable* GetVariable (const std::string &name) {
	if (! VariablesInstance ) {
		LogError ("Unable to register Variable '%s': Variables System not initialized!", name.c_str());
		return NULL;
	}

	return VariablesInstance->GetVariable (name);
}

bool SetVariableValue (const std::string &name, const std::string &value) {
	if (! VariablesInstance ) {
		LogError ("Unable to set Variable '%s': Variables System not initialized!", name.c_str());
		return false;
	}

	Variable *var = VariablesInstance->GetVariable (name);
	if (!var) {
		return false;
	}

	var->SetStringValue (value);
	var->SetBoolValueFromString (value);
	var->SetFloatValue (atof (value.c_str()));

	return true;
}

std::string& GetVariableString (const std::string &name, std::string def) {
	/* We use a static result variable for the case that def was not passed to
	 * is function */
	static std::string def_result = def;

	if (! VariablesInstance ) {
		LogError ("Unable to register Variable '%s': Variables System not initialized!", name.c_str());
		return def_result;
	}

	Variable *var = VariablesInstance->GetVariable (name);
	if (!var) {
		return def_result;
	}

	return var->GetStringValue ();
}

float &GetVariableFloat (const std::string &name, float def) {
	/* We use a static result variable for the case that def was not passed to
	 * is function */
	static float def_result = def;

	if (! VariablesInstance ) {
		LogError ("Unable to register Variable '%s': Variables System not initialized!", name.c_str());
		return def_result;
	}

	Variable *var = VariablesInstance->GetVariable (name);
	if (!var) {
		return def_result;
	}

	return var->GetFloatValue ();
}

/** \brief Returns the boolean value of the Variable with the given name */
bool& GetVariableBool (const std::string &name, bool def) {
	/* We use a static result variable for the case that def was not passed to
	 * is function */
	static bool def_result = def;

	if (! VariablesInstance ) {
		LogError ("Unable to register Variable '%s': Variables System not initialized!", name.c_str());
		return def_result;
	}

	Variable *var = VariablesInstance->GetVariable (name);
	if (!var) {
		return def_result;
	}

	return var->GetBoolValue ();
}

}

