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

Copyright (C) 1996-1997, 1999-2003 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 _CodeWorker_for_dynamic_libraries_h_
#define _CodeWorker_for_dynamic_libraries_h_

/**
 *  -------------------------------------------------------
 *  CW4dl: CodeWorker header for building dynamic libraries
 *  -------------------------------------------------------
 *
 * This C++ header provides all what you need to construct a new package
 * intended to CodeWorker.
 * There is no C++ body for this file. Just include this file in your
 * project, and it is sufficient.
 *
 *
 * What you have to know for building a new package.
 * -------------------------------------------------
 *
 * Let say that the package's name is 'XXX'. The corresponding executable
 * module (dynamic library) will be "XXXcw.dll" under Windows, and
 * "XXXcw.so" under Linux or other.
 *
 * When the interpreter will found the preprocessor directive '#use XXX'
 * in a script, it will load the executable module and execute the
 * exported C-like function 'void XXX_Init(CW4dl::Interpreter*)'.
 *
 * This C-like function MUST be present! 'C-like' means that it is declared
 * extern "C".
 *
 * Initializing the module that way is useful for registering new functions
 * in the engine, via the function 'createCommand()' of the interpreter
 * (see below in the declaration of the class 'Interpreter' for learning
 * more about it).
 *
 * Every function to export must start its declaration with the preprocessor
 * definition 'CW4DL_EXPORT_SYMBOL' (means 'extern "C"', but a little more
 * under Windows).
 *
 * # Up to 4 parameters, the signature of such a function looks like:
 *     CW4DL_EXPORT_SYMBOL const char* selectList(CW4dl::Interpreter*,
 *												  CW4dl::Parameter p1,
 *												  CW4dl::Parameter p2);
 * where 'selectList' is a function expecting 2 parameters.
 *
 * The initializer 'XXX_Init' informs the engine about the existence
 * of this function in the package:
 *     createCommand("selectList", VALUE_PARAMETER, NODE_PARAMETER);
 * which means that 'selectList' expects a string followed by a tree.
 *
 * In the body of the function 'selectList(...)', the C++ binding is
 * obtained easily by a cast of 'CW4dl::Parameter':
 *   - '(const char*)  p1' for the value parameter 'p1',
 *   - '(CW4dl::Tree*) p2' for the node  parameter 'p2',
 *
 * # if a function contains strictly more than 4 parameter, its signature
 * # changes and requires a variable number of parameters:
 *     CW4DL_EXPORT_SYMBOL const char* myFunction(CW4dl::Interpreter*,
 *												  int nbParams,
 *												  CW4dl::Parameter* tParams);
 * where 'tParams' is an array of parameter types, and where 'nbParams' gives
 * the size.
 *
 * The initializer 'XXX_Init' informs the engine about the existence
 * of this function in the package differently too:
 *     createCommand("myFunction", 6, tParams);
 * which means that 'myFunction' has 6 parameters whose types are provided
 * in 'tParams'.
 *
 * Note that every function returns 'const char*'.
 **/
namespace CW4dl {
	/**
	 * One may share 2 kinds of parameter between the interpreter and
	 * the executable module:
	 *    - value: binds to a 'const char*'
	 *    - node:  binds to a 'CW4dl::Tree*', which refers to the classical
	 *             tree structure of CodeWorker
	 **/
	enum PARAMETER_TYPE {
		VALUE_PARAMETER,
		NODE_PARAMETER
	};

	// see further to understand the role of 'Interpreter'
	class Interpreter;


	/**
	 * The preprocessor definition 'CW4DL_EXPORT_SYMBOL' must appear just
	 * before the declaration of functions to export.
	 **/
#	ifdef WIN32
#		define CW4DL_EXPORT_SYMBOL extern "C" _declspec(dllexport)
#	else
#		define CW4DL_EXPORT_SYMBOL extern "C"
#	endif

	typedef void* Parameter;
	typedef void* Tree;
	typedef void* Function;

	typedef void* DynPackage; // private declaration. Don't care about it.


