/**
 * @file Config.cpp
 * @author Petr Egert (egertpet@fel.cvut.cz)
 * @brief Contains Config class implementation
 */

#include "Config.h"
#include "Error.h"

#include <cstdio>
#include <sstream>
#include <iostream>
#include <stdlib.h>

using namespace std;
using namespace RD;

Config *Config::instance = NULL;

/**
 * @brief Performs class initialization
 *
 * Currently does nothing
 * @return RES_OK on success
 */
Result Config::Init()
{
    return RES_OK;
}

/**
 * @brief Load configuration from file
 *
 * The file must be in param = value format, where each pair is on a separate line
 *
 * @param fileName Path to the file to be loaded
 * @return RES_OK on success, RES_NOT_FOUND when file is not found/readable
 */
Result Config::Load(const char *fileName)
{
    FILE *inFile = fopen(fileName, "r");
    if(!inFile)
    {
        return ErrorHandler::Error(string("Config::Load(") + string(fileName) + string(") - file not found"), RES_NOT_FOUND);
    }

    while(!feof(inFile))
    {
        char buff[100];
        fgets(buff, 100, inFile);

        char name[100];
        char val[100];
        sscanf(buff, "%s = %s", name, val);

        values[name] = val;
    }
    return RES_OK;
}

/**
 * @brief Performs class deinitialization
 *
 * Currently does nothing
 * @return RES_OK on success
 */
Result Config::Release()
{
    return RES_OK;
}

/**
 * @brief Get value of a config variable as a string
 * @param name Name of the variable
 * @param defVal Default value in case the variable is not found
 * @return Value of the variable or defVal if the variable is not found
 */
std::string Config::GetString(const std::string &name, const std::string &defVal)
{
    MapType::iterator iter = values.find(name);
    if(iter != values.end()) return iter->second;

    ErrorHandler::Notice(string("Config::GetString - requested variable '") + name + string("' not found"));
    return defVal;
}

/**
 * @brief Get value of a config variable as an integer
 * @param name Name of the variable
 * @param defVal Default value in case the variable is not found
 * @return Value of the variable or defVal if the variable is not found
 */
int Config::GetInt(const std::string &name, int defVal)
{
    MapType::iterator iter = values.find(name);
    if(iter != values.end()) return atoi(iter->second.c_str());

    ErrorHandler::Notice(string("Config::GetInt - requested variable '") + name + string("' not found"));
    return defVal;
}

/**
 * @brief Get value of a config variable as a boolean
 * @param name Name of the variable
 * @param defVal Default value in case the variable is not found
 * @return Value of the variable or defVal if the variable is not found
 */
bool Config::GetBool(const std::string &name, bool defVal)
{
    MapType::iterator iter = values.find(name);
    if(iter != values.end())
    {
        return (iter->second == (std::string) "true");
    }

    ErrorHandler::Notice(string("Config::GetBool - requested variable '") + name + string("' not found"));
    return defVal;
}

/**
 * @brief Set value of a config variable as a string
 * @param name Name of the variable
 * @param val Value to be set
 */
void Config::SetString(const std::string &name, const std::string &val)
{
    values[name] = val;
}

/**
 * @brief Set value of a config variable as an integer
 * @param name Name of the variable
 * @param val Value to be set
 */
void Config::SetInt(const std::string &name, int val)
{
    std::ostringstream os;
    os << val;
    values[name] = os.str();
}

/**
 * @brief Set value of a config variable as a boolean
 * @param name Name of the variable
 * @param val Value to be set
 */
void Config::SetBool(const std::string &name, bool val)
{
    std::ostringstream os;
    os << std::boolalpha << val;
    values[name] = os.str();
}
