#ifndef __OBJECT_H__
#define __OBJECT_H__

#include "Common.h"
#include "Environment.h"
#include "Function.h"
#include "Iterator.h"

#define AScript_DeclareObjectAccessor(name) \
inline static Object_##name *GetObject(const Value &value) { \
	return dynamic_cast<Object_##name *>(value.GetObject()); \
} \
inline static Object_##name *GetObject(Args &args, size_t idxArg) { \
	return dynamic_cast<Object_##name *>(args.GetObject(idxArg)); \
} \
inline static Object_##name *GetSelfObj(Args &args) { \
	return dynamic_cast<Object_##name *>(args.GetSelfObj()); \
} \
inline static Object_##name *Reference(const Object_##name *pObj) { \
	return dynamic_cast<Object_##name *>(Object::Reference(pObj)); \
}

namespace AScript {

//-----------------------------------------------------------------------------
// ObjectBase
//-----------------------------------------------------------------------------
class DLLDECLARE ObjectBase : public Environment, public ICallable {
protected:
	int _cntRef;
protected:
	inline ObjectBase(const ObjectBase &obj) :
							Environment(obj), _cntRef(obj._cntRef) {}
	ObjectBase(Environment *pEnvOuter, EnvType envType);
public:
	virtual ~ObjectBase();
	bool BuildContent(Environment &env, Signal sig, const Value &valueSelf,
		const Expr_Block *pExprBlock, const SymbolSet *pSymbolsAssignable = NULL);
	inline int DecRef() { if (_cntRef > 0) _cntRef--; return _cntRef; }
	inline int GetRefCnt() const { return _cntRef; }
	inline static void Delete(ObjectBase *pObj) {
		if (pObj != NULL && pObj->DecRef() <= 0) delete pObj;
	}
	virtual bool IsFunction() const;
	virtual Iterator *CreateIterator(Signal sig);
	virtual bool DoPropDir(Signal sig, SymbolSet &symbols);
	virtual Value DoCall(Environment &env, Signal sig, Args &args);
	virtual String ToString(Signal sig, bool exprFlag) = 0;
	inline bool PropDir(Signal sig, SymbolSet &symbols) {
		return DoPropDir(sig, symbols);
	}
};

//-----------------------------------------------------------------------------
// Class
//-----------------------------------------------------------------------------
class DLLDECLARE Class : public ObjectBase {
protected:
	const Symbol *_pSymbol;
	Class *_pClassSuper;
	Function *_pConstructor;
	ValueType _valType;
protected:
	inline Class(const Class &cls) : ObjectBase(cls),
			_pSymbol(cls._pSymbol), _pClassSuper(cls._pClassSuper),
			_pConstructor(NULL), _valType(cls._valType) {}
public:
	Class(Environment *pEnvOuter);
	virtual ~Class();
	virtual bool IsClass() const;
	virtual bool IsCustom() const;
	virtual Object *CreateDescendant(Environment &env, Signal sig, Class *pClass);
	virtual bool DoPropDir(Signal sig, SymbolSet &symbols);
	void Prepare();
	inline Class *IncRef() { _cntRef++; return this; }
	inline bool IsAnonymous() const {
		return _pSymbol->IsIdentical(AScript_Symbol(_anonymous_));
	}
	inline void SetSymbol(const Symbol *pSymbol) { _pSymbol = pSymbol; }
	inline const char *GetName() const { return _pSymbol->GetName(); }
	inline void SetValueType(ValueType valType) { _valType = valType; }
	inline ValueType GetValueType() const { return _valType; }
	inline Class *GetClassSuper() const { return _pClassSuper; }
	inline void SetConstructor(Function *pConstructor) {
		_pConstructor = pConstructor;
	}
	inline Function *GetConstructor() { return _pConstructor; }
	virtual bool CastFrom(Environment &env, Signal sig, Value &value);
	virtual bool CastTo(Environment &env, Signal sig, Value &value, ValueType valType);
	virtual String ToString(Signal sig, bool exprFlag);
};

//-----------------------------------------------------------------------------
// Class_Nil
//-----------------------------------------------------------------------------
class DLLDECLARE Class_Nil : public Class {
public:
	Class_Nil(Environment *pEnvOuter);
	virtual bool CastFrom(Environment &env, Signal sig, Value &value);
};

//-----------------------------------------------------------------------------
// Class_Symbol
//-----------------------------------------------------------------------------
class DLLDECLARE Class_Symbol : public Class {
public:
	Class_Symbol(Environment *pEnvOuter);
	virtual bool CastFrom(Environment &env, Signal sig, Value &value);
};

//-----------------------------------------------------------------------------
// Class_Boolean
//-----------------------------------------------------------------------------
class DLLDECLARE Class_Boolean : public Class {
public:
	Class_Boolean(Environment *pEnvOuter);
	virtual bool CastFrom(Environment &env, Signal sig, Value &value);
};

//-----------------------------------------------------------------------------
// Class_Number
//-----------------------------------------------------------------------------
class DLLDECLARE Class_Number : public Class {
public:
	Class_Number(Environment *pEnvOuter);
	virtual bool CastFrom(Environment &env, Signal sig, Value &value);
};

//-----------------------------------------------------------------------------
// Class_Complex
//-----------------------------------------------------------------------------
class DLLDECLARE Class_Complex : public Class {
public:
	Class_Complex(Environment *pEnvOuter);
	virtual bool CastFrom(Environment &env, Signal sig, Value &value);
};

//-----------------------------------------------------------------------------
// Object
//-----------------------------------------------------------------------------
class DLLDECLARE Object : public ObjectBase {
protected:
	Class *_pClass;
protected:
	inline Object(const Object &obj) : ObjectBase(obj), _pClass(obj._pClass) {}
public:
	Object(Class *pClass);
	virtual ~Object();
	virtual Object *Clone() const;
	inline static Object *Reference(const Object *pObj) {
		if (pObj == NULL) return NULL;
		Object *pObjCasted = const_cast<Object *>(pObj);
		pObjCasted->_cntRef++;
		return pObjCasted;
	}
	virtual bool IsObject() const;
	inline Class *GetClass() { return _pClass; }
	inline const Class *GetClass() const { return _pClass; }
	const char *GetClassName() const;
	bool IsInstanceOf(ValueType valType) const;
	inline ValueType GetValueType() const { return _pClass->GetValueType(); }
	virtual int Compare(const Object *pObj) const;
	virtual Value EmptyIndexGet(Signal sig);
	virtual void EmptyIndexSet(Signal sig, const Value &value);
	virtual Value IndexGet(Signal sig, const Value &valueIdx);
	virtual void IndexSet(Signal sig, const Value &valueIdx, const Value &value);
	virtual bool DoPropDir(Signal sig, SymbolSet &symbols);
	virtual Value DoPropGet(Signal sig,
				const Symbol *pSymbol, bool &evaluatedFlag);
	virtual Value DoPropSet(Signal sig,
				const Symbol *pSymbol, const Value &value, bool &evaluatedFlag);
	virtual String ToString(Signal sig, bool exprFlag);
	Value EvalMethod(Signal sig, const Symbol *pSymbol,
							const ValueList &valListArg, bool &evaluatedFlag);
};

}

#endif