	/** class 'Parameter2CW'
	 * Type of parameters to pass to the interpreter when calling a CodeWorker's
	 * function. See Interpreter::callFunction(...).
	 **/
	class Parameter2CW {
		private:
			bool _bValue;
			union {
				const char* _tcValue;
				Tree* _pNode;
			} _param;

		public:
			inline Parameter2CW(const char* tcValue) : _bValue(true) { _param._tcValue = tcValue; }
			inline Parameter2CW(Tree* pNode) : _bValue(false) { _param._pNode = pNode; }
	};


	// Private callback signatures for calling CodeWorker's features from
	// the module.
	// You aren't concerned by them.
	typedef bool (*CREATE_COMMAND0)(DynPackage*, const char*);
	typedef bool (*CREATE_COMMAND1)(DynPackage*, const char*, bool);
	typedef bool (*CREATE_COMMAND2)(DynPackage*, const char*, bool, bool);
	typedef bool (*CREATE_COMMAND3)(DynPackage*, const char*, bool, bool, bool);
	typedef bool (*CREATE_COMMAND4)(DynPackage*, const char*, bool, bool, bool, bool);
	typedef bool (*CREATE_COMMANDN)(DynPackage*, const char*, int,  int*);
	typedef void (*ERROR_COMMAND)(const char*);
	typedef const char* (*COPY_LOCAL_STRING)(Interpreter* pInterpreter, const char*);

	typedef Tree*		(*CREATE_TREE)(const char*);
	typedef const char*	(*GET_VALUE)(Tree*);
	typedef void		(*SET_VALUE)(Tree*, const char*);
	typedef void		(*SET_INT_VALUE)(Tree*, int);
	typedef void		(*SET_DOUBLE_VALUE)(Tree*, double);
	typedef Tree*		(*NEXT_NODE)(Tree*, const char*);
	typedef Tree*		(*INSERT_NODE)(Tree*, const char*);
	typedef void		(*CLEAR_NODE)(Tree*);
	typedef int			(*SIZE_ARRAY)(Tree*);
	typedef Tree*		(*GET_ITEM_FROM_KEY)(Tree*, const char*);
	typedef Tree*		(*GET_ITEM_FROM_POS)(Tree*, int);
	typedef const char*	(*GET_ITEM_KEY)(Tree*, int);
	typedef Tree*		(*PUSH_ITEM)(Tree*, const char*);
	typedef Tree*		(*INSERT_ITEM)(Tree*, const char*, const char*);

	typedef Function*	(*FIND_FUNCTION)(Interpreter* pInterpreter, const char*);

	typedef const char*	(*CALL_FUNCTION0)(Interpreter* pInterpreter, Function*);
	typedef const char*	(*CALL_FUNCTION1)(Interpreter* pInterpreter, Function*, Parameter2CW);
	typedef const char*	(*CALL_FUNCTION2)(Interpreter* pInterpreter, Function*, Parameter2CW, Parameter2CW);
	typedef const char*	(*CALL_FUNCTION3)(Interpreter* pInterpreter, Function*, Parameter2CW, Parameter2CW, Parameter2CW);
	typedef const char*	(*CALL_FUNCTION4)(Interpreter* pInterpreter, Function*, Parameter2CW, Parameter2CW, Parameter2CW, Parameter2CW);

	typedef void		(*RELEASE_FUNCTION)(Function*);


	/** class 'Interpreter'
	 * It represents the runtime context of CodeWorker. It is the unavoidable
	 * intermediary between the module you are building and CodeWorker.
	 * Use it for:
	 *   - registering new functions into the CodeWorker's engine,
	 *   - throwing an error,
	 *   - handling parse trees,
	 **/
	class Interpreter {
		private:
			// Private callbacks for calling CodeWorker's features.
			// Don't care about it
			CREATE_COMMAND0 _createCommand0;
			CREATE_COMMAND1 _createCommand1;
			CREATE_COMMAND2 _createCommand2;
			CREATE_COMMAND3 _createCommand3;
			CREATE_COMMAND4 _createCommand4;
			CREATE_COMMANDN _createCommandN;
			ERROR_COMMAND	_error;
			COPY_LOCAL_STRING	_copyLocalString;

