class   Id;
class   Value;
class   ValueArray;
class   ValueMap;
class   XmlIO;
class   JsonIO;

class   Ref;
struct  ValueTypeRef;

template <class T>
void Jsonize(JsonIO& io, T& var);

template <class T>
void Xmlize(XmlIO& xml, T& var);

const dword VOID_V    = 0;

const dword INT_V     = 1;
const dword DOUBLE_V  = 2;
const dword STRING_V  = 3;
const dword DATE_V    = 4;
const dword TIME_V    = 5;

const dword ERROR_V   = 6;

const dword VALUE_V   = 7;

const dword WSTRING_V = 8;

const dword VALUEARRAY_V = 9;

const dword INT64_V  = 10;
const dword BOOL_V   = 11;

const dword VALUEMAP_V   = 12;
const dword FLOAT_V   = 13;

const dword UNKNOWN_V = (dword)0xffffffff;

template <class T>
inline dword ValueTypeNo(const T *)                 { return StaticTypeNo<T>() + 0x8000000; }

template<> inline dword ValueTypeNo(const int*)     { return INT_V; }
template<> inline dword ValueTypeNo(const int64*)   { return INT64_V; }
template<> inline dword ValueTypeNo(const double*)  { return DOUBLE_V; }
template<> inline dword ValueTypeNo(const float*)   { return FLOAT_V; }
template<> inline dword ValueTypeNo(const bool*)    { return BOOL_V; }
template<> inline dword ValueTypeNo(const String*)  { return STRING_V; }
template<> inline dword ValueTypeNo(const WString*) { return WSTRING_V; }
template<> inline dword ValueTypeNo(const Date*)    { return DATE_V; }
template<> inline dword ValueTypeNo(const Time*)    { return TIME_V; }
template<> inline dword ValueTypeNo(const Value*)   { return VALUE_V; }

template <class T, dword type = UNKNOWN_V, class B = EmptyClass>
class ValueType : public B {
public:
	static dword ValueTypeNo()                      { return type == UNKNOWN_V ? StaticTypeNo<T>() + 0x8000000 : type; }
	friend dword ValueTypeNo(const T*)              { return T::ValueTypeNo(); }

	bool     IsNullInstance() const                 { return false; }
	void     Serialize(Stream& s)                   { NEVER(); }
	void     Xmlize(XmlIO& xio)                     { NEVER(); }
	void     Jsonize(JsonIO& jio)                   { NEVER(); }
	hash_t   GetHashValue() const                   { return 0; }
	bool     operator==(const T&) const             { NEVER(); return false; }
	String   ToString() const                       { return typeid(T).name(); }
	int      Compare(const T&) const                { NEVER(); return 0; }
	int      PolyCompare(const Value&) const        { NEVER(); return 0; }

	operator ValueTypeRef();
};

template <class T, dword type, class B = EmptyClass> // Backward compatiblity
class AssignValueTypeNo : public ValueType<T, type, B> {};

template <class T>
dword GetValueTypeNo() { return ValueTypeNo((T*)NULL); }

class Value : Moveable<Value> {
public:
	class Void {
	protected:
		Atomic  refcount;

	public:
		void               Retain()                    { AtomicInc(refcount); }
		void               Release()                   { if(AtomicDec(refcount) == 0) delete this; }
		int                GetRefCount() const         { return refcount; }

		virtual bool       IsNull() const              { return true; }
		virtual void       Serialize(Stream& s)        {}
		virtual void       Xmlize(XmlIO& xio)          {}
		virtual void       Jsonize(JsonIO& jio)        {}
		virtual hash_t     GetHashValue() const        { return 0; }
		virtual bool       IsEqual(const Void *p)      { return false; }
		virtual bool       IsPolyEqual(const Value& v) { return false; }
		virtual String     AsString() const            { return ""; }
		virtual int        Compare(const Void *p)      { return 0; }
		virtual int        PolyCompare(const Value& p) { return 0; }

		Void()                                         { refcount = 1; }
		virtual ~Void()                                {}

		friend class Value;
	};

