#include "cfg-value.h"

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <limits.h>

#include <errno.h>

#include "scm-mem.h"
#include "io-guts.h"

// -------------------------------------------------------------------------------------------- //
// * Implementation *
// -------------------------------------------------------------------------------------------- //


// CPP 
namespace scm {

	// = x^p
	int ipow(const int x, const int p)
	{
		if (p == 0) return 1;
		if (p == 1) return x;

		int tmp = ipow(x, p / 2);
		if (p % 2 == 0) return tmp*tmp;
		else
			return x*tmp*tmp;
	}
}

// -------------------------------------------------------------------------------------------- //
bool scm::is_integer(const char* token, int* value)
{
	const int mode = 10;
	char* pend;

	if (strlen(token) == 0) return false;

	errno = 0;
	long lvalue = strtol(token, &pend, mode);
	if ((errno == ERANGE && (lvalue == LONG_MAX || lvalue == LONG_MIN)) ||
		(errno != 0 && lvalue == 0)) {
		return false;
	}
	// checking integer bounds //
	if ((lvalue >= INT_MAX) || (lvalue <= INT_MIN)) return false;
	if (*pend != '\0') return false;

	*value = (int)lvalue;
	return true;
}

bool scm::is_integer(const char* token)
{
	int value;
	return is_integer(token, &value);
}

bool scm::is_double(const char* token, double* value)
{
	char* pend;

	if (strlen(token) == 0) return false;

	errno = 0;
	*value = strtod(token, &pend);
	if ((errno == ERANGE && (*value == HUGE_VAL || *value == -HUGE_VAL)) ||
		(errno != 0 && *value == (double)0)) {
		return false;
	}

	if (*pend != '\0') return false;
	return true;
}

bool scm::is_double(const char* token)
{
	double value;
	return is_double(token, &value);
}

bool scm::is_valid_c_name(const char* token)
{
	int token_length = (int)strlen(token);

	if (token_length == 0) return false;
	if ((!isalpha(token[0])) && (token[0] != '_')) return false;

	for (int i = 1; i < token_length; i++) {
		if ((!isalnum(token[i])) && (token[i] != '_')) return false;
	}

	return true;
}

bool scm::is_valid_string(const char* token)
{
	int token_length = (int)strlen(token);

	if (token_length <= 1) return false;
	if ((token[0] != '"') || (token[token_length - 1] != '"')) return false;

	return true;
}

bool scm::is_boolean(const char* token, bool* value)
{
	if (!strcmp(token, "true")) {
		*value = true;
		return true;
	}
	if (!strcmp(token, "false")) {
		*value = false;
		return true;
	}

	return false;
}

bool scm::is_boolean(const char* token)
{
	bool value;
	return is_boolean(token, &value);
}


void scm::strcpyrm(char* a, const char* b, const char sym)
{
	int i = 0;
	for (int k = 0; k < (int)strlen(b); k++) {
		if (b[k] == sym) continue;
		a[i] = b[k];
		i++;
	}
	a[i] = '\0';
}
// -------------------------------------------------------------------------------------------- //


// -------------------------------------------------------------------------------------------- //
// * Implementation *
// * scm::cfgValue * 
// -------------------------------------------------------------------------------------------- //

// -------------------------------------------------------------------------------------------- //
scm::cfgValue::cfgValue() :
	type(IS_UNDEF),
	eint(0), edouble((double)0), estring(NULL), ebool(false)
{
}

scm::cfgValue::cfgValue(const int x) :
	type(IS_INT),
	eint(x), edouble((double)0), estring(NULL), ebool(false)
{
}

scm::cfgValue::cfgValue(const float x) :
	type(IS_DOUBLE),
	eint(0), edouble((double)x), estring(NULL), ebool(false)
{
}

scm::cfgValue::cfgValue(const double x) :
	type(IS_DOUBLE),
	eint(0), edouble(x), estring(NULL), ebool(false)
{
}

scm::cfgValue::cfgValue(const long double x) :
	type(IS_DOUBLE),
	eint(0), edouble((double)x), estring(NULL), ebool(false)
{
}

