#ifndef __DECLARATION_H__
#define __DECLARATION_H__

#include "Value.h"

namespace AScript {

class Class;
class Expr;
class Environment;
class Args;

//-----------------------------------------------------------------------------
// Declaration
//-----------------------------------------------------------------------------
class DLLDECLARE Declaration {
private:
	const Symbol *_pSymbol;
	ValueType _valType;
	OccurPattern _occurPattern;
	bool _listFlag;
	bool _nomapFlag;
	Expr *_pExprDefault;
public:
	Declaration(const Declaration &decl);
	Declaration(const Symbol *pSymbol, ValueType valType);
	Declaration(const Symbol *pSymbol, ValueType valType,
		OccurPattern occurPattern, bool listFlag, bool nomapFlag, Expr *pExprDefault);
	~Declaration();
	static Declaration *Create(Environment &env, Signal sig, const Expr *pExpr);
	bool ValidateAndCast(Environment &env, Signal sig,
							Value &value, bool listElemFlag = false) const;
	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 bool GetNoMapFlag() const { return _nomapFlag; }
	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 IsVariableLength() const {
		return _occurPattern == OCCUR_ZeroOrMore || _occurPattern == OCCUR_OnceOrMore;
	}
	inline bool IsType(ValueType valType) const { return _valType == valType; }
	inline bool IsQuote() const { return IsType(VTYPE_Quote); }
	inline bool IsAlwaysMappable() const {
		return (_occurPattern == OCCUR_Once || _occurPattern == OCCUR_ZeroOrOnce) &&
				!IsType(VTYPE_Any) && !IsType(VTYPE_List) && !_listFlag;
	}
	inline bool ShouldImplicitMap(const Value &value) const {
		return (value.IsList() || value.IsIterator()) && !GetNoMapFlag() &&
				!((IsType(VTYPE_List) || _listFlag) && value.IsFlatList());
	}
	String ToString() const;
	void SetError_ArgumentType(Signal sig, const Value &value) const;
	void SetError_ArgumentMustBeList(Signal sig, const Value &value) const;
	static void SetError_InvalidArgument(Signal sig);
	static void SetError_NotEnoughArguments(Signal sig);
	static void SetError_TooManyArguments(Signal sig);
};

//-----------------------------------------------------------------------------
// DeclarationList
//-----------------------------------------------------------------------------
class DLLDECLARE DeclarationList : public std::vector<Declaration *> {
public:
	typedef std::map<const Symbol *, const Expr *, Symbol::KeyCompare_UniqNumber> ExprMap;
public:
	static const DeclarationList Null;
public:
	inline DeclarationList() {}
	~DeclarationList();
	bool IsVariableLength() const;
	void SetAsLoose();
	bool Compensate(Environment &env, Signal sig, ValueList &valList) const;
	//bool ShouldGenerateIterator(const ValueList &valListArg,
	//				const Iterator *pIteratorSelf, bool listSelfFlag) const;
	bool ShouldImplicitMap(const ValueList &valList) const;
	bool ShouldImplicitMap(const Args &args) const;
	String ToString() const;
	static void SetError_InvalidArgumentName(Signal sig, const ExprMap &exprMap);
};

//-----------------------------------------------------------------------------
// DeclarationOwner
//-----------------------------------------------------------------------------
class DLLDECLARE DeclarationOwner : public DeclarationList {
private:
	const Symbol *_pSymbolDict;
	bool _allowTooManyArgsFlag;
public:
	inline DeclarationOwner() : _pSymbolDict(NULL), _allowTooManyArgsFlag(false) {}
	DeclarationOwner(const DeclarationOwner &declOwner);
	~DeclarationOwner();
	void operator=(const DeclarationOwner &declOwner);
	inline const Symbol *GetSymbolDict() const { return _pSymbolDict; }
	inline void SetSymbolDict(const Symbol *pSymbol) { _pSymbolDict = pSymbol; }
	inline void AllowTooManyArgs(bool flag) { _allowTooManyArgsFlag = flag; }
	inline bool IsAllowTooManyArgs() const { return _allowTooManyArgsFlag; }
	bool Declare(Environment &env, Signal sig, const ExprList &exprList);
	bool PrepareArgsForUnary(Environment &env, Signal sig,
		const ExprList &exprListArg, ValueList &valListArg, Value &valueWithDict) const;
	bool PrepareArgs(Environment &env, Signal sig,
		const ExprList &exprListArg, ValueList &valListArg, Value &valueWithDict) const;
	bool ValidateAndCast(Environment &env, Signal sig,
		const ValueList &valList, ValueList &valListCasted) const;
	String ToString() const;
};

}

#endif