			CREATE_TREE	 _createTree;
			GET_VALUE	 _getValue;
			SET_VALUE	 _setValue;
			SET_INT_VALUE	 _setIntValue;
			SET_DOUBLE_VALUE _setDoubleValue;
			NEXT_NODE	 _nextNode;
			INSERT_NODE	 _insertNode;
			CLEAR_NODE	 _clearNode;
			SIZE_ARRAY	 _sizeArray;
			GET_ITEM_FROM_KEY _getItemFromKey;
			GET_ITEM_FROM_POS _getItemFromPos;
			GET_ITEM_KEY _getItemKey;
			PUSH_ITEM	 _pushItem;
			INSERT_ITEM	 _insertItem;

			FIND_FUNCTION _findFunction;
			CALL_FUNCTION0 _callFunction0;
			CALL_FUNCTION1 _callFunction1;
			CALL_FUNCTION2 _callFunction2;
			CALL_FUNCTION3 _callFunction3;
			CALL_FUNCTION4 _callFunction4;
			RELEASE_FUNCTION _releaseFunction;

			// Reference to the CodeWorker's package that manages this module.
			// Don't care about it.
			DynPackage* _pPackage;

			// Variable scope of the interpreter.
			// Not used, but might be in future callbacks.
			Tree* _pVisibility;

			// Contains a string allocated locally. Don't care about this field.
			char* _tcLocalString;

		public:
			//------------------------------------------------------------------
			// Creating new functions to register in CodeWorker.
			//--------------------------------------------------
			//
			// Enriching the engine of CodeWorker with new functions is done by
			// calling 'createCommand()'.
			//
			// These calls are done just after loading the module in
			// CodeWorker (preprocessor statement '#use'), when the engine
			// initializes the library, running the exported special function
			// 'xxx_Init' (where 'xxx' is the name of the package).
			//
			// The signature of the initializer conforms to:
			// 'CW4DL_EXPORT_SYMBOL void xxx_Init(CW4dl::Interpreter* interpreter)'
			//------------------------------------------------------------------

			/** function 'createCommand()'
			 * createCommand() serves to inform the engine of CodeWorker about
			 * the functions exported by the package, giving their signature.
			 * Each createCommand() takes the name of the function as the first
			 * parameter. Then, it describes the type of parameters:
			 *   - VALUE_PARAMETER: 'const char*'  in the C++ binding,
			 *   - NODE_PARAMETER:  'CW4dl::Tree*' in the C++ binding.
			 *
			 * To register functions belonging up to 4 parameters, use the function
			 * with the fixed number of parameters (5 first functions).
			 * To register functions expecting strictly more that 4 parameters,
			 * use the 'createCommand()' with variable number of parameters.
			 **/
			inline bool createCommand(const char* tcName) { return _createCommand0(_pPackage, tcName); }
			inline bool createCommand(const char* tcName, PARAMETER_TYPE p1) { return _createCommand1(_pPackage, tcName, (p1 == NODE_PARAMETER)); }
			inline bool createCommand(const char* tcName, PARAMETER_TYPE p1, PARAMETER_TYPE p2) { return _createCommand2(_pPackage, tcName, (p1 == NODE_PARAMETER), (p2 == NODE_PARAMETER)); }
			inline bool createCommand(const char* tcName, PARAMETER_TYPE p1, PARAMETER_TYPE p2, PARAMETER_TYPE p3) { return _createCommand3(_pPackage, tcName, (p1 == NODE_PARAMETER), (p2 == NODE_PARAMETER), (p3 == NODE_PARAMETER)); }
			inline bool createCommand(const char* tcName, PARAMETER_TYPE p1, PARAMETER_TYPE p2, PARAMETER_TYPE p3, PARAMETER_TYPE p4) { return _createCommand4(_pPackage, tcName, (p1 == NODE_PARAMETER), (p2 == NODE_PARAMETER), (p3 == NODE_PARAMETER), (p4 == NODE_PARAMETER)); }
			inline bool createCommand(const char* tcName, int iNbParams, PARAMETER_TYPE* tParams) { return _createCommandN(_pPackage, tcName, iNbParams, (int*) tParams); }

