#ifndef _KVI_UPARSER_H_
#define _KVI_UPARSER_H_

//
//   File : kvi_uparser.h
//   Creation date : Sun Jul 02 2000 14:47:12 by Szymon Stefanek
//
//   This file is part of the KVirc irc client distribution
//   Copyright (C) 1999-2002 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 <qobject.h>
#include <qasciidict.h>
#include "kvi_list.h"

class KviWindow;
class KviCommand;
class KviUserParser;
class KviDataContainer;
class KviExprTree;
class KviDns;
class KviParameterList;
class KviPopupMenu;
class KviStringArray;

typedef QAsciiDict<KviStr> KviDictionary;

#define KVI_DATA_TYPE_NONE 0
#define KVI_DATA_TYPE_VARIABLE 1
#define KVI_DATA_TYPE_DICTREFERENCE 2
#define KVI_DATA_TYPE_DICTVARIABLE 3
#define KVI_DATA_TYPE_DICTKEYSREFERENCE 4
#define KVI_DATA_TYPE_DICTITEMCOUNT 5
#define KVI_DATA_TYPE_ARRAYREFERENCE 6
#define KVI_DATA_TYPE_ARRAYVARIABLE 7
#define KVI_DATA_TYPE_ARRAYITEMCOUNT 8

typedef struct _KviDataType
{
	KviStr              szName; // dict or var name
	KviStr              szKey;  // dict key
	unsigned int        uIndex; // array index
	KviStr            * pVariable;
	KviDataContainer  * pDataContainer;
	KviDictionary     * pDictionary;
	KviStringArray    * pArray;
	int                 iDataType;
} KviDataType;

typedef bool (KviUserParser::*commandParseProc)(KviCommand *);

typedef bool (KviUserParser::*functionParseProc)(KviCommand *,KviParameterList *,KviStr &);

typedef struct _KviFunctionParseProc
{
	functionParseProc proc;
} KviFunctionParseProc;

typedef struct _KviCommandParserProc
{
	commandParseProc proc;
} KviCommandParseProc;

typedef struct _KviOperatorParseStruct
{
	KviDataType       * pDataType;
	KviStr              buffer;
	int                 iLeftOp;
	int                 iRightOp;
	KviDataType       * pRightDataType;
} KviOperatorParseStruct;

typedef struct _KviScriptObjectFunctionHandler KviScriptObjectFunctionHandler;


class KVIRC_API KviUserParser : public QObject
{
	friend class KviScriptObject;
	Q_OBJECT
public:
	KviUserParser();
	~KviUserParser();
private:
	QAsciiDict<KviCommandParseProc>   * m_pCommandExecDict;
	QAsciiDict<KviCommandParseProc>   * m_pCommandSkipDict;
	QAsciiDict<KviFunctionParseProc>  * m_pFunctionDict;
	KviDataContainer                  * m_pGlobalDataContainer;
	KviStr                              m_szEmptyString;
public:
	bool parseUserCommand(KviWStr &buffer,KviWindow * wnd);
	bool parseUserCommand(KviStr &buffer,KviWindow *wnd);
	// Transfers parameter ownership!!!
	bool parseCommandBuffer(char *,KviWindow *wnd,KviParameterList * params = 0);
	// public for modules (and for popupmenu)
	bool parseCmdFinalPart(KviCommand *c,KviStr &buffer);
	bool parseCmdSingleToken(KviCommand *c,KviStr &buffer);
	void skipComment(KviCommand *c);
	bool skipCommand(KviCommand *c);
	bool extractParameters(KviCommand *c,KviParameterList *paramList);
	bool extractFunctionParameters(KviCommand *c,KviParameterList * paramList);

	bool parseCmdUpTo(KviCommand *c,KviStr &buffer,char terminator);
	bool parseCommand(KviCommand *c);
	bool evaluateExpression(KviCommand *c,long * result,bool bExpectClosedParenthesis = true);
	void printError(KviCommand *c,bool bCallStackOnly = false,int * stackFrames = 0);
	bool parseCallbackCommand(KviCommand *c,KviParameterList * paramList,KviStr * cmd);
	KviDataContainer * globalDataContainer(){ return m_pGlobalDataContainer; };
	// returns true if have to stop output!
	bool triggerEvent(int index,KviWindow *wnd,KviParameterList * params,bool bTransferOwnership = true,bool bIsRaw = false);