scm::cfgValue::cfgValue(const char* c_str) :
	type(IS_STRING),
	eint(0), edouble((double)0), estring(NULL), ebool(false)
{
	estring = new char[strlen(c_str) + 1];
	strcpy(estring, c_str);
}

scm::cfgValue::cfgValue(const bool x) :
	type(IS_BOOLEAN),
	eint(0), edouble((double)0), estring(NULL), ebool(x)
{
}

scm::cfgValue::~cfgValue()
{
	clear();
}

scm::cfgValue::cfgValue(const cfgValue& x)
{
	type = x.type;

	if (type == IS_INT) eint = x.eint;
	else if (type == IS_DOUBLE) edouble = x.edouble;
	else if (type == IS_BOOLEAN) ebool = x.ebool;
	else if (type == IS_STRING) 
	{
		estring = new char[strlen(x.estring) + 1];
		strcpy(estring, x.estring);
	}
}
// -------------------------------------------------------------------------------------------- //

// * swap & assignment * //
// -------------------------------------------------------------------------------------------- //
const scm::cfgValue&
scm::cfgValue::operator=(cfgValue x)
{
	swap(x);
	return (*this);
}

void scm::cfgValue::swap(
	cfgValue& x)
{
	scm::swap(type, x.type);
	scm::swap(eint, x.eint);
	scm::swap(edouble, x.edouble);
	scm::swap(estring, x.estring);
	scm::swap(ebool, x.ebool);
}
// -------------------------------------------------------------------------------------------- //

// * make implicit value * //
// -------------------------------------------------------------------------------------------- //
scm::cfgValue scm::cfgValue::make_implicit(const char* value_in_string)
{
	cfgValue x;

	if (is_integer(value_in_string, &x.eint)) 
		x.type = IS_INT;
	else if (is_double(value_in_string, &x.edouble)) 
		x.type = IS_DOUBLE;
	else if (is_boolean(value_in_string, &x.ebool))
		x.type = IS_BOOLEAN;
	else if (is_valid_string(value_in_string))
	{
		x.type = IS_STRING;
		x.estring = new char[strlen(value_in_string) + 1];
		strcpyrm(x.estring, value_in_string, '"');
	}

	return x;
}
// -------------------------------------------------------------------------------------------- //

// * clear * //
// -------------------------------------------------------------------------------------------- //
void scm::cfgValue::clear()
{
	if (type == IS_STRING) {
		delete[] estring;
		estring = NULL;
	}

	type = IS_UNDEF;
}
// -------------------------------------------------------------------------------------------- //

// * get and check calls * //
// -------------------------------------------------------------------------------------------- //
bool scm::cfgValue::get(int* x) const
{
	if (type == IS_INT) {
		(*x) = eint;
		return true;
	}

	return false;
}

bool scm::cfgValue::get(float* x) const
{
	if (type == IS_DOUBLE) {
		(*x) = (float)edouble;
		return true;
	}
	if (type == IS_INT) {
		(*x) = (float)eint;
		return true;
	}

	return false;
}

bool scm::cfgValue::get(double* x) const
{
	if (type == IS_DOUBLE) {
		(*x) = edouble;
		return true;
	}
	if (type == IS_INT) {
		(*x) = (double)eint;
		return true;
	}

	return false;
}

bool scm::cfgValue::get(long double* x) const
{
	if (type == IS_DOUBLE) {
		(*x) = (long double)edouble;
		return true;
	}
	if (type == IS_INT) {
		(*x) = (long double)eint;
		return true;
	}

	return false;
}

bool scm::cfgValue::get(char** c_str) const
{
	if (type == IS_STRING) {
		(*c_str) = new char[strlen(estring) + 1];
		strcpy(*c_str, estring);
		return true;
	}

	return false;
}

bool scm::cfgValue::get(std::string& x) const
{
	if (type == IS_STRING) {
		x = std::string(estring);
		return true;
	}

	return false;
}

bool scm::cfgValue::get(bool* x) const
{
	if (type == IS_BOOLEAN) {
		(*x) = ebool;
		return true;
	}

	return false;
}

scm::cfgValue::VAR_TYPE scm::cfgValue::get_type() const 
{
	return type;
}