			/** function 'copyLocalString(...)'
			 * Both CodeWorker and the shared library have their own heap
			 * management.
			 * You can't allocate memory in the module and desallocate
			 * it in CodeWorker.
			 * To pass a string as a result of function, it must be either
			 * a constant string or a string you have to delete after its
			 * use.
			 * But when, and how?
			 * The string will be allocated in the body of the function and
			 * desallocated by the interpreter after the call. You allocate
			 * the string by running 'copyLocalString()':
			 *   Parameter:
			 *       - tcText: a constant string to copy,
			 *   Return value:
			 *       The duplicated input string, allocated in the scope of
			 *       the interpreter.
			 **/ 
			inline const char* copyLocalString(const char* tcText) { return _copyLocalString(this, tcText); }

			/** function 'error(...)'
			 * Throws an error.
			 *
			 * Equivalent to the function 'error(...)' available in the
			 * scripting language.
			 **/
			inline void error(const char* tcError) { _error(tcError); }

			/** function 'trueConstant()'
			 * Returns the boolean value 'true'.
			 **/
			inline static const char* trueConstant() { return "true"; }

			//------------------------------------------------------------------
			// Node creation
			//------------------------------------------------------------------

			/** function 'createTree(...)'
			 * Returns a new local tree. The caller has to delete this tree after
			 * use.
			 **/
			inline Tree* createTree(const char* tcName) { return _createTree(tcName); }

			//------------------------------------------------------------------
			// Node value
			//------------------------------------------------------------------

			/** function 'getValue(...)'
			 * Returns the value of a node.
			 **/
			inline const char* getValue(Tree* pTree) { return _getValue(pTree); }

			/** function 'setValue(...)'
			 * Assigns a value to a node.
			 **/
			inline void setValue(Tree* pTree, const char* tcValue) { _setValue(pTree, tcValue); }

			/** function 'setIntValue(...)'
			 * Assigns an integer value to a node.
			 **/
			inline void setIntValue(Tree* pTree, int iValue) { _setIntValue(pTree, iValue); }

			/** function 'setDoubleValue(...)'
			 * Assigns a double value to a node.
			 **/
			inline void setDoubleValue(Tree* pTree, double dValue) { _setDoubleValue(pTree, dValue); }

			//------------------------------------------------------------------
			// Node attribute
			//------------------------------------------------------------------

			/** function 'nextNode(...)'
			 * Navigates to the node an attribute is pointing to.
			 * If the node doesn't exist, it returns a null pointer.
			 *
			 * Example:
			 *   CW4dl::Tree* pClassName = interpreter->nextNode(pClass, "name");
			 **/
			inline Tree* nextNode(Tree* pTree, const char* tcAttribute) { return _nextNode(pTree, tcAttribute); }

			/** function 'insertNode(...)'
			 * Inserts a subnode to a node.
			 * If the node already exists, it does nothing.
			 *
			 * Example:
			 *   CW4dl::Tree* pMethods = interpreter->insertNode(pClass, "methods");
			 **/
			inline Tree* insertNode(Tree* pTree, const char* tcAttribute) { return _insertNode(pTree, tcAttribute); }

			/** function 'clearNode(...)'
			 * Clears the value and erases all subnodes.
			 **/
			inline void  clearNode(Tree* pTree) { _clearNode(pTree); }

			//------------------------------------------------------------------
			// Node array
			//------------------------------------------------------------------

			/** function 'size(...)'
			 * Returns the size of an array (i.e the number of items).
			 **/
			inline int size(Tree* pTree) { return _sizeArray(pTree); }

			/** function 'getItem(..., const char*)'
			 * Returns the item of an array, whose key is passed as parameter.
			 *
			 * Example:
			 *   CW4dl::Tree* pItem = interpreter->getItem(listOfRooms, "kitchen");
			 * In CodeWorker:
			 *   localref pItem = listOfRooms["kitchen"];
			 **/
			inline Tree* getItem(Tree* pTree, const char* tcKey) { return _getItemFromKey(pTree, tcKey); }

