#ifndef _KVI_KVS_VARIANT_H_
#define _KVI_KVS_VARIANT_H_
//=============================================================================
//
//   File : kvi_kvs_variant.h
//   Created on Tue 07 Oct 2003 04:01:19 by Szymon Stefanek
//
//   This file is part of the KVIrc IRC client distribution
//   Copyright (C) 2003 Szymon Stefanek <pragma at kvirc dot net>
//
//   This program is FREE software. You can redistribute it and/or
//   modify it under the terms of the GNU General Public License
//   as published by the Free Software Foundation; either version 2
//   of the License, or (at your opinion) any later version.
//
//   This program is distributed in the HOPE that it will be USEFUL,
//   but WITHOUT ANY WARRANTY; without even the implied warranty of
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//   See the GNU General Public License for more details.
//
//   You should have received a copy of the GNU General Public License
//   along with this program. If not, write to the Free Software Foundation,
//   Inc. ,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
//=============================================================================

#include "kvi_settings.h"
#include "kvi_qstring.h"

// anything can be cast down to a scalar but nothing else can be casted up


class KviKvsVariant;

class KVIRC_API KviKvsNumber
{
	friend class KviKvsVariant;
public:
	enum DataType { Real, Integer };
protected:
	union {
		int    iInteger;
		double dReal;
	} m_u;
	DataType m_type;
public:
	DataType type() const { return m_type; };
	bool isReal() const { return m_type == Real; };
	bool isInteger() const { return m_type == Integer; };
	double real() const { return m_u.dReal; };
	int integer() const { return m_u.iInteger; };
};

// pre-declare.. the real declarations are included below
class KviKvsHash;
class KviKvsArray;


#define SHARED_VARIANT

#ifdef SHARED_VARIANT

class KviKvsVariantData
{
public:
	enum Type {
		Nothing = 0,  // m_pData not initialized
		String  = 1,  // QString       (scalar)
		Integer = 2,  // long int      (scalar)
		Real    = 4,  // double        (scalar)
		Array   = 8,  // KviKvsArray
		Hash    = 16  // KviKvsHash
	};
public:
	unsigned int m_uRefs;
	Type m_eType;
	union {
		int           iInteger;
		double      * pReal;
		QString     * pString;
		KviKvsArray * pArray;
		KviKvsHash  * pHash;
	} m_u;
};

class KVIRC_API KviKvsVariant
{
public:
	KviKvsVariant();
	KviKvsVariant(int iInteger);
	KviKvsVariant(double dReal);
	KviKvsVariant(double * pReal);
	KviKvsVariant(const QString &szString);
	KviKvsVariant(QString * pString);
	KviKvsVariant(KviKvsArray * pArray);
	KviKvsVariant(KviKvsHash * pHash);
	KviKvsVariant(const KviKvsVariant &v);
	~KviKvsVariant();
protected:
	KviKvsVariantData * m_pData;
public:
	KviKvsVariantData::Type type(){ return m_pData ? m_pData->m_eType : KviKvsVariantData::Nothing; };

	void setReal(double dReal);
	void setReal(double * pReal);
	void setInteger(int iInteger);
	void setString(const QString &szString);
	void setString(QString * pString);
	void setArray(KviKvsArray * pArray);
	void setHash(KviKvsHash * pHash);
	void setNothing();
	//void unset(){ setNothing(); };

	void getTypeName(QString &szBuffer) const;

	bool isNothing() const { return !m_pData; };
	bool isInteger() const { return m_pData ? (m_pData->m_eType == KviKvsVariantData::Integer) : false; };
	bool isReal() const { return m_pData ? (m_pData->m_eType == KviKvsVariantData::Real) : false; };
	bool isNumeric() const { return m_pData ? (m_pData->m_eType & (KviKvsVariantData::Integer | KviKvsVariantData::Real)) : false; };
	bool isString() const { return m_pData ? (m_pData->m_eType == KviKvsVariantData::String) : false; };
	bool isScalar() const { return m_pData ? (m_pData->m_eType & (KviKvsVariantData::String | KviKvsVariantData::Integer | KviKvsVariantData::Real)) : false; };
	bool isArray() const { return m_pData ? (m_pData->m_eType == KviKvsVariantData::Array) : false; };
	bool isHash() const { return m_pData ? (m_pData->m_eType == KviKvsVariantData::Hash) : false; };
	
	bool isEmpty() const;
	
