///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Contains a parser.
 *	\file		IceParser.h
 *	\author		Pierre Terdiman
 *	\date		April, 4, 2000
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEPARSER_H__
#define __ICEPARSER_H__

	// Parse & search
	ICECORE_API bool ParseAndSearch(const String& str, const String& keywords);

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/**
	 *	User-callback, called by the parser each time a new string parameter has been found.
	 *	\param		param		[in] the string parameter
	 *	\param		userdata	[in] user-defined data
	 *	\return		true to end parsing
	 */
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	typedef bool	(*PARSE_CALLBACK)		(ubyte* param, udword userdata);

	class ICECORE_API StringParser
	{
		public:
		// Constructor/Destructor
										StringParser();
										~StringParser();

		// Initialize separators and end symbol
		static			bool			Init();
		static			void			SetSeparator(ubyte symbol)				{ mSeparator[symbol] = true;				}
		static			void			SetDiscarded(ubyte symbol)				{ mDiscarded[symbol] = true;				}

		// Callback control
		__forceinline	StringParser&	SetUserData(udword data)				{ mUserData	= data;			return *this;	}
		__forceinline	StringParser&	SetCallback(PARSE_CALLBACK callback)	{ mCallback	= callback;		return *this;	}

		// Parsing method
						bool			Parse(const char* text);
		private:
		static			bool			mSeparator[256];	//!< Separators
		static			bool			mDiscarded[256];	//!< Discarded symbols
		static			ubyte			mEndSymbol;			//!< End marker

		// User callback
						udword			mUserData;			//!< User-defined data sent to callbacks
						PARSE_CALLBACK	mCallback;
	};

	class ParameterBlock;

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/**
	 *	User-callback, called by the parser each time a new string parameter has been found, or when an error occurs.
	 *	\param		pb			[in] current line's parameter block
	 *	\param		context		[in] callback context (e.g. error codes for error callback)
	 *	\param		userdata	[in] user-defined data
	 *	\param		cmd			[in] possible matched command
	 *	\return		true to go ahead and continue parsing, false to stop it
	 */
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	typedef bool	(*CMDPARSE_CALLBACK)		(const ParameterBlock& pb, udword context, udword userdata, const ParameterBlock* cmd);

	enum BlockFixingCode
	{
		BFC_PRESERVE			= 0,			//!< Don't modify strings
		BFC_REMOVE_TABS			= (1<<0),		//!< Replace tabs with spaces
		BFC_MAKE_LOWER_CASE		= (1<<1),		//!< Make lower case
		BFC_REMOVE_SEMICOLON	= (1<<2),		//!< Remove end-of-line semicolons
		BFC_DISCARD_COMMENTS	= (1<<3),		//!< Discard comments
		BFC_FORCE_DWORD			= 0x7fffffff
	};

	class ICECORE_API ParameterBlock
	{
		public:
		// Constructor/Destructor
											ParameterBlock();
											~ParameterBlock();
		// Initialize
						udword				Create(const String& str);
						udword				Create(const ParameterBlock& block);
		// Reset
						void				DeleteAll();
		// Settings
						void				BindData(CMDPARSE_CALLBACK callback, udword context, bool checkparams);
						void				ForceNbParams(udword i)			{ mNbParams = i;									}
		// Data access
		__forceinline	udword				GetNbParams()			const	{ return mNbParams;									}
		__forceinline	String&				GetParam(udword i)		const	{ ASSERT(i>=0 && i<mNbParams); return mTable[i];	}
		__forceinline	String&				operator[](udword i)	const	{ ASSERT(i>=0 && i<mNbParams); return mTable[i];	}

		__forceinline	CMDPARSE_CALLBACK	GetCallback()			const	{ return mCallback;									}
		__forceinline	udword				GetContext()			const	{ return mContext;									}
		__forceinline	bool				MustCheckParams()		const	{ return mCheckParams;								}

		private:
		// Parameters
						udword				mNbParams;
						String*				mTable;
		// Data
						CMDPARSE_CALLBACK	mCallback;
						udword				mContext;
						bool				mCheckParams;
	};

	class ICECORE_API CommandManager
	{
		public:
		// Constructor/Destructor
											CommandManager();
		virtual								~CommandManager();
		// Commands
						bool				FlushCommands();
						bool				RegisterCommand(const char* command, CMDPARSE_CALLBACK callback=null, udword context=0, bool checkparams=true);
						bool				RegisterCommand(const String& command, CMDPARSE_CALLBACK callback=null, udword context=0, bool checkparams=true);
		__forceinline	udword				GetNbCommands()			const	{ return mCommands.GetNbEntries();					}
		__forceinline	ParameterBlock*		GetCommand(udword i)	const	{ return (ParameterBlock*)mCommands.GetEntry(i);	}
		private:
		// Registered commands and associated data
						Container			mCommands;
	};

	ICECORE_API CommandManager*	GetCommandManager();

	#define SMC_ERROR_INVALIDPARAMNUMBER	1
	#define SMC_ERROR_INVALIDPARAMTYPE		2
	#define SMC_ERROR_INVALIDIFDEF			3
	#define SMC_ERROR_INVALIDENDIF			4

	class ICECORE_API CommandParser : public CommandManager
	{
		public:
		// Constructor/Destructor
											CommandParser();
		virtual								~CommandParser();
		// Settings
		__forceinline	CommandParser&		MakeLowerCase			(bool flag)				{ mMakeLowerCase		= flag;	return *this;		}
		__forceinline	CommandParser&		RemoveTabs				(bool flag)				{ mRemoveTabs			= flag;	return *this;		}
		__forceinline	CommandParser&		RemoveSemiColon			(bool flag)				{ mRemoveSemiColon		= flag;	return *this;		}
		__forceinline	CommandParser&		DiscardComments			(bool flag)				{ mDiscardComments		= flag;	return *this;		}
		__forceinline	CommandParser&		DiscardUnknownCommands	(bool flag)				{ mDiscardUnknownCmds	= flag;	return *this;		}
		__forceinline	CommandParser&		DiscardGlobalCommands	(bool flag)				{ mDiscardGlobalCmds	= flag;	return *this;		}

		// Callback control
		__forceinline	CommandParser&		SetUserData(udword data)						{ mUserData	= data;				return *this;		}
		__forceinline	CommandParser&		SetCallback(CMDPARSE_CALLBACK callback)			{ mCallback	= callback;			return *this;		}
		__forceinline	CommandParser&		SetErrorCallback(CMDPARSE_CALLBACK callback)	{ mErrorCallback = callback;	return *this;		}

		// Parsing method
						bool				CommandParse(const char* buffer);
		private:
		// User callback
						udword				mUserData;				//!< User-defined data sent to callbacks
						CMDPARSE_CALLBACK	mCallback;				//!< User-defined callback for each line
						CMDPARSE_CALLBACK	mErrorCallback;			//!< User-defined callback for errors
		// Current line is cut to pieces in this parameter block
						ParameterBlock		mPB;
		// 
//						FIFOStack			mFIFO;
		// Settings
						bool				mMakeLowerCase;
						bool				mRemoveTabs;
						bool				mRemoveSemiColon;
						bool				mDiscardComments;
						bool				mDiscardUnknownCmds;
						bool				mDiscardGlobalCmds;
		// Internal methods
						bool				FindCommand(const CommandManager* cm, const ParameterBlock& work, bool& validcommand, ParameterBlock*& cmd);
	};

	class ICECORE_API BufferParser : public CommandParser
	{
		public:
		// Constructor/Destructor
											BufferParser();
		virtual								~BufferParser();
		// Parsing method
						bool				Execute(const char* filename);
	};

	class ICECORE_API ScriptFile : public CommandParser
	{
		public:
		// Constructor/Destructor
											ScriptFile();
		virtual								~ScriptFile();
		// Parsing method
						bool				Execute(const char* filename);
	};

#endif // __ICEPARSER_H__
