#ifndef __DECLARATION_H__
#define __DECLARATION_H__

#include "Value.h"

namespace AScript {

class Class;
class Expr;
class Environment;

//-----------------------------------------------------------------------------
// Declaration
//-----------------------------------------------------------------------------
class Declaration {
private:
	const Symbol *_pSymbol;
	ValueType _valType;
	const Class *_pClass;
	bool _listFlag;
	OccurPattern _occurPattern;
	Expr *_pExprDefault;
private:
	~Declaration();
public:
	Declaration(const Declaration &decl);
	Declaration(const Symbol *pSymbol, ValueType valType, const Class *pClass,
		bool listFlag, OccurPattern occurPattern, Expr *pExprDefault);
	static Declaration *Create(Environment &env, Signal sig, const Expr *pExpr);
	inline Declaration *Clone() const { return new Declaration(*this); }
	inline static void Delete(Declaration *pDecl) { delete pDecl; }
	inline const Symbol *GetSymbol() const { return _pSymbol; }
	inline bool GetListFlag() const { return _listFlag; }
	inline void SetOccurPattern(OccurPattern occurPattern) { _occurPattern = occurPattern; }
	inline OccurPattern GetOccurPattern() const { return _occurPattern; }
	inline const Expr *GetExprDefault() const { return _pExprDefault; }
	inline ValueType GetValueType() const { return _valType; }
	inline bool IsMandatory() const {
		return _occurPattern == OCCUR_Once || _occurPattern == OCCUR_OnceOrMore;
	}
	inline bool IsOptional() const {
		return _occurPattern == OCCUR_ZeroOrOnce || _pExprDefault != NULL;
	}
	//inline bool IsOptional() const {
	//	return _occurPattern == OCCUR_ZeroOrOnce ||
	//				_occurPattern == OCCUR_ZeroOrMore || _pExprDefault != NULL;
	//}
	inline bool IsVariableLength() const {
		return _occurPattern == OCCUR_ZeroOrMore || _occurPattern == OCCUR_OnceOrMore;
	}
	inline bool IsQuote() const { return _valType == VTYPE_Quote; }
	inline bool IsAlwaysMappable() const {
		return (_occurPattern == OCCUR_Once || _occurPattern == OCCUR_ZeroOrOnce) &&
				_valType != VTYPE_AnyType && _valType != VTYPE_List && !_listFlag;
	}
	inline bool IsApplicable(const Value &value) const {
		return !value.IsList() ||
				((_valType == VTYPE_List || _listFlag) && value.IsFlatList());
	}
	String ToString(Signal sig) const;
};

class DeclarationList : public std::vector<Declaration *> {
public:
	static const DeclarationList Null;
public:
	inline DeclarationList() {}
	bool IsVariableLength() const;
	bool IsApplicable(const ValueList &valList) const;
	void SetAsLoose();
	String ToString(Signal sig) const;
};

class DeclarationOwner : public DeclarationList {
public:
	inline DeclarationOwner() {}
	DeclarationOwner(const DeclarationOwner &declOwner);
	~DeclarationOwner();
};

}

#endif
