#ifndef __VALUE_H__
#define __VALUE_H__

#include "Common.h"
#include "File.h"

namespace AScript {

class Expr;
class ObjectBase;
class Module;
class Class;
class Object;
class Object_File;
class Object_String;
class Environment;
class Function;

class ValueList;
class ValueDict;

//-----------------------------------------------------------------------------
// Value
//-----------------------------------------------------------------------------
class ValueVisitor {
public:
	virtual void Visit(Signal sig, const Value &value) = 0;
};

class Value {
public:
	struct KeyCompare {
		inline bool operator()(const Value &value1, const Value &value2) const {
			return Compare(value1, value2) < 0;
		}
	};
private:
	char _valType;
	char _ownFlag;
	union {
		Number num;				// VTYPE_Number
		bool flag;				// VTYPE_Boolean
		const Symbol *pSymbol;	// VTYPE_Symbol
		Complex *pComp;			// VTYPE_Complex
		Module *pModule;		// VTYPE_Module
		Class *pClass;			// VTYPE_Class
		Object *pObj;			// VTYPE_Object,Function,String,List,Dict,
								// VTYPE_File,FileStat,DateTime,Expr
								// VTYPE_Environment,Error
	} _u;
private:
	static const Complex _compZero;
public:
	static const Value Null;
public:
	inline Value() : _valType(static_cast<char>(VTYPE_Invalid)), _ownFlag(true) {
		DBG(::_tprintf(_T("%p Value()\n"), this));
	}
	inline Value(Number num) : _valType(static_cast<char>(VTYPE_Number)), _ownFlag(true) {
		_u.num = num;
		DBG(::_tprintf(_T("%p Value(Number)\n"), this));
	}
	inline Value(bool flag) : _valType(static_cast<char>(VTYPE_Boolean)), _ownFlag(true) {
		_u.flag = flag;
		DBG(::_tprintf(_T("%p Value(bool)\n"), this));
	}
	inline Value(const Symbol *pSymbol) : _valType(static_cast<char>(VTYPE_Symbol)), _ownFlag(true) {
		_u.pSymbol = pSymbol;
		DBG(::_tprintf(_T("%p Value(Symbol)\n"), this));
	}
	Value(Environment &env, const TCHAR *str);
	Value(Environment &env, const TCHAR *str, size_t len);
	Value(Object *pObj, ValueType valType, bool ownFlag = true);
	inline Value(const Complex &comp) : _valType(static_cast<char>(VTYPE_Complex)), _ownFlag(true) {
		_u.pComp = DupComplex(comp);
		DBG(::_tprintf(_T("%p Value(Complex)\n"), this));
	}
	Value(const Value &value);
	~Value();
	Value &operator=(const Value &value);
	const TCHAR *GetTypeName() const;
	bool IsObject() const;
	inline ValueType GetType() const { return static_cast<ValueType>(_valType); }
	inline bool IsType(ValueType valType) const {
		return _valType == static_cast<char>(valType);
	}
	inline bool IsInvalid() const			{ return IsType(VTYPE_Invalid);		}
	inline bool IsValid() const				{ return !IsType(VTYPE_Invalid);	}
	inline bool IsNumber() const			{ return IsType(VTYPE_Number);		}
	inline bool IsBoolean() const			{ return IsType(VTYPE_Boolean);		}
	inline bool IsSymbol() const			{ return IsType(VTYPE_Symbol);		}
	inline bool IsString() const			{ return IsType(VTYPE_String);		}
	inline bool IsComplex() const			{ return IsType(VTYPE_Complex);		}
	inline bool IsModule() const			{ return IsType(VTYPE_Module);		}
	inline bool IsClass() const				{ return IsType(VTYPE_Class);		}
	inline bool IsGenericObject() const		{ return IsType(VTYPE_Object);		}
	inline bool IsFunction() const			{ return IsType(VTYPE_Function);	}
	inline bool IsList() const				{ return IsType(VTYPE_List);		}
	inline bool IsDict() const				{ return IsType(VTYPE_Dict);		}
	inline bool IsFile() const				{ return IsType(VTYPE_File);		}
	inline bool IsFileStat() const			{ return IsType(VTYPE_FileStat);	}
	inline bool IsDateTime() const			{ return IsType(VTYPE_DateTime);	}
	inline bool IsExpr() const				{ return IsType(VTYPE_Expr);		}
	inline bool IsEnvironment() const		{ return IsType(VTYPE_Environment);	}
	inline bool IsError() const				{ return IsType(VTYPE_Error);		}
	inline bool IsExprOrSymbol() const		{ return IsExpr() || IsSymbol();	}
	inline bool IsNumberOrComplex() const	{ return IsNumber() || IsComplex(); }
	inline void SetNumber(Number num) {
		FreeResource(); _valType = static_cast<char>(VTYPE_Number), _u.num = num;
	}
	inline void SetBoolean(bool flag) {
		FreeResource(); _valType = static_cast<char>(VTYPE_Boolean), _u.flag = flag;
	}
	inline void SetSymbol(const Symbol *pSymbol) {
		FreeResource(); _valType = static_cast<char>(VTYPE_Symbol), _u.pSymbol = pSymbol;
	}
	inline void SetComplex(const Complex &comp) {
		FreeResource();
		if (comp.imag() == 0.) {
			 _valType = static_cast<char>(VTYPE_Number), _u.num = comp.real();
		} else {
			 _valType = static_cast<char>(VTYPE_Complex), _u.pComp = DupComplex(comp);
		}
	}
	inline Number GetNumber() const {
		return IsNumber()? _u.num :
				IsBoolean()? (_u.flag? 1. : 0.) :
				IsString()? ::_tcstod(GetString(), NULL) : 0.;
	}
	inline long GetLong() const { return static_cast<long>(GetNumber()); }
	inline long GetULong() const { return static_cast<unsigned long>(GetNumber()); }
	inline bool GetBoolean() const {
		return IsBoolean()? _u.flag : IsValid();
	}
	inline const Symbol *GetSymbol() const {
		return IsSymbol()? _u.pSymbol : NULL;
	}
	const TCHAR *GetString() const;
	const DateTime &GetDateTime() const;
	ErrorType GetErrorType() const;
	Object_String *GetStringObj();
	const Object_String *GetStringObj() const;
	inline Complex GetComplex() const {
		return IsComplex()? *_u.pComp :
				IsNumber()? Complex(GetNumber()) : _compZero;
	}
	bool IsFlatList() const;
	ObjectBase *ExtractObject(Signal sig);
	ValueList &GetList();
	const ValueList &GetList() const;
	ValueDict &GetDict();
	const ValueDict &GetDict() const;
	File &GetFile();
	const Expr *GetExpr() const;
	Expr *CloneExpr() const;
	Function *GetFunction();
	inline const Function *GetFunction() const {
		return const_cast<Function *>(const_cast<Value *>(this)->GetFunction());
	}
	inline Module *GetModule() { return IsModule()? _u.pModule : NULL; }
	inline const Module *GetModule() const { return IsModule()? _u.pModule : NULL; }
	inline Class *GetClass() { return IsClass()? _u.pClass : NULL; }
	inline Object *GetObject() { return IsObject()? _u.pObj : NULL; }
	inline const Object *GetObject() const { return IsObject()? _u.pObj : NULL; }
	String ToString(Signal sig, bool exprFlag = true) const;
	Number ToNumber(bool allowPartFlag, bool &successFlag) const;
	void Accept(Signal sig, ValueVisitor &visitor) const;
	void InitAsModule(Module *pModule);
	void InitAsClass(Class *pClass);
	void InitAsObject(Object *pObj, ValueType valType, bool ownFlag = true);
	Object *InitAsObject(Environment &envOuter);
	ValueList &InitAsList(Environment &envOuter);
	ValueList &InitAsList(Environment &envOuter, size_t n, const Value &value);
	ValueDict &InitAsDict(Environment &envOuter);
	Object_File *InitAsFile(Environment &envOuter);
	void InitAsExpr(Environment &envOuter, Expr *pExpr);
	void InitAsFunction(Environment &envOuter, Function *pFunc);
	void InitAsEnvironment(Environment &env);
public:
	static int Compare(const Value &value1, const Value &value2);
private:
	static Complex *DupComplex(const Complex &comp);
	void FreeResource();
};

//-----------------------------------------------------------------------------
// ValueList
//-----------------------------------------------------------------------------
class ValueList : public std::vector<Value> {
public:
	static const ValueList Null;
public:
	inline ValueList() {}
	inline ValueList(size_t n) : std::vector<Value>(n) {}
	inline ValueList(size_t n, const Value &value) : std::vector<Value>(n, value) {}
	inline ValueList(const Value &value) : std::vector<Value>(1) {
		(*this)[0] = value;
	}
	inline ValueList(const Value &value1, const Value &value2) : std::vector<Value>(2) {
		(*this)[0] = value1, (*this)[1] = value2;
	}
	inline ValueList(const Value &value1, const Value &value2, const Value &value3) :
															std::vector<Value>(3) {
		(*this)[0] = value1, (*this)[1] = value2, (*this)[2] = value3;
	}
	bool IsTypeMixed() const;
	bool IsFlat() const;
	bool IsContain(const Value &value) const;
	bool CheckMatrix(int *pnRow, int *pnCol) const;
	void Print(Signal sig, int indentLevel = 0) const;
	static bool AssumeSameLength(Signal sig,
					const ValueList &valList1, const ValueList &valList2);
};

//-----------------------------------------------------------------------------
// ValueMap
//-----------------------------------------------------------------------------
class ValueMap : public std::map<const Symbol *, Value, Symbol::KeyCompare_UniqNumber> {
public:
	static const ValueMap Null;
public:
	inline bool IsSet(const Symbol *pSymbol) const {
		return find(pSymbol) != const_cast<ValueMap *>(this)->end();
	}
	inline void Insert(const Symbol *pSymbol) {
		insert(value_type(pSymbol, Value::Null));
	}
	inline void Insert(const Symbol *pSymbol, const Value &value) {
		insert(value_type(pSymbol, value));
	}
};

//-----------------------------------------------------------------------------
// ValueDict
//-----------------------------------------------------------------------------
class ValueDict : public std::map<Value, Value, Value::KeyCompare> {
public:
	static const ValueDict Null;
public:
	bool Store(Signal sig, const ValueList &valList);
	bool Store(Signal sig, const Value &valueIdx, const Value &value);
	inline static bool IsValidKey(const Value &value) {
		return value.IsNumber() || value.IsString() || value.IsSymbol();
	}
};

//-----------------------------------------------------------------------------
// ValuePicker
//-----------------------------------------------------------------------------
class ValuePicker {
private:
	const Symbol *_pSymbol;
	ValueList::const_iterator _pValue;
	ValueList::const_iterator _pValueBegin;
	ValueList::const_iterator _pValueEnd;
public:
	inline ValuePicker(const ValuePicker &picker) :
			_pSymbol(picker._pSymbol), _pValue(picker._pValue),
			_pValueBegin(picker._pValueBegin), _pValueEnd(picker._pValueEnd) {}
	inline ValuePicker(const ValueList &valList,
								const Symbol *pSymbol = AScript_Symbol(_anonymous_)) :
			_pSymbol(pSymbol), _pValue(valList.begin()),
			_pValueBegin(valList.begin()), _pValueEnd(valList.end()) {}
	inline bool IsValid() const { return _pValue != _pValueEnd; }
	inline void Reset() { _pValue = _pValueBegin; }
	inline void Advance() { if (IsValid()) _pValue++; };
	inline const Symbol *GetSymbol() const { return _pSymbol; }
	inline const Value &GetValue() const { return *_pValue; }
	inline void operator=(const ValuePicker &picker) {
		_pSymbol = picker._pSymbol, _pValue = picker._pValue;
		_pValueBegin = picker._pValueBegin, _pValueEnd = picker._pValueEnd;
	}
};

//-----------------------------------------------------------------------------
// ValuePickerList
//-----------------------------------------------------------------------------
class ValuePickerList : public std::vector<ValuePicker> {
public:
	//void Assign(Environment &env, bool escalateFlag) const;
	bool IsValidAll() const;
	bool IsValidAny() const;
	void Reset();
	void Advance();
};

inline const TCHAR *GetNumberFormat() { return _T("%g"); }

}

#endif
