/*
  Copyright (C) 2010-2011  Charles Pence <charles@charlespence.net>
  Copyright (C) 1996-1997  Id Software, Inc.

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "pch.h"
#include "quakedef.h"

class cvar_t
{
public:
    cvar_t() : s(""), have_float(false), f(0.0f) { }

    bool archive;
    
    void set(const std::string &str)
    { s = str; have_float = false; }
    
    const std::string &to_s()
    { return s; }

    float to_f()
    {
        if (!have_float)
        {
            f = Util::lexical_cast<float>(s);
            have_float = true;
        }
        
        return f;
    }

private:
    std::string s;

    bool have_float;
    float f;
};

typedef boost::unordered_map<std::string, cvar_t> cvar_map;
static cvar_map cvar_vars;

/*
============
Cvar_VariableValue
============
*/
float Cvar_VariableValue (const std::string &var_name)
{
    return cvar_vars[var_name].to_f();
}


/*
============
Cvar_VariableString
============
*/
std::string Cvar_VariableString (const std::string &var_name)
{
    return cvar_vars[var_name].to_s();
}


/*
============
Cvar_CompleteVariable
============
*/
std::string Cvar_CompleteVariable(const std::string &partial)
{
    if (!partial.length())
        return std::string();

    // check functions
    for (cvar_map::iterator iter = cvar_vars.begin() ;
         iter != cvar_vars.end() ; ++iter)
    {
        if (!(*iter).first.compare(0, partial.length(), partial))
            return (*iter).first;
    }

    return std::string();
}


/*
============
Cvar_Set
============
*/
void Cvar_Set(const std::string &var_name, const std::string &value)
{
    cvar_vars[var_name].set(value);
}

/*
============
Cvar_SetValue
============
*/
void Cvar_SetValue(const std::string &var_name, float value)
{
    Cvar_Set(var_name, Util::lexical_cast<std::string>(value));
}


/*
============
Cvar_RegisterVariable

Adds a freestanding variable to the variable list.
============
*/
void Cvar_RegisterVariable(const std::string &name, const std::string &value, qboolean archive)
{
    cvar_vars[name].set(value);
    cvar_vars[name].archive = archive;
}

/*
============
Cvar_Command

Handles variable inspection and changing from the console
============
*/
qboolean Cvar_Command (void)
{
    // check variables
    if (!cvar_vars.count(Cmd_Argv(0)))
        return false;

    // perform a variable print or set
    cvar_t &v = cvar_vars[Cmd_Argv(0)];
    
    if (Cmd_Argc() == 1)
    {
        Con_Printf ("\"%s\" is \"%s\"\n", Cmd_Argv(0).c_str(), v.to_s().c_str());
        return true;
    }

    Cvar_Set (Cmd_Argv(0), Cmd_Argv(1));
    return true;
}


/*
============
Cvar_WriteVariables

Writes lines containing "set variable value" for all variables
with the archive flag set to true.
============
*/
void Cvar_WriteVariables (File &fp)
{
    for (cvar_map::iterator iter = cvar_vars.begin() ; 
         iter != cvar_vars.end() ; ++iter)
    {
        if ((*iter).second.archive)
            fp.Printf("%s \"%s\"\n", (*iter).first.c_str(), (*iter).second.to_s().c_str());
    }
}

