#ifndef __VARIABLE_AMV
	#define __VARIABLE_AMV

#include <iostream>
#include <typeinfo>
#include "stringAMV.h"
#include "exception.h"
#include "REEvaluator.h"
#include "amvdefs.h"

namespace amv	{

template <class type>
class variable	{
	string name;
	bool defined;
	type value;
	static REEvaluator REEvariable;
	public:
		class invalid_name: public exception	{
			public:
				invalid_name(const char *sourceMessage="Nombre inválido"):
				exception(sourceMessage)
					{
					}

		};

		variable(const string &sourceName);
		variable(const string &sourceName, const type &t);
		variable &operator=(const variable &v);
		variable &operator=(const type &t);
		bool operator==(const variable &v);
		bool operator<(const variable &v);
		string &getName();
		const string &getName() const;
		void setName(const string &s);
		bool isDefined() const;
		void undef();
		type &getValue();
		const type &getValue() const;
		void setValue(const type &t);
		const type_info &getTypeInfo() const
			{
			return typeid(type);
			}
		const char *getTypeName() const
			{
			return (typeid(type)).name();
			}
		friend ostream &operator<<(ostream &os, const variable<type> &v);
		friend istream &operator>>(istream &is, variable<type> &v);

};

template <class type>
REEvaluator variable<type>::REEvariable="([a-z]|[A-Z])+<([0-9])*";

template <class type>
inline variable<type>::variable(const string &sourceName):
name(), defined(false), value()
{
string s;
string::const_iterator it(sourceName.begin());
if(!REEvariable.getLexema(it,sourceName.end(),s))
	throw invalid_name();
name=s;
}

template <class type>
inline variable<type>::variable(const string &sourceName, const type &t):
name(), defined(true), value(t)
{
string s;
string::const_iterator it(sourceName.begin());
if(!REEvariable.getLexema(it,sourceName.end(),s))
	throw invalid_name();
name=s;
}

template <class type>
inline variable<type> &variable<type>::operator=(const variable &v)
{
defined=v.defined;
if(defined)
	value=v.value;
}

template <class type>
inline variable<type> &variable<type>::operator=(const type &t)
{
defined=true;
value=t;
	return *this;
}

template <class type>
inline bool variable<type>::operator==(const variable &v)
{
return name==v.name;
}

template <class type>
inline bool variable<type>::operator<(const variable &v)
{
return name<v.name;
}

template <class type>
inline string &variable<type>::getName()
{
return name;
}

template <class type>
inline const string &variable<type>::getName() const
{
return name;
}

template <class type>
inline void variable<type>::setName(const string &s)
{
string s1;
string::const_iterator it(s.begin());
if(!REEvariable.getLexema(it,s.end(),s1))
	throw invalid_name();

name=s1;
}

template <class type>
inline bool variable<type>::isDefined() const
{
return defined;
}

template <class type>
inline void variable<type>::undef()
{
defined=false;
}

template <class type>
inline type &variable<type>::getValue()
{
return value;
}

template <class type>
inline const type &variable<type>::getValue() const
{
return value;
}

template <class type>
inline void variable<type>::setValue(const type &t)
{
defined=true;
value=t;
}

template <class type>
inline ostream &operator<<(ostream &os, const variable<type> &v)
{
if(v.defined)
	os<<v.value;
else
	os<<v.name;

return os;
}

template <class type>
inline istream &operator>>(istream &is, variable<type> &v)
{
if(is>>v.value)
	v.defined=true;

return is;
}

}

#endif