/* "CodeWorker":	a scripting language for parsing and generating text.

Copyright (C) 1996-1997, 1999-2002 Cédric Lemaire

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library 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
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

To contact the author: codeworker@free.fr
*/

#ifndef _DtaScriptVariable_h_
#define _DtaScriptVariable_h_

#include <string>
#include <list>
#include <vector>
#include <map>
#include <set>
#include <memory>

namespace CodeWorker {
	class ExprScriptVariable;
	class ExprScriptExpression;
	class DtaProject;
	class DtaScriptIndex;
	class DtaScriptReferenceVariable;
	class GrfBlock;
	class CppCompilerEnvironment;
	class ExternalValueNode;

	class DtaScriptVariable;

	class DtaScriptVariableList {
		private:
			DtaScriptVariable* _pNode;
			DtaScriptVariableList* _pNext;

		public:
			inline DtaScriptVariableList(DtaScriptVariable* pNode = 0L, DtaScriptVariableList* pNext = 0L) : _pNode(pNode), _pNext(pNext) {}
			inline ~DtaScriptVariableList() { delete _pNext; }

			inline DtaScriptVariable* getNode() const { return _pNode; }
			inline void setNode(DtaScriptVariable* pNode) { _pNode = pNode; }
			inline DtaScriptVariableList* getNext() const { return _pNext; }
			inline void setNext(DtaScriptVariableList* pNext) { _pNext = pNext; }

			void pushBack(DtaScriptVariable* pVariable);
	};

	class DtaScriptVariable {
	private:
		const char* _tcName;
		DtaScriptVariable* _pParent;
		DtaScriptVariableList* _pAttributes;
		struct NodeArrayType {
			std::list<DtaScriptVariable*> items;
			mutable std::map<std::string, DtaScriptVariable*>* cache;
			inline NodeArrayType() : cache(0L) {}
			NodeArrayType(DtaScriptVariable* pElt);
			~NodeArrayType();
		} *_pArray;
		std::set<DtaScriptVariable*>* _pReferencedByVariables;
		enum VALUE_NODE_TYPE {NO_VALUE_NODE, STRING_VALUE_NODE, REFERENCE_VALUE_NODE, EXTERNAL_VALUE_NODE} _eValueNode;
		union {
			DtaScriptVariable* var;
			struct {
				char* text;
				size_t length;
			} str;
			ExternalValueNode* ext;
		} _value;

	public:
		inline DtaScriptVariable() : _pParent(0L), _eValueNode(NO_VALUE_NODE), _tcName(0L), _pArray(0L), _pReferencedByVariables(0L), _pAttributes(0L) {}
		inline DtaScriptVariable(DtaScriptVariable* pParent, const char* tcName)
			: _pParent(pParent), _eValueNode(NO_VALUE_NODE), _pArray(0L), _pReferencedByVariables(0L), _pAttributes(0L),
#ifdef WIN32
			  _tcName(::_strdup(tcName))
#else
			  _tcName(::strdup(tcName))
#endif
		{}
		inline DtaScriptVariable(DtaScriptVariable* pParent, const std::string& sName)
			: _pParent(pParent), _eValueNode(NO_VALUE_NODE), _pArray(0L), _pReferencedByVariables(0L), _pAttributes(0L),
#ifdef WIN32
			  _tcName(::_strdup(sName.c_str()))
#else
			  _tcName(::strdup(sName.c_str()))
#endif
		{}
		virtual ~DtaScriptVariable();

		virtual bool isIndex() const;

		inline DtaScriptVariable* getParent() const { return _pParent; }
		inline DtaScriptVariable* getReferencedVariable() const { return ((_eValueNode == REFERENCE_VALUE_NODE) ? _value.var : 0L); }
		inline ExternalValueNode* getExternalValueNode() const { return ((_eValueNode == EXTERNAL_VALUE_NODE) ? _value.ext : 0L); }
		std::string getCompleteName() const;
		inline const char* getName() const { return _tcName; }
		bool isLocal() const;
		inline DtaScriptVariableList* getAttributes() const { return _pAttributes; }
		const std::list<DtaScriptVariable*>* getArray() const;
		int getArraySize() const;
		const std::map<std::string, DtaScriptVariable*>* getSortedArray() const;
		std::auto_ptr<std::vector<DtaScriptVariable*> > getSortedNoCaseArray() const;
		std::auto_ptr<std::vector<DtaScriptVariable*> > getSortedArrayOnValue() const;
		std::auto_ptr<std::vector<DtaScriptVariable*> > getSortedNoCaseArrayOnValue() const;
		DtaScriptVariable* getArrayElement(const std::string& sPosition) const;
		DtaScriptVariable* getArrayElement(int iPosition) const;
		void invertArray();
		void removeArrayElement();
		void removeArrayElement(const char* sPosition);
		void removeArrayElement(int iPosition);
		void removeFirstElement();
		void removeLastElement();
		void clearArray();
		void sortArray();

