#ifndef _KVI_COMMAND_H_
#define _KVI_COMMAND_H_

//
//   File : kvi_command.h
//   Creation date : Sun Jul 02 2000 15:39:34 by Szymon Stefanek
//
//   This file is part of the KVirc irc client distribution
//   Copyright (C) 1999-2000 Szymon Stefanek (pragma at kvirc dot net)
//
//   This program is FREE software. You can redistribute it and/or
//   modify it under the terms of the GNU General Public License
//   as published by the Free Software Foundation; either version 2
//   of the License, or (at your opinion) any later version.
//
//   This program 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 General Public License for more details.
//
//   You should have received a copy of the GNU General Public License
//   along with this program. If not, write to the Free Software Foundation,
//   Inc. ,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//

#include "kvi_settings.h"
#include "kvi_string.h"
#include "kvi_wstring.h"
#include "kvi_parameterlist.h"
#include "kvi_datacontainer.h"

#include <qstrlist.h>

class KviUserParser;
class KviWindow;
class KviScriptObject;

class KVIRC_API KviCommand
{
	friend class KviUserParser;
	friend class KviServerParser;
	friend class KviScriptObject;
	friend class KviPopupMenu;
	friend class KviTimerManager;
public:
	enum ProcessingState { Error ,                           // Unrecoverable
							Success ,                        // Ok
							Halt ,                           // Halt encountered: break out of the processing stack (no error)
							Return ,                         // Just like Halt but with a return value
							Break ,                          // Jump out of the inner loop
							ParsingDictionaryAssignment ,    // Processing the right operand of a dictionary assignment operator
							HaveDictionaryReturn ,           // Was parsing right dictionary operand and encountered a function that returns a dictionary
							ParsingArrayAssignment ,
							HaveArrayReturn
						};

	KviCommand(const char * cmdBuffer,KviWindow *wnd,KviCommand * pParent = 0,KviDataContainer * pExtendedScopeDataContainer = 0);
	KviCommand(const KviStr & cmdBuffer,KviWindow *wnd,KviCommand * pParent = 0,KviDataContainer * pExtendedScopeDataContainer = 0);
	KviCommand(const QString & cmdBuffer,KviWindow *wnd,KviCommand * pParent = 0,KviDataContainer * pExtendedScopeDataContainer = 0);
	KviCommand(const char * begin,const char * end,KviWindow *wnd,KviCommand * pParent = 0);

	~KviCommand();

private:
	KviCommand            * m_pParent;                       // parend command
	KviStr                  m_szCmdBuffer;                   // we're parsing this command buffer: m_ptr points inside here!
	char                  * m_ptr;                           // pointer to m_szCmdBuffer... parsing pointer
	KviWindow             * m_pWnd;                          // window we are bound to
	KviParameterList      * m_pParamList;                    // list of toplevel command positional parameters
	bool                    m_bOwnParams;                    // do we own the param list ?
	QStrList              * m_pContextStack;                 // context string stack
	KviPtrList<KviStr>    * m_pSwitchList;                   // switches in the current command
	KviDataContainer      * m_pDataContainer;                // local data container (owned)
	KviDataContainer      * m_pExtendedScopeDataContainer;   // extended scope data container: may be set and removed from external functions
	KviStr                  m_szRetBuffer;                   // return buffer from the whole command
	KviScriptObject       * m_pScopeObject;                  // current scope object: this is stacked externally!
	KviScriptObject       * m_pThisPointer;                  // this object pointer: this is stacked externally!
	const char            * m_pszCurrentEntity;              // Currently parsed command/function (valid only just after the call!) (this is a pointer to the stack!)
	ProcessingState         m_state;                         // processing state
	int                     m_iError;                        // last error
	KviStr                  m_szErrDetail;                   // error detail string
	KviParameterList      * m_pReturnParameterList;          // parameter list to which we have to append list returns in identifiers (newer owned in fact , but deleted if found owned in destructor)
	KviPtrList<KviStr>    * m_pAliasSwitchList;              // shallow
public:
	bool                parsingDictionaryAssignment(){ return (m_state == ParsingDictionaryAssignment); };
	void                setParsingDictionaryAssignment(bool bYes);
	bool                parsingArrayAssignment(){ return (m_state == ParsingArrayAssignment); };
	void                setParsingArrayAssignment(bool bYes);
	void                beginListArrayOrDictionaryReturnIdentifier();
	void                addListArrayOrDictionaryReturnValue(int id,const KviStr &val,KviStr &buffer);
	void                addListArrayOrDictionaryReturnValue(int id,const char * val,KviStr &buffer);
	KviDictionary     * dictionaryReturn();
	KviStringArray    * arrayReturn();