	void completeModuleCommand(const KviStr &mod,const KviStr &cmd,KviPtrList<KviStr> * matches);
	void completeModuleFunction(const KviStr &mod,const KviStr &cmd,KviPtrList<KviStr> * matches);
	void completeCommand(const KviStr &cmd,KviPtrList<KviStr> * matches);
	void completeFunction(const KviStr &cmd,KviPtrList<KviStr> * matches);
protected:
	void initFunctionDict();
	void initCommandDict();

	// kvi_uparser.cpp
	bool parseCommandBlock(KviCommand *c);
	bool parseSingleCommand(KviCommand *c);
	bool parseLValueCommand(KviCommand *c);

	bool parseVariable(KviCommand *c,KviStr &buffer,KviDataType * d = 0,bool bIncludeLists = true);
	bool parseVariableKey(KviCommand *c,KviStr &buffer);
	bool parseVariableIndex(KviCommand *c,KviStr &buffer);
	bool lookupDataType(KviCommand *c,KviDataType *d);
	bool parseParameterIdentifier(KviCommand *c,KviStr &buffer);
	bool parseIdentifier(KviCommand *c,KviStr &buffer);
	bool parseFncSingleParam(KviCommand *c,KviParameterList * paramList,bool bSkipIdentAndVars = false);
//	bool parseFncSingleParamNoIdent(KviCommand *c,KviParameterList * paramList);


	bool buildPopupMenu(KviCommand *c,KviPopupMenu *p);

	bool callObjectFunction(KviScriptObjectFunctionHandler * h,
		KviParameterList * paramList,KviStr &buffer,KviCommand *c);

	bool extractSwitches(KviCommand *c);
	bool extractSingleSwitch(KviCommand *c);


	bool parseObjectFunction(KviCommand *c,KviStr &buffer);

	// kvi_up_oper.cpp
	bool parseOperator(KviCommand *c,KviDataType * d);
	bool parseOperatorAssignment(KviCommand *c,KviDataType * d);

	bool evaluateNumericLeftOperand(KviCommand *c,KviOperatorParseStruct *s,const char * oper);
	bool evaluateNumericRightOperand(KviCommand *c,KviOperatorParseStruct *s,const char * oper);
	bool parseOperatorIncrement(KviCommand *c,KviOperatorParseStruct *s);
	bool parseOperatorSelfAddition(KviCommand *c,KviOperatorParseStruct *s);
	bool parseOperatorDecrement(KviCommand *c,KviOperatorParseStruct *s);
	bool parseOperatorSelfSubtraction(KviCommand *c,KviOperatorParseStruct *s);
	bool parseOperatorSelfMultiply(KviCommand *c,KviOperatorParseStruct *s);
	bool parseOperatorSelfModulo(KviCommand *c,KviOperatorParseStruct *s);
	bool parseOperatorSelfOr(KviCommand *c,KviOperatorParseStruct *s);
	bool parseOperatorSelfAnd(KviCommand *c,KviOperatorParseStruct *s);
//	bool parseOperatorSelfNot(KviCommand *c,KviOperatorParseStruct *s);
	bool parseOperatorSelfDivide(KviCommand *c,KviOperatorParseStruct *s);
	bool parseOperatorAppendString(KviCommand *c,KviOperatorParseStruct *s);
	bool parseOperatorAppendToken(KviCommand *c,KviOperatorParseStruct *s);
	bool parseOperatorAppendList(KviCommand *c,KviOperatorParseStruct *s);

	bool parseOperatorSelfStringManipulate(KviCommand *c,KviDataType * d);
	bool executeOperatorSelfStringManipulate(KviCommand *c,KviStr * pVariable,char operation,const KviStr &szPar1,const KviStr &szPar2,const KviStr &szFlags);