			/** function 'getItem(..., int)'
			 * Returns the item of an array, whose rank is passed as parameter.
			 * It starts counting a 0.
			 *
			 * Example:
			 *   CW4dl::Tree* pItem = getItem(listOfRooms, 2);
			 * In CodeWorker:
			 *   localref pItem = listOfRooms#[2];
			 **/
			inline Tree* getItem(Tree* pTree, int iKey) { return _getItemFromPos(pTree, iKey); }

			/** function 'getItemKey(..., int)'
			 * Returns the key of an array's item, whose rank is passed as parameter.
			 * It starts counting a 0.
			 *
			 * Example:
			 *   interpreter->insertItem(listOfRooms, "kitchen", "2nd floor");
			 *   interpreter->insertItem(listOfRooms, "bathroom");
			 *   const char* tcKey0 = getItemKey(listOfRooms, 0);
			 *   const char* tcKey1 = getItemKey(listOfRooms, 1);
			 * with:
			 *   tcKey0 equals "kitchen"
			 *   tcKey1 equals "bathroom"
			 **/
			inline const char* getItemKey(Tree* pTree, int iKey) { return _getItemKey(pTree, iKey); }

			/** function 'pushItem(...)'
			 * Adds a new item in a list, where the key is automatically computed as
			 * the rank of the item in the list (starting at 0), and returns it.
			 * A value may be assigned to the new item.
			 *
			 * Example:
			 *   CW4dl::Tree* pItem = interpreter->pushItem(pList, "myFile.txt");
			 * In CodeWorker:
			 *   pushItem pList = "myFile.txt";
			 *   localref pItem = pList#back;
			 **/
			inline Tree* pushItem(Tree* pArray, const char* tcValue = 0L) { return _pushItem(pArray, tcValue); }

			/** function 'insertItem(...)'
			 * Inserts a new item in a list, associated to a given key.
			 * A value may be assigned to the new item.
			 *
			 * Example:
			 *   interpreter->insertItem(pList, "kitchen", "2nd floor");
			 *   interpreter->insertItem(pList, "bathroom");
			 * In CodeWorker:
			 *   insert pList["kitchen"] = "2nd floor";
			 *   insert pList["bathroom"];
			 **/
			inline Tree* insertItem(Tree* pArray, const char* tcKey, const char* tcValue = 0L) { return _insertItem(pArray, tcKey, tcValue); }

			/** function 'findFunction(...)'
			 * Searches a function implemented in CodeWorker, at the current
			 * instruction scope.
			 * This function may be either predefined or user defined.
			 *
			 * Example:
			 *   CW4dl::Function* pFunction = interpreter->findFunction("traceObject");
			 *   interpreter->callFunction(pFunction, pList);
			 **/
			inline Function* findFunction(const char* tcFunctionName) { return _findFunction(this, tcFunctionName); }

			/** function 'callFunction(...)'
			 * Calls a CodeWorker's function previously obtained with 'findFunction()'.
			 * This function may be either predefined or user defined.
			 *
			 * Important: you have to delete the function's pointer after use, with
			 *   'releaseFunction()'.
			 *
			 * Example:
			 *   CW4dl::Function* pFunction = interpreter->findFunction("traceObject");
			 *   interpreter->callFunction(pFunction, pList);
			 *   ...
			 *   interpreter->releaseFunction(pFunction); // not used anymore
			 **/
			inline const char* callFunction(Function* pfFunction) { return _callFunction0(this, pfFunction); }
			inline const char* callFunction(Function* pfFunction, Parameter2CW p1) { return _callFunction1(this, pfFunction, p1); }
			inline const char* callFunction(Function* pfFunction, Parameter2CW p1, Parameter2CW p2) { return _callFunction2(this, pfFunction, p1, p2); }
			inline const char* callFunction(Function* pfFunction, Parameter2CW p1, Parameter2CW p2, Parameter2CW p3) { return _callFunction3(this, pfFunction, p1, p2, p3); }
			inline const char* callFunction(Function* pfFunction, Parameter2CW p1, Parameter2CW p2, Parameter2CW p3, Parameter2CW p4) { return _callFunction4(this, pfFunction, p1, p2, p3, p4); }

			inline void releaseFunction(Function* pfFunction) { _releaseFunction(pfFunction); }

		private:
			Interpreter();
			Interpreter(const Interpreter&);
	};
}

#endif