	struct Sval {
		bool       (*IsNull)(const void *p);
		void       (*Serialize)(void *p, Stream& s);
		void       (*Xmlize)(void *p, XmlIO& xio);
		void       (*Jsonize)(void *p, JsonIO& jio);
		hash_t     (*GetHashValue)(const void *p);
		bool       (*IsEqual)(const void *p1, const void *p2);
		bool       (*IsPolyEqual)(const void *p, const Value& v);
		String     (*AsString)(const void *p);
		int        (*Compare)(const void *p1, const void *p2);
		int        (*PolyCompare)(const void *p1, const Value& p2);
	};

protected:
	enum { STRING = 0, REF = 255, VOIDV = 3 };

	static VectorMap<dword, Void* (*)()>& Typemap();
	static Sval *svo[256];
	static Index<String>& NameNdx();
	static Index<dword>&  TypeNdx();

	static void   AddName(dword type, const char *name);
	static int    GetType(const char *name);
	static String GetName(dword type);
	static void   RegisterStd();

	friend void ValueRegisterHelper();

	String   data;
	Void    *&ptr()                  { ASSERT(IsRef()); return *(Void **)&data; }
	Void     *ptr() const            { ASSERT(IsRef()); return *(Void **)&data; }

	void     SetRefType(dword type)  { ASSERT(IsRef()); ((int *)&data)[2] = type; }
	dword    GetRefType() const      { ASSERT(IsRef()); return ((int *)&data)[2]; }

	bool     IsString() const          { return !data.IsSpecial(); }
	bool     Is(byte v) const          { return data.IsSpecial(v); }
	bool     IsRef() const             { return Is(REF); }
	void     InitRef(Void *p, dword t) { data.SetSpecial(REF); ptr() = p; SetRefType(t); }
	void     RefRelease();
	void     RefRetain();
	void     FreeRef()                 { if(IsRef()) RefRelease(); }
	void     Free()                    { FreeRef(); data.Clear(); }
	void     SetLarge(const Value& v);

	template <class T>
	void     InitSmall(const T& init);
	template <class T>
	T&       GetSmallRaw() const;
	template <class T>
	T&       GetSmall() const;

	int      GetOtherInt() const;
	int64    GetOtherInt64() const;
	double   GetOtherDouble() const;
	float	 GetOtherFloat() const;
	bool     GetOtherBool() const;
	Date     GetOtherDate() const;
	Time     GetOtherTime() const;
	String   GetOtherString() const;
	hash_t   GetOtherHashValue() const;

	bool     IsPolyEqual(const Value& v) const;

	enum VSMALL { SMALL };

	template <class T>
	Value(const T& value, VSMALL);

	template <class T> friend Value SvoToValue(const T& x);

	String  GetName() const;

	int     PolyCompare(const Value& v) const;
	int     Compare2(const Value& v) const;

	Vector<Value>&  UnShareArray();

	const Vector<Value>& GetVA() const;

#if defined(_DEBUG) && defined(COMPILER_GCC)
	uint32  magic[4];
	void    Magic()               { magic[0] = 0xc436d851; magic[1] = 0x72f67c76; magic[2] = 0x3e5e10fd; magic[3] = 0xc90d370b; }
	void    ClearMagic()          { magic[0] = magic[1] = magic[2] = magic[3] = 0; }
#else
	void    Magic()               {}
	void    ClearMagic()          {}
#endif

#ifndef DEPRECATED
	static  void Register(dword w, Void* (*c)(), const char *name = NULL);
#endif

	Value(Void *p) = delete;

public:
	template <class T>
	static  void Register(const char *name = NULL);
	template <class T>
	static  void SvoRegister(const char *name = NULL);

	dword    GetType() const;
	bool     IsError() const         { return GetType() == ERROR_V; }
	bool     IsVoid() const          { return Is(VOIDV) || IsError(); }
	bool     IsNull() const;

	template <class T>
	bool     Is() const;
	template <class T>
	const T& To() const;
	template <class T>
	const T& Get() const;