bool scm::cfgValue::is_defined() const
{
	return (type != IS_UNDEF);
}
// -------------------------------------------------------------------------------------------- //

// * print * //
// -------------------------------------------------------------------------------------------- //
void scm::cfgValue::print() const
{
	print(stdout);
}

void scm::cfgValue::print(FILE *ptr) const
{
	if (type == IS_INT)
		fprintf(ptr, "%i", eint);
	else if (type == IS_DOUBLE)
		fprintf(ptr, "%f", edouble);
	else if (type == IS_BOOLEAN)
		fprintf(ptr, "%s", ebool ? "true" : "false");
	else if (type == IS_STRING)
		fprintf(ptr, "%s", estring);
	else
		fprintf(ptr, "(UNDEFINED)");
}

void scm::cfgValue::print_typed() const
{
	if (type == IS_INT)
		printf("(INT) %i", eint);
	else if (type == IS_DOUBLE)
		printf("(DOUBLE) %f", edouble);
	else if (type == IS_BOOLEAN)
		printf("(BOOLEAN) %s", ebool ? "true" : "false");
	else if (type == IS_STRING)
		printf("(STRING) %s", estring);
	else 
		printf("(UNDEFINED)");
}
// -------------------------------------------------------------------------------------------- //

// * operators * //
// -------------------------------------------------------------------------------------------- //
scm::cfgValue& scm::cfgValue::operator+=(const cfgValue& x)
{
	// (int) += (int)
	// (int) += (double) + conversion to (double)
	// (double) += (double)
	// (double) += (int)
	// (string) += (string)
	if ((type == IS_INT) && (x.type == IS_INT))
		eint += x.eint;
	else if ((type == IS_INT) && (x.type == IS_DOUBLE))
	{
		edouble = (double)eint + x.edouble;
		type = IS_DOUBLE;
	}
	else if ((type == IS_DOUBLE) && (x.type == IS_DOUBLE))
		edouble += x.edouble;
	else if ((type == IS_DOUBLE) && (x.type == IS_INT))
		edouble += (double)x.eint;
	else if ((type == IS_STRING) && (x.type == IS_STRING))
	{
		const size_t length = strlen(estring) + strlen(x.estring) + 1;
		char *buf = new char[length];

		strcpy(buf, estring);
		strcat(buf, x.estring);

		delete[] estring;
		estring = buf;
	}
	else
	{
		clear();	// type:= IS_UNDEF
	}

	return (*this);
}

scm::cfgValue& scm::cfgValue::operator-=(const cfgValue& x)
{
	// (int) -= (int)
	// (int) -= (double) + conversion to (double)
	// (double) -= (double)
	// (double) -= (int)
	if ((type == IS_INT) && (x.type == IS_INT))
		eint -= x.eint;
	else if ((type == IS_INT) && (x.type == IS_DOUBLE))
	{
		edouble = (double)eint - x.edouble;
		type = IS_DOUBLE;
	}
	else if ((type == IS_DOUBLE) && (x.type == IS_DOUBLE))
		edouble -= x.edouble;
	else if ((type == IS_DOUBLE) && (x.type == IS_INT))
		edouble -= (double)x.eint;
	else
	{
		clear();	// type:= IS_UNDEF
	}

	return (*this);
}

scm::cfgValue& scm::cfgValue::operator*=(const cfgValue& x)
{
	// (int) *= (int)
	// (int) *= (double) + conversion to (double)
	// (double) *= (double)
	// (double) *= (int)
	if ((type == IS_INT) && (x.type == IS_INT))
		eint *= x.eint;
	else if ((type == IS_INT) && (x.type == IS_DOUBLE))
	{
		edouble = (double)eint * x.edouble;
		type = IS_DOUBLE;
	}
	else if ((type == IS_DOUBLE) && (x.type == IS_DOUBLE))
		edouble *= x.edouble;
	else if ((type == IS_DOUBLE) && (x.type == IS_INT))
		edouble *= (double)x.eint;
	else
	{
		clear();	// type:= IS_UNDEF
	}

	return (*this);
}