		DtaScriptVariable* getVariable(const ExprScriptVariable& exprVariable);
		DtaScriptVariable* getNonRecursiveVariable(DtaScriptVariable& visibility, const ExprScriptVariable& exprVariable);
		DtaScriptVariable* getNonRecursiveNonReferencedVariable(DtaScriptVariable& visibility, const ExprScriptVariable& exprVariable);
		DtaScriptVariable* getVariableForReferenceAssignment(const ExprScriptVariable& exprVariable);
		DtaScriptVariable* getExistingVariable(const ExprScriptVariable& exprVariable);
		DtaScriptVariable* getNoWarningExistingVariable(const ExprScriptVariable& exprVariable);

		DtaScriptVariable* getNonRecursiveVariable(const char* sName);
		DtaScriptVariable* getVariable(const char* sName, bool bRecursiveSearch = true, bool bCreateIfUnknown = true, bool bReferencedVariable = true);
		DtaScriptVariable* getNode(const char* sName);
		DtaScriptVariable* insertNode(const char* sName);
		DtaScriptVariable* getEvaluatedNode(const std::string& sDynamicVariable);
		DtaScriptVariable* getOrCreateLocalEvaluatedNode(const std::string& sDynamicVariable);
		DtaScriptVariable* insertEvaluatedNode(const std::string& sDynamicVariable);
		DtaScriptVariable* insertClassicalEvaluatedNode(const std::string& sDynamicVariable);
		bool equal(const DtaScriptVariable& variable);

		DtaScriptIndex* createIndex(const char* sName);
		DtaScriptIndex* getIndex(const char* sName) const;

		DtaScriptVariable* addElement(const std::string& sName);

		void setValueAtVariable(const char* sVariable, const char* sValue, bool bRecursiveSearch = false, bool bCreateIfUnknown = true);

		const char* getValue() const;
		size_t getValueLength() const;
		double getDoubleValue() const;
		bool   getBooleanValue() const;
		int    getIntValue() const;
		void clearValue();
		void setValue(const char* sValue);
		void setValue(bool bValue);
		void setValue(double dValue);
		void setValue(int iValue);
		void setValue(const std::list<std::string>& listOfValues);
		void setValue(DtaScriptVariable* pVariable);
		void setValue(ExternalValueNode* pExternal);
		void concatValue(const char* sValue);

		void remove(DtaScriptVariable* pVariable);
		void remove(const char* sAttribute);
		void removeRecursive(const char* sAttribute);
		void clearContent();
		void addArrayElements(const DtaScriptVariable& variable);
		void copyAll(const DtaScriptVariable& variable, bool bMerge = false);
		DtaScriptVariable* pushItem(const std::string& sValue);
		void slideNodeContent(DtaScriptVariable& visibility, const ExprScriptVariable& varExpr);

		void trace(DtaScriptVariable& visibility);
		void traceStack();

	private:
		DtaScriptVariable* addInternalElement(const std::string& sName);
		DtaScriptVariable* getInternalVariableExtraction(DtaScriptVariable& visibility, const ExprScriptVariable& exprVariable, bool bRecursiveSearch, bool bCreateIfUnknown, bool bReferencedVariable);
		void removeReference();
		void addReferencedBy(DtaScriptVariable* pVariable);
	};



	class GrfForeach;

	class DtaScriptIndex : public DtaScriptVariable {
	private:
		GrfForeach* _pForeach;

	public:
		DtaScriptIndex(DtaScriptVariable* pParent, const std::string& sName) : DtaScriptVariable(pParent, sName), _pForeach(0L) {}
		virtual ~DtaScriptIndex();

		virtual bool isIndex() const;

		inline void setForeach(GrfForeach* pForeach) { _pForeach = pForeach; }
		inline GrfForeach* getForeach() const { return _pForeach; }
	};
}

#endif