	operator String() const          { return IsString() ? data : GetOtherString(); }
	operator WString() const;
	operator Date() const            { return Is(DATE_V) ? GetSmallRaw<Date>() : GetOtherDate(); }
	operator Time() const            { return Is(TIME_V) ? GetSmallRaw<Time>() : GetOtherTime(); }
	operator double() const          { return Is(DOUBLE_V) ? GetSmallRaw<double>() : GetOtherDouble(); }
	operator float() const           { return Is(FLOAT_V) ? GetSmallRaw<float>() : GetOtherFloat(); }
	operator int() const             { return Is(INT_V) ? GetSmallRaw<int>() : GetOtherInt(); }
	operator int64() const           { return Is(INT64_V) ? GetSmallRaw<int64>() : GetOtherInt64(); }
	operator bool() const            { return Is(BOOL_V) ? GetSmallRaw<bool>() : GetOtherBool(); }
	std::string  ToStd() const       { return operator String().ToStd(); }
	std::wstring ToWStd() const      { return operator WString().ToStd(); }

	Value(const String& s) : data(s) { Magic(); }
	Value(const WString& s);
	Value(const char *s) : data(s)   { Magic(); }
	Value(int i)                     : data(i, INT_V, String::SPECIAL) { Magic(); }
	Value(int64 i)                   : data(i, INT64_V, String::SPECIAL) { Magic(); }
	Value(double d)                  : data(d, DOUBLE_V, String::SPECIAL) { Magic(); }
	Value(float d)                   : data(d, FLOAT_V, String::SPECIAL) { Magic(); }
	Value(bool b)                    : data(b, BOOL_V, String::SPECIAL) { Magic(); }
	Value(Date d)                    : data(d, DATE_V, String::SPECIAL) { Magic(); }
	Value(Time t)                    : data(t, TIME_V, String::SPECIAL) { Magic(); }
	Value(const Nuller&)             : data((int)Null, INT_V, String::SPECIAL) { Magic(); }
	Value(const std::string& s) : Value(String(s)) {}
	Value(const std::wstring& s) : Value(WString(s)) {}

	bool operator==(const Value& v) const;
	bool operator!=(const Value& v) const { return !operator==(v); }
	bool IsSame(const Value& v) const;

	int  Compare(const Value& v) const;
	bool operator<=(const Value& x) const { return Compare(x) <= 0; }
	bool operator>=(const Value& x) const { return Compare(x) >= 0; }
	bool operator<(const Value& x) const  { return Compare(x) < 0; }
	bool operator>(const Value& x) const  { return Compare(x) > 0; }

	String ToString() const;
	String operator ~() const             { return ToString(); }
	String GetTypeName() const            { return GetName(); }

	void  Serialize(Stream& s);
	void  Xmlize(XmlIO& xio);
	void  Jsonize(JsonIO& jio);

	hash_t GetHashValue() const;

	Value& operator=(const Value& v);
	Value(const Value& v);

	int   GetCount() const;
	const Value& operator[](int i) const;
	const Value& operator[](const String& key) const;
	const Value& operator[](const char *key) const;
	const Value& operator[](const Id& key) const;

	Value& At(int i);
	Value& operator()(int i)              { return At(i); }
	void   Add(const Value& src);
	template <typename T>
	Value& operator<<(const T& src)       { Add(src); return *this; }

	Value& GetAdd(const Value& key);
	Value& operator()(const String& key);
	Value& operator()(const char *key);
	Value& operator()(const Id& key);

	Value()                               : data((int)Null, VOIDV, String::SPECIAL) { Magic(); }
	~Value()                              { ClearMagic(); if(IsRef()) RefRelease(); }

	Value(Void *p, dword type)            { InitRef(p, type); Magic(); }
	const Void *GetVoidPtr() const        { ASSERT(IsRef()); return ptr(); }

	friend void Swap(Value& a, Value& b)  { Swap(a.data, b.data); }

	typedef const Value   *const_iterator;

	const_iterator         begin() const                      { return GetVA().begin(); }
	const_iterator         end() const                        { return GetVA().end(); }

#ifdef DEPRECATED
	typedef Value          value_type;
	typedef const_iterator ConstIterator;
	typedef const Value&   const_reference;
	typedef int            size_type;
	typedef int            difference_type;

