/* -----------------------------------------------------------------------------
	GSFramework
	Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
------------------------------------------------------------------------------*/


		#include <cstring>
		#include "data/nvariant.h"
		#include "alloc/ialloc.h"

		using namespace GS;


//------------------------------------------------------------------------------
void				Variant::Reset()
{
	type = VariantNone;
}
void				Variant::Free()
{
	switch (type)
	{
		case VariantString:
			s_value.Clear();
			break;

		case VariantBinary:
			_safe_delete_array(d_value);
			d_size = 0;
			break;

		default:
		    break;
	}
	type = VariantNone;
}
Variant::~Variant()
{	Free();	}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
Variant				&Variant::operator = (const Variant &v)
{
	switch (v.GetType())
	{
		case VariantBool:		*this = v.b_value;	break;
		case VariantInteger:	*this = v.i_value;	break;
		case VariantFloat:		*this = v.f_value;	break;
		case VariantString:		*this = v.s_value;	break;
		case VariantBinary:
		{
			Free();
			void *v_data; size_t v_size;
			if	(v.GetBinary(v_data, v_size))
				SetBinary(v_data, v_size);
		}
		break;

		default:
			Free();
			break;
	}
	return *this;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
bool				Variant::operator < (const Variant &b) const
{
	switch (GetType())
	{
		case VariantBool:
			if	(b.GetType() == VariantBool)
				return b_value < b.b_value;
			break;

		case VariantInteger:
			switch (b.GetType())
			{
				case VariantInteger:	return i_value < b.i_value;
				case VariantFloat:		return i_value < (int)b.f_value;

				default: break;
			}
			break;

		case VariantFloat:
			switch (b.GetType())
			{
				case VariantInteger:	return f_value < (float)b.i_value;
				case VariantFloat:		return f_value < b.f_value;

				default: break;
			}
			break;

		default: break;
	}
	return false;
}
bool				Variant::operator > (const Variant &b) const
{	return !(*this < b);	}
bool				Variant::operator == (const Variant &b) const
{
	switch (GetType())
	{
		case VariantBool:
			if	(b.GetType() == VariantBool)
				return b_value == b.b_value;
			break;

		case VariantInteger:
			switch (b.GetType())
			{
				case VariantInteger:	return i_value == b.i_value;
				case VariantFloat:		return i_value == (int)b.f_value;

				default: break;
			}
			break;

		case VariantFloat:
			switch (b.GetType())
			{
				case VariantInteger:	return f_value == (float)b.i_value;
				case VariantFloat:		return f_value == b.f_value;

				default: break;
			}
			break;

		case VariantString:
			if	(b.GetType() == VariantString)
				return s_value == b.s_value;
			break;

		default: break;
	}
	return false;
}
bool				Variant::operator != (const Variant &b) const
{	return !(*this == b);	}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
Variant				&Variant::operator = (const char *v)
{
	Free();
	s_value.Set(v);
	type = VariantString;
	return *this;
}
bool				Variant::Get(const char * &v) const
{
	if	(type != VariantString)
		return false;
	v = s_value.c_str();
	return true;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
Variant				&Variant::operator = (int v)
{
	Free();
	type = VariantInteger;
	i_value = v;
	return *this;
}
bool				Variant::Get(int &v) const
{
	switch (type)
	{
		case VariantBool:		v = b_value ? 1 : 0;	return true;
		case VariantInteger:	v = i_value;			return true;
		case VariantFloat:		v = (int)f_value;		return true;

		default: break;
	}
	return false;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
Variant				&Variant::operator = (uint v)
{
	Free();
	type = VariantInteger;
	u_value = v;
	return *this;
}
bool				Variant::Get(uint &v) const
{
	switch (type)
	{
		case VariantBool:		v = b_value ? 1 : 0;	return true;
		case VariantInteger:	v = u_value;			return true;
		case VariantFloat:		v = (int)f_value;		return true;

		default: break;
	}
	return false;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
Variant				&Variant::operator = (bool v)
{
	Free();
	type = VariantBool;
	b_value = v;
	return *this;
}
bool				Variant::Get(bool &v) const
{
	switch (type)
	{
		case VariantBool:		v = b_value;			return true;
		case VariantInteger:	v = asbool(i_value);	return true;
		case VariantFloat:		v = asbool(f_value);	return true;

		default: break;
	}
	return false;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
Variant				&Variant::operator = (float v)
{
	Free();
	type = VariantFloat;
	f_value = v;
	return *this;
}
bool				Variant::Get(float &v) const
{
	switch (type)
	{
		case VariantBool:		v = b_value ? 1.f : 0.f;	return true;
		case VariantInteger:	v = (float)i_value;			return true;
		case VariantFloat:		v = f_value;				return true;

		default: break;
	}
	return false;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
bool				Variant::SetBinary(const void *v, size_t size)
{
	Free();

	d_value = new char[size];
	if	(d_value)
	{
		memcpy(d_value, v, size);
		d_size = size;
		type = VariantBinary;
	}
	return true;
}
bool				Variant::GetBinary(void *&data, size_t &size) const
{
	if	(type != VariantBinary)
		return false;

	data = (void *)new char[d_size];
	if	(data == NULL)
	{
		size = 0;
		return false;
	}

	memcpy(data, d_value, d_size);
	size = d_size;
	return true;
}
//------------------------------------------------------------------------------
