#ifndef _VARINST_H_
#define _VARINST_H_

#include <string>
#include <list>
#include <iostream>

#include "../tobject.h"
#include "../ptr.h"

class VarDef;
class IModule;

class VarInst;

using namespace std;

class VarInstListener:public TObject
{
public:
	static const char* type;
	const char* getType() const;
	
	/**
	 * Called whenever a variable is changed 
	 *
	 * \param variable pointer to changing variable
	 */
	virtual void valueUpdated(VarInst* variable)=0;
};


/**
 * \brief Represent variable instance.
 * 
 * \date 01-29-2006
 *
 * \author Ondrej Svejdar
 *
 * \todo 
 *
 * \bug 
 *
 */
class VarInst:public TObject
{
	const VarDef* definition;
	IModule* module;
	bool notifyOn;
	typedef list<Ptr<VarInstListener> > t_listeners;
	t_listeners listeners;
protected:
	virtual ostream& print(ostream& o) const=0;
	void notify();
public:

	void addValueListener(VarInstListener* listener)
	{
		Ptr<VarInstListener> myListener(listener);
		listeners.push_back(myListener);
	}

	/**
	 * \return true if modular system receives notifications
	 */
	inline bool isNotificationOn() const
	{
		return notifyOn;
	}

	/**
	 * \brief enables or disables notification about variable changes to modular system
	 * \param value value
	 */
	inline void setNotification(bool value)
	{
		notifyOn=value;
	}

	/**
	 * \brief initialize variable value from string
	 * \param value string
	 * \return true if there was no conversion error
	 */
	virtual bool fromString(const char* value)=0;


	/**
	 * \return variable definition
	 */
	inline const VarDef* getVarDef() const
	{
		return definition;
	}


	/**
	 * \brief ctor
	 * \param definition variable definition
	 * \param module module instance
	 */
	inline VarInst(const VarDef* definition,IModule* module):definition(definition),module(module),notifyOn(true) {}
	
	
	/**
	 * \brief convert variable value to string
	 * \return string
	 */
	const string& toString() const=0;
	
	friend ostream& operator<<(ostream& o,const VarInst& inst)
	{
		return inst.print(o);
	}
};

/// Variable instance of type "bool"
class VarBool:public VarInst
{
	bool value;
public:
	static const char* type;
	const char* getType() const;

	static const char* TRUE_VALUE;
	static const char* FALSE_VALUE;

	inline bool get() const
	{
		return value;
	}

	inline void set(bool value)
	{
		this->value=value;
		notify();
	}

	inline VarBool(const VarDef* definition,IModule* module):VarInst(definition,module) {}
	bool fromString(const char* value)
	{
		if (strcmp(value,"true")==0)
		{
			this->value=true;
			notify();
			return true;
		}
		if (strcmp(value,"false")==0)
		{
			this->value=false;
			notify();
			return true;
		}
		return false;
	}
	const string& toString() const;
protected:
	ostream& print(ostream& o) const
	{
		o<<(value?"true":"false");
		return o;
	}
};

/// Variable instance of type "char"
class VarChar:public VarInst
{
	char value;
public:
	static const char* type;
	const char* getType() const;

	inline char get() const
	{
		return value;
	}

	inline void set(char value)
	{
		this->value=value;
		notify();
	}

	inline VarChar(const VarDef* definition,IModule* module):VarInst(definition,module) {}
	bool fromString(const char* value)
	{
		if (value[1]!='\0') return false;
		this->value=value[0];
		notify();
		return true;
	}
	const string& toString() const;
protected:
	ostream& print(ostream& o) const
	{
		o<<value;
		return o;
	}
};

/// Variable instance of type "int"
class VarInteger:public VarInst
{
	int value;
public:
	static const char* type;
	const char* getType() const;

	inline int get() const
	{
		return value;
	}

	inline void set(int value)
	{
		this->value=value;
		notify();
	}

	inline VarInteger(const VarDef* definition,IModule* module):VarInst(definition,module) {}
	bool fromString(const char* value)
	{
		this->value=atoi(value);
		notify();

		return true;
	}
	const string& toString() const;
protected:
	ostream& print(ostream& o) const
	{
		o<<value;
		return o;
	}
};

/// Variable instance of type "double"
class VarDouble:public VarInst
{
	double value;
public:
	static const char* type;
	const char* getType() const;

	inline double get() const
	{
		return value;
	}

	inline void set(double value)
	{
		this->value=value;
		notify();
	}

	inline VarDouble(const VarDef* definition,IModule* module):VarInst(definition,module) {}
	bool fromString(const char* value)
	{
		this->value=atof(value);
		notify();

		return true;
	}
	const string& toString() const;
protected:
	ostream& print(ostream& o) const
	{
		o<<value;
		return o;
	}
};

/// Variable instance of type "string"
class VarString:public VarInst
{
	string value;
public:
	static const char* type;
	const char* getType() const;

	inline const string& get() const
	{
		return value;
	}

	inline void set(const string& value)
	{
		this->value=value;
		notify();
	}

	inline VarString(const VarDef* definition,IModule* module):VarInst(definition,module) {}
	bool fromString(const char* value)
	{
		this->value=value;
		notify();

		return true;
	}
	const string& toString() const;
protected:
	ostream& print(ostream& o) const
	{
		o<<value;
		return o;
	}
};

extern double toDouble(const VarInst* varInst);
extern int toInt(const VarInst* varInst);
extern char toChar(const VarInst* varInst);
extern const char* toString(const VarInst* varInst);
extern bool toBool(const VarInst* varInst);

#endif/*_VARINST_H_*/
