/*
   core/cvar.cc
   This file is part of the Osirion project and is distributed under
   the terms of the GNU General Public License version 2
*/

#include "core/cvar.h"
#include "sys/sys.h"

#include <map>
#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>


namespace core
{

Cvar				*Cvar::con_ansi = 0;
Cvar				*Cvar::con_timestamps = 0;

Cvar				*Cvar::sv_dedicated = 0;
Cvar				*Cvar::sv_private = 0;
Cvar				*Cvar::sv_framerate = 0;
Cvar				*Cvar::sv_name = 0;
Cvar				*Cvar::sv_description = 0;
Cvar				*Cvar::sv_password = 0;
Cvar				*Cvar::sv_keepalive = 0;
Cvar				*Cvar::sv_collisionmargin = 0;

Cvar				*Cvar::net_host = 0;
Cvar				*Cvar::net_port = 0;
Cvar				*Cvar::net_maxclients = 0;
Cvar				*Cvar::net_timeout = 0;
Cvar				*Cvar::net_framerate = 0;
Cvar				*Cvar::net_selecttimeout = 0;

Cvar				*Cvar::mem_vertex = 0;

Cvar::Registry 			Cvar::cvar_registry;

Cvar::Cvar(const char* name, const unsigned int flags) : cvar_name(name), cvar_info(), cvar_str()
{
	cvar_flags = flags;
}

void Cvar::set_info(const char* info)
{
	if (info)
		cvar_info.assign(info);
}

void Cvar::assign(const std::string& other)
{
	cvar_str = other;
	std::stringstream s(cvar_str);
	if (!(s >> cvar_value))
		cvar_value = cvar_str.size();
}

void Cvar::assign(const char* other)
{
	if (other) {
		cvar_str.assign(other);
		std::stringstream s(cvar_str);
		if (!(s >> cvar_value))
			cvar_value = cvar_str.size();
	} else {
		cvar_str.clear();
		cvar_value = 0;
	}
}

void Cvar::assign(const float other)
{
	std::stringstream s;
	s << other;
	s >> cvar_str;
	cvar_value = other;
}

Cvar* Cvar::get(const char* name, const char* value, const unsigned int flags)
{
	Cvar *c = find(name);
	if (!c) {
		c = new Cvar(name, flags);
		c->assign(value);
		cvar_registry[c->name()] = c;
	}
	c->cvar_flags |= flags;
	return c;
}

Cvar* Cvar::get(const char* name, const float value, const unsigned int flags)
{
	Cvar *c = find(name);
	if (!c) {
		c = new Cvar(name, flags);
		c->assign(value);
		cvar_registry[c->name()] = c;
	}
	c->cvar_flags |= flags;
	return c;
}

Cvar* Cvar::set(const char* name, const char* value, const unsigned int flags)
{
	Cvar *c = find(name);
	if (!c) {
		c = new Cvar(name, flags);
		cvar_registry[c->name()] = c;
	}
	c->assign(value);
	c->cvar_flags = flags;

	//con_debug << "set " << name << " " << cvar->str() << std::endl;
	return c;
}

Cvar* Cvar::set(const char* name, const float value, const unsigned int flags)
{
	Cvar *c = find(name);
	if (!c) {
		c = new Cvar(name, flags);
		cvar_registry[c->name()] = c;
	}
	c->assign(value);
	c->cvar_flags = flags;

	//con_debug << "set " << name << " " << cvar->str() << std::endl;
	return c;
}

void Cvar::unset(const std::string& name)
{
	Cvar *c = find(name);
	if (c) {
		con_debug << "unset " << name << std::endl;
		cvar_registry.erase(name);
		delete c;
	}
}

void Cvar::unset(const char* name)
{
	if (!name)
		return;

	std::string namestr(name);
	unset(namestr);
}

Cvar *Cvar::find(const std::string& name)
{
	Registry::iterator it = cvar_registry.find(name);
	if (it == cvar_registry.end())
		return 0;
	else
		return (*it).second;
}

Cvar *Cvar::find(const char* name)
{
	if (!name)
		return 0;

	std::string namestr(name);
	return(find(namestr));
}

void Cvar::list()
{
	Registry::iterator it;
	for (it = cvar_registry.begin(); it != cvar_registry.end(); it++) {
		std::string typeindicator;
		if (((*it).second->flags() & Archive) == Archive)
			typeindicator += 'A';
		else
			typeindicator += ' ';

		if (((*it).second->flags() & Game) == Game)
			typeindicator += 'G';
		else
			typeindicator += ' ';

		if (((*it).second->flags() & ReadOnly) == ReadOnly)
			typeindicator += 'R';
		else
			typeindicator += ' ';

		con_print << " " << typeindicator <<
		" " << (*it).first << " " << (*it).second->str() << " ^N" << (*it).second->info() << std::endl;
	}
	con_print << "  Flags: A=Archive G=Game R=ReadOnly" << std::endl;
	con_print << "^B  " << cvar_registry.size() << " registered variables" << std::endl;
}

}