	// evaluates Integer, Real and String rappresenting an Integer
	bool asInteger(int &iVal) const;
	// evaluates also string lengths, array and hash sizes
	bool asIntegerExt(int &iVal) const;
	// evaluates Real, Integer and String rappresenting a Real
	bool asReal(double &dVal) const;
	// evaluates Real, Integer and String rappresenting a Real or integer
	bool asNumber(KviKvsNumber &n) const;
	// almost always evaluates to some number...
	bool asNumberExt(KviKvsNumber &n) const;
	// always evaluates to a boolean value
	bool asBoolean() const;
	// evaluates anything to a string
	void asString(QString &szBuffer) const;
	void appendAsString(QString &szBuffer) const;

	int integer() const { return m_pData ? m_pData->m_u.iInteger : 0; };
	double real() const { return m_pData ? *(m_pData->m_u.pReal) : 0.0; };
	const QString & string() const { return m_pData ? *(m_pData->m_u.pString) : QString::null; };
	KviKvsArray * array() const { return m_pData ? m_pData->m_u.pArray : 0; };
	KviKvsHash * hash() const { return m_pData ? m_pData->m_u.pHash : 0; };

	void copyFrom(const KviKvsVariant * v);
	void copyFrom(const KviKvsVariant & v);
	void takeFrom(KviKvsVariant * v);
	void takeFrom(KviKvsVariant &v);
	
	void dump(const char * prefix) const;
};

#else //!SHARED_VARIANT

class KVIRC_API KviKvsVariant
{
public:
	enum DataType {
		Nothing = 0,
		String  = 1,  // QString       (scalar)
		Integer = 2,  // long int      (scalar)
		Real    = 4,  // double        (scalar)
		Array   = 8,  // KviKvsArray
		Hash    = 16  // KviKvsHash
	};
public:
	KviKvsVariant();
	KviKvsVariant(int iInteger);
	KviKvsVariant(double dReal);
	KviKvsVariant(double * pReal);
	KviKvsVariant(const QString &szString);
	KviKvsVariant(QString * pString);
	KviKvsVariant(KviKvsArray * pArray);
	KviKvsVariant(KviKvsHash * pHash);
	KviKvsVariant(const KviKvsVariant &v);
	~KviKvsVariant();
protected:
	DataType m_type;
	union {
		int           iInteger;
		double      * pReal;
		QString     * pString;
		KviKvsArray * pArray;
		KviKvsHash  * pHash;
	} m_u;
public:
	DataType type(){ return m_type; };

	void setReal(double dReal);
	void setReal(double * pReal);
	void setInteger(int iInteger);
	void setString(const QString &szString);
	void setString(QString * pString);
	void setArray(KviKvsArray * pArray);
	void setHash(KviKvsHash * pHash);
	void setNothing();
	//void unset(){ setNothing(); };

	void getTypeName(QString &szBuffer) const;

	bool isNothing() const { return m_type == Nothing; };
	bool isInteger() const { return m_type == Integer; };
	bool isReal() const { return m_type == Real; };
	bool isNumeric() const { return (m_type & (Integer | Real)); };
	bool isString() const { return m_type == String; };
	bool isScalar() const { return (m_type & (String | Integer | Real)); };
	bool isArray() const { return m_type == Array; };
	bool isHash() const { return m_type == Hash; };
	
	bool isEmpty() const;
	
	// evaluates Integer, Real and String rappresenting an Integer
	bool asInteger(int &iVal) const;
	// evaluates also string lengths, array and hash sizes
	bool asIntegerExt(int &iVal) const;
	// evaluates Real, Integer and String rappresenting a Real
	bool asReal(double &dVal) const;
	// evaluates Real, Integer and String rappresenting a Real or integer
	bool asNumber(KviKvsNumber &n) const;
	// almost always evaluates to some number...
	bool asNumberExt(KviKvsNumber &n) const;
	// evaluates anything to a string
	void asString(QString &szBuffer) const;
	void appendAsString(QString &szBuffer) const;

	int integer() const { return m_u.iInteger; };
	double real() const { return *(m_u.pReal); };
	const QString & string() const { return *(m_u.pString); };
	KviKvsArray * array() const { return m_u.pArray; };
	KviKvsHash * hash() const { return m_u.pHash; };

	void copyFrom(const KviKvsVariant *v);
	void copyFrom(const KviKvsVariant &v);
	void takeFrom(KviKvsVariant *v);
	void takeFrom(KviKvsVariant &v);
	
	void dump(const char * prefix) const;
};

#endif //!SHARED_VARIANT

#include "kvi_kvs_array.h"
#include "kvi_kvs_hash.h"


#endif //!_KVI_KVS_VARIANT_H_