scm::cfgValue& scm::cfgValue::operator/=(const cfgValue& x)
{
	// (int) /= (int)
	// (int) /= (double) + conversion to (double)
	// (double) /= (double)
	// (double) /= (int)
	if ((type == IS_INT) && (x.type == IS_INT))
		eint /= x.eint;
	else if ((type == IS_INT) && (x.type == IS_DOUBLE))
	{
		edouble = (double)eint / x.edouble;
		type = IS_DOUBLE;
	}
	else if ((type == IS_DOUBLE) && (x.type == IS_DOUBLE))
		edouble /= x.edouble;
	else if ((type == IS_DOUBLE) && (x.type == IS_INT))
		edouble /= (double)x.eint;
	else
	{
		clear();	// type:= IS_UNDEF
	}

	return (*this);
}

scm::cfgValue& scm::cfgValue::operator%=(const cfgValue& x)
{
	// int %= (int)
	if ((type == IS_INT) && (x.type == IS_INT))
		eint %= x.eint;
	else
	{
		clear();	// type:= IS_UNDEF
	}

	return (*this);
}

scm::cfgValue& scm::cfgValue::operator^=(const cfgValue& x)
{
	// (int) ^= (int)
	// (int) ^= (double) + conversion to (double)
	// (double) ^= (double)
	// (double) ^= (int)
	if ((type == IS_INT) && (x.type == IS_INT))
		eint = ipow(eint, x.eint);
	else if ((type == IS_INT) && (x.type == IS_DOUBLE))
	{
		edouble = pow((double)eint, x.edouble);
		type = IS_DOUBLE;
	}
	else if ((type == IS_DOUBLE) && (x.type == IS_DOUBLE))
		edouble = pow(edouble, x.edouble);
	else if ((type == IS_DOUBLE) && (x.type == IS_INT))
		edouble = pow(edouble, x.eint);
	else
	{
		clear();	// type:= IS_UNDEF
	}

	return (*this);
}

// *: check if we should really use const on return (all operators) ->
const scm::cfgValue 
scm::cfgValue::operator+(const cfgValue& x) const
{
	return cfgValue(*this) += x;
}

const scm::cfgValue
scm::cfgValue::operator-(const cfgValue& x) const
{
	return cfgValue(*this) -= x;
}

const scm::cfgValue
scm::cfgValue::operator*(const cfgValue& x) const
{
	return cfgValue(*this) *= x;
}

const scm::cfgValue
scm::cfgValue::operator/(const cfgValue& x) const
{
	return cfgValue(*this) /= x;
}

const scm::cfgValue
scm::cfgValue::operator%(const cfgValue& x) const
{
	return cfgValue(*this) %= x;
}

const scm::cfgValue
scm::cfgValue::operator^(const cfgValue& x) const
{
	return cfgValue(*this) ^= x;
}

const scm::cfgValue
scm::cfgValue::operator==(const cfgValue& x) const
{
	cfgValue res;

	if (type == IS_INT) 
	{
		if (x.type == IS_INT) 
		{
			res.type = IS_BOOLEAN;
			res.ebool = (eint == x.eint);
		}
		else if (x.type == IS_DOUBLE) 
		{
			res.type = IS_BOOLEAN;
			res.ebool = (eint == x.edouble);
		}
		else if (x.type == IS_BOOLEAN) 
		{
			res.type = IS_BOOLEAN;
			res.ebool = (eint == (int)x.ebool);
		}
	}
	else if (type == IS_DOUBLE) 
	{
		if (x.type == IS_INT)
		{
			res.type = IS_BOOLEAN;
			res.ebool = (edouble == x.eint);
		}
		else if (x.type == IS_DOUBLE)
		{
			res.type = IS_BOOLEAN;
			res.ebool = (edouble == x.edouble);
		}
		else if (x.type == IS_BOOLEAN)
		{
			res.type = IS_BOOLEAN;
			res.ebool = (edouble == (int)x.ebool);
		}
	}
	else if (type == IS_BOOLEAN)
	{
		if (x.type == IS_INT)
		{
			res.type = IS_BOOLEAN;
			res.ebool = ((int)ebool == x.eint);
		}
		else if (x.type == IS_DOUBLE)
		{
			res.type = IS_BOOLEAN;
			res.ebool = ((int)ebool == x.edouble);
		}
		else if (x.type == IS_BOOLEAN)
		{
			res.type = IS_BOOLEAN;
			res.ebool = (ebool == x.ebool);
		}
	}
	else if (type == IS_STRING)
	{
		if (x.type == IS_STRING)
		{
			res.type = IS_BOOLEAN;
			res.ebool = (!strcmp(estring, x.estring));
		}
	}

	return res;
}

