/* GMM (C) 2018 Stephane Charette <stephanecharette@gmail.com>
 * $Id: Cfg.cpp 2687 2018-12-06 21:15:40Z stephane $
 */

#include "Cfg.hpp"


Cfg::Cfg(void) :
	PropertiesFile(
		[]
		{
			PropertiesFile::Options options;

			options.storageFormat			= PropertiesFile::StorageFormat::storeAsXML;
			options.applicationName			= "GormanMoistureMeter";
			options.filenameSuffix			= ".cfg";
			options.commonToAllUsers		= true;
			options.ignoreCaseOfKeyNames	= true;

			return options;
		}() )
{
	LOG_MSG("configuration file used: " << getFile().getFullPathName().toStdString());

	first_time_initialization();

	return;
}


Cfg &Cfg::first_time_initialization(void)
{
	insert_if_not_exist("get_version_number"		, "TRUE");
	insert_if_not_exist("get_motd"					, "TRUE");
	insert_if_not_exist("output_directory"			, "C:\\22m2k\\data\\%Y\\boardmc\\");
	insert_if_not_exist("opc_console_application"	, "OPCConsole.exe");
	insert_if_not_exist("opc_url"					, "opcda://localhost/RSLinx OPC Server");
	insert_if_not_exist("opc_group"					, "INFEED");
	insert_if_not_exist("opc_show_console_window"	, "FALSE");
	insert_if_not_exist("allow_user_to_close"		, "TRUE");

	insert_if_not_exist("warn_if_package_contains_too_many_boards"	, "TRUE");
	insert_if_not_exist("warn_board_threshold"						, "1500");
	insert_if_not_exist("warn_seconds_between_warnings"				, "300");

	// reset this every time, since the temp directory is based on the currently logged in username
	// example:  "C:\Users\STPHAN~1\AppData\Local\Temp\gmm_opc_output.txt"
	set_str("opc_output_filename", File::getSpecialLocation(File::tempDirectory).getChildFile("gmm_opc_output.txt").getFullPathName().toStdString());

	const bool result = saveIfNeeded();
	if (! result)
	{
		gmm().errors.push_back("Failed to save configuration file " + getFile().getFullPathName().toStdString() + ". (Permission issues?)");
	}

	return *this;
}


Cfg::~Cfg(void)
{
	return;
}


Cfg &Cfg::insert_if_not_exist(const std::string &key, const std::string &val)
{
	if (containsKey(key.c_str()) == false)
	{
		setValue(key.c_str(), val.c_str());
	}

	return *this;
}


Cfg &Cfg::insert_if_not_exist(const std::string &key, const int &val)
{
	return insert_if_not_exist(key, std::to_string(val));
}


Cfg &Cfg::set_str(const std::string &key, const std::string &val)
{
	setValue(key.c_str(), val.c_str());

	return *this;
}


std::string Cfg::get_str(const std::string &key)
{
	if (containsKey(key.c_str()) == false)
	{
		Lox::Exception ex( LOX_WHERE, "expected configuration to contain a key named \"" + key + "\"");
		throw ex;
	}

	return getValue(key.c_str()).toStdString();
}


std::string Cfg::get_str(const std::string &key, const std::string &default_value)
{
	if (containsKey(key.c_str()) == false)
	{
		return default_value;
	}

	return getValue(key.c_str()).toStdString();
}


int Cfg::get_int(const std::string &key)
{
	if (containsKey(key.c_str()) == false)
	{
		Lox::Exception ex( LOX_WHERE, "expected configuration to contain a key named \"" + key + "\"");
		throw ex;
	}

	return getIntValue(key.c_str());
}


bool Cfg::get_bool(const std::string &key, const bool default_value)
{
	if (containsKey(key.c_str()) == false)
	{
		return default_value;
	}

	/* 2018-03-13:  There is a method called getBoolValue(), but when I tested
	 * it with values in configuration such as "true", it was returning false
	 * which led me to decide to write my own get_bool().
	 */

	const String val = getValue(key.c_str());

	if (val.compareIgnoreCase("true")	== 0 ||
		val.compareIgnoreCase("yes")	== 0 ||
		val.compareIgnoreCase("t")		== 0 ||
		val.compareIgnoreCase("y")		== 0 ||
		val.compareIgnoreCase("1")		== 0)
	{
		return true;
	}

	if (val.compareIgnoreCase("false")	== 0 ||
		val.compareIgnoreCase("no")		== 0 ||
		val.compareIgnoreCase("f")		== 0 ||
		val.compareIgnoreCase("n")		== 0 ||
		val.compareIgnoreCase("0")		== 0)
	{
		return false;
	}

	// otherwise, any other value is ignored and we return the default one
	return default_value;
}