	// kvi_up_expr.cpp
	KviExprTree * parseExpression(KviCommand *c);
	KviExprTree * parseExprOperand(KviCommand *c);
	KviExprTree * parseExprSimpleOperand(KviCommand *c);
	KviExprTree * parseExpression_RightOperand(KviExprTree * curTopOperator,KviCommand *c);
	KviExprTree * parseExprOperator(KviCommand *c);

	// kvi_up_skip.cpp
	bool skipCommandBlock(KviCommand *c);
	bool skipSingleCommand(KviCommand *c);
	bool skipLValueCommand(KviCommand *c,bool bStopAtParenthesis = false);
	bool skipForCondition(KviCommand *c);
	bool skipFor(KviCommand *c);

	bool skipSwitches(KviCommand *c);
	bool skipSingleSwitch(KviCommand *c);

	bool skipVariable(KviCommand *c);
	bool skipVariableKey(KviCommand *c);
	bool skipVariableIndex(KviCommand *c);

	bool skipExpressionBody(KviCommand *c);
	bool skipIdentifier(KviCommand *c);
	bool skipPopupBody(KviCommand *c);

	bool skipNormalCommand(KviCommand *c);
	bool skipCallbackCommand(KviCommand *c);
	bool skipClass(KviCommand *c);
	bool skipIf(KviCommand *c);
	bool skipDefpopup(KviCommand *c);
	bool skipSwitch(KviCommand *c);
	bool skipCaseLabel(KviCommand *c);
	bool skipDefaultLabel(KviCommand *c);
	bool skipIterationCommand(KviCommand *c);

	// kvi_up_cmd.cpp
	bool parseCmd_ECHO(KviCommand *c);
	bool parseCmd_HOST(KviCommand *c);
	bool parseCmd_QUERY(KviCommand *c);
	bool parseCmd_RAW(KviCommand *c);
	bool parseCmd_NICK(KviCommand *c);
	bool parseCmd_PRIVMSG(KviCommand *c);
	bool parseCmd_NOTICE(KviCommand *c);
	bool parseCmd_JOIN(KviCommand *c);
	bool parseCmd_PART(KviCommand *c);
	bool parseCmd_TOPIC(KviCommand *c);
	bool parseCmd_OP(KviCommand *c);
	bool parseCmd_DEOP(KviCommand *c);
	bool parseCmd_VOICE(KviCommand *c);
	bool parseCmd_DEVOICE(KviCommand *c);
	bool parseCmd_MODE(KviCommand *c);
	bool parseCmd_DELETE(KviCommand *c);
	bool parseCmd_PARSE(KviCommand *c);
	bool parseCmd_CLASS(KviCommand *c);
	bool parseCmd_PRIVATEIMPL(KviCommand *c);
	bool parseCmd_SETRETURN(KviCommand *c);
	bool parseCmd_IF(KviCommand *c);
	bool parseCmd_SRAND(KviCommand *c);
	bool parseCmd_SERVER(KviCommand *c);
	bool parseCmd_CONNECT(KviCommand *c);
	bool parseCmd_DISCONNECT(KviCommand *c);
	bool parseCmd_POPUP(KviCommand *c);
	bool parseCmd_DEFPOPUP(KviCommand *c);
	bool parseCmd_EVENT(KviCommand *c);
	bool parseCmd_EVENTCTL(KviCommand *c);
	bool parseCmd_BAN(KviCommand *c);
	bool parseCmd_UNBAN(KviCommand *c);
	bool parseCmd_ME(KviCommand *c);
	bool parseCmd_WHILE(KviCommand *c);
	bool parseCmd_CTCP(KviCommand *c);
	bool parseCmd_WHOIS(KviCommand *c);
	bool parseCmd_WHOWAS(KviCommand *c);
	bool parseCmd_AVATAR(KviCommand *c);
	bool parseCmd_AWHOIS(KviCommand *c);
	bool parseCmd_OPTION(KviCommand *c);
	bool parseCmd_ALIAS(KviCommand *c);
	bool parseCmd_HALT(KviCommand *c);
	bool parseCmd_KICK(KviCommand *c);
	bool parseCmd_RUN(KviCommand *c);
	bool parseCmd_PLAY(KviCommand *c);
	bool parseCmd_OPENURL(KviCommand *c);
	bool parseCmd_HELP(KviCommand *c);
	bool parseCmd_TIMER(KviCommand *c);
	bool parseCmd_KILLTIMER(KviCommand *c);
	bool parseCmd_BREAK(KviCommand *c);
	bool parseCmd_RAISE(KviCommand *c);
	bool parseCmd_ADDTARGET(KviCommand *c);
	bool parseCmd_DELTARGET(KviCommand *c);
	bool parseCmd_SWITCH(KviCommand *c);
	bool parseCmd_BUTTON(KviCommand *c);
	bool parseCmd_RFC2812WRAPPER(KviCommand *c);
	bool parseCmd_AWAY(KviCommand *c);
	bool parseCmd_BACK(KviCommand *c);
	bool parseCmd_QUIT(KviCommand *c);
	bool parseCmd_CLEAR(KviCommand *c);
	bool parseCmd_FOREACH(KviCommand *c);
	bool parseCmd_SOUND(KviCommand *c);
	bool parseCmd_PASS(KviCommand *c);
	bool parseCmd_SETMENU(KviCommand *c);
	bool parseCmd_BEEP(KviCommand *c);
	bool parseCmd_RETURN(KviCommand *c);
	bool parseCmd_KILLCLASS(KviCommand *c);
	bool parseCmd_CLEAROBJECTS(KviCommand *c);
	bool parseCmd_BUTTONCTL(KviCommand *c);
	bool parseCmd_THE(KviCommand * c);
	bool parseCmd_FOR(KviCommand * c);
	bool parseCmd_EVAL(KviCommand * c);
	bool parseCmd_SAY(KviCommand * c);
	bool parseCmd_EXEC(KviCommand * c);
	bool parseCmd_ECHOPRIVMSG(KviCommand * c);