	const KviStr      & returnValue(){ return m_szRetBuffer; };

	void                setAliasSwitchList(KviPtrList<KviStr> * pList){ m_pAliasSwitchList = pList; };
	KviPtrList<KviStr> * aliasSwitchList(){ return m_pAliasSwitchList; };

	void                setReturnParameterList(KviParameterList * p){ m_pReturnParameterList = p; };
	KviParameterList  * returnParameterList(){ return m_pReturnParameterList; };

//	const char        * currentCommandName(){ return m_szCurrentCommandName.ptr(); };
	const char        * currentEntity(){ return m_pszCurrentEntity; };
	void                setCurrentEntity(const char * ent){ m_pszCurrentEntity = ent; };
	KviCommand    *     parent(){ return m_pParent; };
	// data
	void                forgetExtendedScopeDataContainer(){ m_pExtendedScopeDataContainer = 0; };
	KviDataContainer  * extendedScopeDataContainer(){ return m_pExtendedScopeDataContainer; };
	KviDataContainer  * dataContainer(){ return m_pDataContainer; };
	void                setDataContainer(KviDataContainer * c);
	void                forgetDataContainer(){ m_pDataContainer = 0; };
	// params tricks
	void                getParamCount(KviStr &buffer);
	void                getSingleParam(int param,KviStr &buffer);
	void                getParam(int fromParam,int toParam,KviStr &buffer);
	bool                hasParams(){ return m_pParamList != 0; };
	KviParameterList *  params(){ return m_pParamList; };
	void                setParams(KviParameterList * params,bool bTransferOwnership = true);
	// switch tricks
	bool                hasSwitch(char letter);
	bool                getSwitchValue(char letter,KviStr &buffer);
	void                clearSwitchList(){ while(m_pSwitchList->first())m_pSwitchList->removeFirst(); };
	// command buffer
	void                setCmdBuffer(const char * cmdBuffer);
	const char    *     commandBuffer(){ return m_szCmdBuffer; };
	// parsing tricks
	char          *     ptr(){ return m_ptr; };
	void                next(){ ++m_ptr; };
	void                skip(int nChars){ m_ptr += nChars; };
	void                setPtr(char *ptr){ m_ptr = ptr; };
	void                skipWhiteSpace();
	void                skipSpace();
	// window binding
	KviWindow     *     window(){ return m_pWnd; };
	void                rebindToWindow(KviWindow * wnd){ m_pWnd = wnd; };
	// context stuff
	void                enterContext(const char * context){ m_pContextStack->append(context); };
	bool                leaveContext(){ return m_pContextStack->removeLast(); };
	int                 contextStackSize(){ return m_pContextStack->count(); };
	// processing result

	// errors & warnings
	bool                error(int errCode,const char * format = 0,...);
	bool                warning(const char *format,...);
	bool                warning(const kvi_wchar_t *format,...);
	bool                noIrcContext();
	bool                notConnectedToServer();
	void                warnNoIrcContext();
	void                warnNotConnectedToServer();
	// error checking
	bool                hasError(){ return (m_state == Error); };
	// object stuff
	KviScriptObject *   scopeObject(){ return m_pScopeObject; };
	KviScriptObject *   thisPointer(){ return m_pThisPointer; };
	void                setThisPointer(KviScriptObject *o){ m_pThisPointer = o; };
	void                setScopeObject(KviScriptObject *ob){ m_pScopeObject = ob; };
	// retval stuff
	void                setReturnValue(const char * retValue){ m_szRetBuffer = retValue; };
	// break handling
	void                setBreakEncountered();
	bool                breakEncountered();
	void                setBreakHandled(int iContextStackSize);
	// halt handling
	void                setHaltEncountered(){ m_state = Halt; };
	bool                haltEncountered(){ return (m_state == Halt); };
	// return handling
	void                setReturnEncountered(){ m_state = Return; };
	bool                returnEncountered(){ return (m_state == Return); };
};

#define ENTER_CONTEXT(_cmd_ptr,_name) _cmd_ptr->enterContext(_name)

#endif //_KVI_COMMAND_H_