const scm::cfgValue
scm::cfgValue::operator!=(const cfgValue& x) const
{
	cfgValue res = ((*this) == x);
	if (res.type == IS_BOOLEAN) res.ebool = (!res.ebool);
	
	return res;
}

const scm::cfgValue
scm::cfgValue::operator<(const cfgValue& x) const
{
	cfgValue res;

	if (type == IS_INT)
	{
		if (x.type == IS_INT)
		{
			res.type = IS_BOOLEAN;
			res.ebool = (eint < x.eint);
		}
		else if (x.type == IS_DOUBLE)
		{
			res.type = IS_BOOLEAN;
			res.ebool = (eint < x.edouble);
		}
		else if (x.type == IS_BOOLEAN)
		{
			res.type = IS_BOOLEAN;
			res.ebool = (eint < (int)x.ebool);
		}
	}
	else if (type == IS_DOUBLE)
	{
		if (x.type == IS_INT)
		{
			res.type = IS_BOOLEAN;
			res.ebool = (edouble < x.eint);
		}
		else if (x.type == IS_DOUBLE)
		{
			res.type = IS_BOOLEAN;
			res.ebool = (edouble < x.edouble);
		}
		else if (x.type == IS_BOOLEAN)
		{
			res.type = IS_BOOLEAN;
			res.ebool = (edouble < (int)x.ebool);
		}
	}
	else if (type == IS_BOOLEAN)
	{
		if (x.type == IS_INT)
		{
			res.type = IS_BOOLEAN;
			res.ebool = ((int)ebool < x.eint);
		}
		else if (x.type == IS_DOUBLE)
		{
			res.type = IS_BOOLEAN;
			res.ebool = ((int)ebool < x.edouble);
		}
		else if (x.type == IS_BOOLEAN)
		{
			res.type = IS_BOOLEAN;
			res.ebool = (ebool < x.ebool);
		}
	}

	return res;
}

const scm::cfgValue
scm::cfgValue::operator>(const cfgValue& x) const
{
	cfgValue res;

	if (type == IS_INT)
	{
		if (x.type == IS_INT)
		{
			res.type = IS_BOOLEAN;
			res.ebool = (eint > x.eint);
		}
		else if (x.type == IS_DOUBLE)
		{
			res.type = IS_BOOLEAN;
			res.ebool = (eint > x.edouble);
		}
		else if (x.type == IS_BOOLEAN)
		{
			res.type = IS_BOOLEAN;
			res.ebool = (eint > (int)x.ebool);
		}
	}
	else if (type == IS_DOUBLE)
	{
		if (x.type == IS_INT)
		{
			res.type = IS_BOOLEAN;
			res.ebool = (edouble > x.eint);
		}
		else if (x.type == IS_DOUBLE)
		{
			res.type = IS_BOOLEAN;
			res.ebool = (edouble > x.edouble);
		}
		else if (x.type == IS_BOOLEAN)
		{
			res.type = IS_BOOLEAN;
			res.ebool = (edouble > (int)x.ebool);
		}
	}
	else if (type == IS_BOOLEAN)
	{
		if (x.type == IS_INT)
		{
			res.type = IS_BOOLEAN;
			res.ebool = ((int)ebool > x.eint);
		}
		else if (x.type == IS_DOUBLE)
		{
			res.type = IS_BOOLEAN;
			res.ebool = ((int)ebool > x.edouble);
		}
		else if (x.type == IS_BOOLEAN)
		{
			res.type = IS_BOOLEAN;
			res.ebool = (ebool > x.ebool);
		}
	}

	return res;
}

