#ifndef __OBJECT_H__
#define __OBJECT_H__

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

namespace AScript {

//-----------------------------------------------------------------------------
// ObjectBase
//-----------------------------------------------------------------------------
class ObjectBase : public Environment {
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 Expr_Block *pExprBlock,
									const SymbolSet *pSymbolsAssignable = NULL);
	inline int DecRef() { _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 IsList() const;
	virtual bool IsDict() const;
	virtual bool IsFile() const;
	virtual bool IsExpr() const;
	virtual bool IsFunction() const;
	virtual String ToString(Signal sig, bool exprFlag) = 0;
};

//-----------------------------------------------------------------------------
// Class
//-----------------------------------------------------------------------------
class Class : public ObjectBase {
public:
	class Constructor : public ConstructorBase {
	public:
		Constructor(Environment &env, const TCHAR *name = AScript_Symbol(Object)->GetName());
		virtual Value DoEval(Environment &env, Signal sig, Context &context) const;
	};
protected:
	const Symbol *_pSymbol;
	Class *_pClassSuper;
protected:
	inline Class(const Class &cls) : ObjectBase(cls),
					_pSymbol(cls._pSymbol), _pClassSuper(cls._pClassSuper) {}
public:
	Class(Environment *pEnvOuter, const Symbol *pSymbol);
	virtual ~Class();
	virtual bool IsCustom() const;
	virtual bool IsClass() const;
	virtual Object *CreateDescendant(Environment &env, Signal sig, Class *pClass);
	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 TCHAR *GetName() const { return _pSymbol->GetName(); }
	inline Class *GetClassSuper() { return _pClassSuper; }
	virtual String ToString(Signal sig, bool exprFlag);
};

//-----------------------------------------------------------------------------
// Object
//-----------------------------------------------------------------------------
class 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 Object *IncRef() { _cntRef++; return this; }
	virtual bool IsObject() const;
	inline Class *GetClass() { return _pClass; }
	inline const Class *GetClass() const { return _pClass; }
	const TCHAR *GetClassName() const;
	virtual Value GetByIndex(Signal sig, const Value &valueIdx) const;
	virtual void SetByIndex(Signal sig, const Value &valueIdx, const Value &value);
	virtual Value Call(Environment &env, Signal sig,
							Value &value, ContextExpr &contextExpr);
	virtual String ToString(Signal sig, bool exprFlag);
	Value EvalMethod(Signal sig, const Symbol *pSymbol,
							const ValueList &valListArg, bool &evaluatedFlag);
};

}

#endif