	bool parseMultipleModeCommand(KviCommand *c,char plusminus,char flag);

	// kvi_up_fnc.cpp
	bool parseFnc_WINDOW(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_CHANNEL(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_QUERY(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_CONSOLE(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_CONTEXT(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_NEW(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_THIS(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_RAND(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_UNIXTIME(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_TIME(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_DATE(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_SELECTED(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_ISMEOP(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_SW(KviCommand *c,KviParameterList * params,KviStr &buffer);
	//bool parseFnc_STRFINDFIRST(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_TARGET(KviCommand *c,KviParameterList *params,KviStr &buffer);
	bool parseFnc_OPTION(KviCommand *c,KviParameterList *params,KviStr &buffer);
	bool parseFnc_MASK(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_AVATAR(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_ISTIMER(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_AWAY(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_ISWELLKNOWN(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_USERNAME(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_HOSTNAME(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_SERVER(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_FMTLINK(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_LF(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_CR(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_ASCII(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_CHAR(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_K(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_B(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_U(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_O(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_R(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_ME(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_ISANYCONSOLECONNECTED(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_BASE64TOASCII(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_HEXTOASCII(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_ACTIVE(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_ISMEVOICE(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_ISMEHALFOP(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_ISMEUSEROP(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_CLASSDEFINED(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_FEATURES(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_VERSION(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_SPLIT(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_ICON(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_ICONNAME(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool parseFnc_ISMAINWINDOWMINIMIZED(KviCommand *, KviParameterList *, KviStr &);
	bool parseFnc_MSGTYPE(KviCommand *c,KviParameterList *params,KviStr &buffer);
//	bool parseFnc_MATCH(KviCommand *c,KviParameterList * params,KviStr &buffer);
//	bool parseFnc_JOIN(KviCommand *c,KviParameterList * params,KviStr &buffer);
public slots:
	void parseCmd_HOST_dnsSlot(KviDns * dns);
};

extern KVIRC_API KviUserParser * g_pUserParser;

#endif //_KVI_UPARSER_H_