const scm::cfgValue
scm::cfgValue::operator<=(const cfgValue& x) const
{
	cfgValue res = ((*this) > x);
	if (res.type == IS_BOOLEAN) res.ebool = (!res.ebool);

	return res;
}

const scm::cfgValue
scm::cfgValue::operator>=(const cfgValue& x) const
{
	cfgValue res = ((*this) < x);
	if (res.type == IS_BOOLEAN) res.ebool = (!res.ebool);

	return res;
}

const scm::cfgValue
scm::cfgValue::operator-() const
{
	// -(int)
	// -(double)
	cfgValue x;	// default: type:= IS_UNDEF

	if (type == IS_INT) {
		x = (*this);
		x.eint = -x.eint;
	}
	else if (type == IS_DOUBLE) {
		x = (*this);
		x.edouble = -x.edouble;
	}

	return x;
}

const scm::cfgValue
scm::cfgValue::operator+() const
{
	// +(int)
	// +(double)
	cfgValue x;	// default: type:= IS_UNDEF

	if (type == IS_INT) x = (*this);
	else if (type == IS_DOUBLE) x = (*this);

	return x;
}

const scm::cfgValue
scm::cfgValue::logical_and(const cfgValue& x) const
{
	cfgValue res;

	if ((type == IS_BOOLEAN) && (x.type == IS_BOOLEAN))
	{
		res.type = IS_BOOLEAN;
		res.ebool = (ebool && x.ebool);
	}

	return res;
}

const scm::cfgValue
scm::cfgValue::logical_or(const cfgValue& x) const
{
	cfgValue res;

	if ((type == IS_BOOLEAN) && (x.type == IS_BOOLEAN))
	{
		res.type = IS_BOOLEAN;
		res.ebool = (ebool || x.ebool);
	}

	return res;
}

// <-
//
// -------------------------------------------------------------------------------------------- //

// * functions * // 
// -------------------------------------------------------------------------------------------- //
const scm::cfgValue 
scm::cfgValue::cfg_sin(const cfgValue& x)
{
	// sin(int)
	// sin(double)
	cfgValue y;		// default: type:=IS_UNDEF

	if (x.type == IS_DOUBLE) {
		y.edouble = sin(x.edouble);
		y.type = IS_DOUBLE;
	}
	else if (x.type == IS_INT) {
		y.edouble = sin((double)x.eint);
		y.type = IS_DOUBLE;
	}

	return y;
}

const scm::cfgValue 
scm::cfgValue::cfg_cos(const cfgValue& x)
{
	// cos(int)
	// cos(double)
	cfgValue y;		// default: type:=IS_UNDEF

	if (x.type == IS_DOUBLE) {
		y.edouble = cos(x.edouble);
		y.type = IS_DOUBLE;
	}
	else if (x.type == IS_INT) {
		y.edouble = cos((double)x.eint);
		y.type = IS_DOUBLE;
	}

	return y;
}

const scm::cfgValue 
scm::cfgValue::cfg_tan(const cfgValue& x)
{
	// tan(int)
	// tan(double)
	cfgValue y;		// default: type:=IS_UNDEF

	if (x.type == IS_DOUBLE) {
		y.edouble = tan(x.edouble);
		y.type = IS_DOUBLE;
	}
	else if (x.type == IS_INT) {
		y.edouble = tan((double)x.eint);
		y.type = IS_DOUBLE;
	}

	return y;
}

const scm::cfgValue 
scm::cfgValue::cfg_log(const cfgValue& x)
{
	// log(int)
	// log(double)
	cfgValue y;		// default: type:=IS_UNDEF

	if (x.type == IS_DOUBLE) {
		y.edouble = log(x.edouble);
		y.type = IS_DOUBLE;
	}
	else if (x.type == IS_INT) {
		y.edouble = log((double)x.eint);
		y.type = IS_DOUBLE;
	}

	return y;
}

const scm::cfgValue 
scm::cfgValue::cfg_sqrt(const cfgValue& x)
{
	// sqrt(int)
	// sqrt(double)
	cfgValue y;		// default: type:=IS_UNDEF

	if (x.type == IS_DOUBLE) {
		y.edouble = sqrt(x.edouble);
		y.type = IS_DOUBLE;
	}
	else if (x.type == IS_INT) {
		y.edouble = sqrt((double)x.eint);
		y.type = IS_DOUBLE;
	}

	return y;
}