	static  void Register(dword w, Void* (*c)(), const char *name = NULL);
#endif
};

struct ValueTypeError : Exc {
	Value src;
	int   target;

	ValueTypeError(const String& text, const Value& src, int target);
};

template <class T> bool  FitsSvoValue()                    { return sizeof(T) <= 8; }
template <class T> Value SvoToValue(const T& x)            { return Value(x, Value::SMALL); }

template <class T> Value RichToValue(const T& data);

template <class T> Value RawToValue(const T& data);
template <class T> Value RawPickToValue(T&& data);
template <class T> Value RawDeepToValue(const T& data);
template <class T> T&    CreateRawValue(Value& v);

Value        ErrorValue(const char *s);
Value        ErrorValue(const String& s);
const Value& ErrorValue();

template <class T>
inline bool IsPolyEqual(const T& x, const Value& v) {
	return false;
}

template <class T>
inline hash_t ValueGetHashValue(const T& x) {
	return UPP::GetHashValue(x);
}

#define VALUE_COMPARE_V(T, VT) \
inline bool operator==(const Value& v, T x)   { return v.Is<VT>() ? (VT)v == x : v == Value(x); } \
inline bool operator==(T x, const Value& v)   { return v.Is<VT>() ? (VT)v == x : v == Value(x); } \
inline bool operator!=(const Value& v, T x)   { return v.Is<VT>() ? (VT)v != x : v != Value(x); } \
inline bool operator!=(T x, const Value& v)   { return v.Is<VT>() ? (VT)v != x : v != Value(x); } \

#define VALUE_COMPARE(T) VALUE_COMPARE_V(T, T)

VALUE_COMPARE(int)
VALUE_COMPARE(int64)
VALUE_COMPARE(double)
VALUE_COMPARE(float)
VALUE_COMPARE(bool)
VALUE_COMPARE(Date)
VALUE_COMPARE(Time)
VALUE_COMPARE(String)
VALUE_COMPARE(WString)
VALUE_COMPARE_V(const char *, String)
VALUE_COMPARE_V(const wchar *, WString)

inline bool IsVoidValueTypeNo(int q)     { return (dword)q == VOID_V; }
inline bool IsErrorValueTypeNo(int q)    { return (dword)q == ERROR_V; }
inline bool IsStringValueTypeNo(int q)   { return (dword)q == STRING_V || (dword)q == WSTRING_V; }

inline bool IsIntegerValueTypeNo(int q)  { return (dword)q == INT_V || (dword)q == INT64_V || (dword)q == BOOL_V; }
inline bool IsFloatValueTypeNo(int q)    { return (dword)q == DOUBLE_V || (dword)q == FLOAT_V; }

inline bool IsNumberValueTypeNo(int q)   { return IsIntegerValueTypeNo(q) || IsFloatValueTypeNo(q); }
inline bool IsDateTimeValueTypeNo(int q) { return (dword)q == DATE_V || (dword)q == TIME_V; }

inline bool IsVoid(const Value& v)       { return v.IsVoid(); }
inline bool IsError(const Value& v)      { return v.IsError(); }
inline bool IsString(const Value& v)     { return v.Is<String>() || v.Is<WString>(); }
inline bool IsNumber(const Value& v)     { return v.Is<double>() || v.Is<float>() || v.Is<int>() || v.Is<int64>() || v.Is<bool>(); }
inline bool IsDateTime(const Value& v)   { return v.Is<Date>() || v.Is<Time>(); }
inline bool IsValueArray(const Value& v) { return v.GetType() == VALUEARRAY_V || v.GetType() == VALUEMAP_V; }
inline bool IsValueMap(const Value& v)   { return IsValueArray(v); }

String      GetErrorText(const Value& v);

inline bool          IsNull(const Value& v)               { return v.IsNull(); }
inline const Value&  Nvl(const Value& a, const Value& b)  { return IsNull(a) ? b : a; }

inline bool          IsNaN(const Value& v)                { return v.Is<double>() && IsNaN((double)v); }