const scm::cfgValue 
scm::cfgValue::cfg_abs(const cfgValue& x)
{
	// sqrt(int)
	// sqrt(double)

	cfgValue y;		// default: type:=IS_UNDEF

	if (x.type == IS_DOUBLE) {
		y.edouble = (x.edouble < (double)0) ?
			-x.edouble : x.edouble;
		y.type = IS_DOUBLE;
	}
	else if (x.type == IS_INT) {
		y.eint = (x.eint < 0) ?
			-x.eint : x.eint;
		y.type = IS_INT;
	}

	return y;
}

const scm::cfgValue 
scm::cfgValue::cfg_to_string(const cfgValue& x)
{
	// string(int)
	// string(double)
	// string(string)
	// string(boolean)
	cfgValue y;		// default: type:=IS_UNDEF

	if (x.type == IS_INT)
	{
		y.type = IS_STRING;
		std::string val_string = convert_to_string(x.eint);
		y.estring = new char[strlen(val_string.c_str()) + 1];
		strcpy(y.estring, val_string.c_str());
	}
	else if (x.type == IS_DOUBLE)
	{
		y.type = IS_STRING;
		std::string val_string = convert_to_string(x.edouble);
		y.estring = new char[strlen(val_string.c_str()) + 1];
		strcpy(y.estring, val_string.c_str());
	}
	else if (x.type == IS_BOOLEAN)
	{
		y.type = IS_STRING;
		std::string val_string;
		val_string = (x.ebool) ? "true" : "false";
		y.estring = new char[strlen(val_string.c_str()) + 1];
		strcpy(y.estring, val_string.c_str());
	}
	else if (x.type == IS_STRING) y = x;

	return y;
}

const scm::cfgValue 
scm::cfgValue::cfg_min(const cfgValue& a, const cfgValue& b)
{
	// min(int, int)
	// min(double, double)
	// min(int, double)
	// min(double, int)
	cfgValue _min;		// default: type:=IS_UNDEF

	if ((a.type == IS_DOUBLE) && (b.type == IS_DOUBLE))
		_min = (a.edouble < b.edouble) ? a : b;
	else if ((a.type == IS_DOUBLE) && (b.type == IS_INT)) 
	{
		_min.edouble = (a.edouble < (double)b.eint) ?
			a.edouble : (double)b.eint;
		_min.type = IS_DOUBLE;
	}
	else if ((a.type == IS_INT) && (b.type == IS_DOUBLE)) 
	{
		_min.edouble = ((double)a.eint < b.edouble) ?
			(double)a.eint : b.edouble;
		_min.type = IS_DOUBLE;
	}
	else if ((a.type == IS_INT) && (b.type == IS_INT)) 
		_min = (a.eint < b.eint) ? a : b;

	return _min;
}

const scm::cfgValue 
scm::cfgValue::cfg_max(const cfgValue& a, const cfgValue& b)
{
	// max(int, int)
	// max(double, double)
	// max(int, double)
	// max(double, int)
	cfgValue _max;		// default: type:=IS_UNDEF

	if ((a.type == IS_DOUBLE) && (b.type == IS_DOUBLE))
		_max = (a.edouble > b.edouble) ? a : b;
	else if ((a.type == IS_DOUBLE) && (b.type == IS_INT))
	{
		_max.edouble = (a.edouble > (double)b.eint) ?
			a.edouble : (double)b.eint;
		_max.type = IS_DOUBLE;
	}
	else if ((a.type == IS_INT) && (b.type == IS_DOUBLE))
	{
		_max.edouble = ((double)a.eint > b.edouble) ?
			(double)a.eint : b.edouble;
		_max.type = IS_DOUBLE;
	}
	else if ((a.type == IS_INT) && (b.type == IS_INT))
		_max = (a.eint > b.eint) ? a : b;

	return _max;
}
// -------------------------------------------------------------------------------------------- //