#ifndef _xbEXPR_
#define _xbEXPR_
/*<<<***************************************************************************
The MIT License (MIT)

Copyright(C) 2013 - 2015 Marc Mirti Mancinelli, Christophe Lardau and Philippe Pamart (xdcube.org)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
////////////////////////////////////////////////////////////////////////////////
#Title: xbExpr
#Project: xdcBase
////////////////////////////////////////////////////////////////////////////////
#Author: Marc MIRTI MANCINELLI
#History:
<15/09/2013: creation.
12/02/2014: this notice inserted.
***************************************************************************>>>*/

#ifndef _xbSTRING_
#	include "xbString.h"
#endif
#ifndef _xbPTR_
#	include "xbPtr.h"
#endif

class xbEXPORT xbExpr:public xbBase
{
public:
	enum ExprMode
	{
		Expr_F01=		0x00000001,
		Expr_F02=		0x00000002,
		Expr_F03=		0x00000004,
		Expr_F04=		0x00000008,
		Expr_F05=		0x00000010,
		Expr_F06=		0x00000020,
		Expr_F07=		0x00000040,
		Expr_F08=		0x00000080,

		Expr_CaseDep=	0x10000000,

		//Predefined modes
		Expr_All=		0x0000FFFF,
	};

	xbExpr(ExprMode dfltmode = Expr_All)
	{
		m_mode = ulong(dfltmode);
		m_searchType = 0;
	}

	bool	SearchExpr(const xbString &str,ulong mode);
	bool	SearchString(const xbString &str,ulong mode);
	bool	SearchSubString(const xbString &str,ulong mode);

	bool	SearchNext();

	struct Cond;
protected:
	//Events to override
	virtual bool onGetNext() = 0;
	virtual bool onKeysOk(const Cond *pCond,ulong mode) const = 0;
	virtual bool onFlagSet(bool bFirst,const xbString &str,int op,ulong *pmode) const = 0;

	struct CondKey
	{
		CondKey()
		{
			m_bStrStart = true;
			m_bStrEnd = true;
		}
		bool IsOk(const char *pStr,ulong mode,const char **ppStr) const;
	protected:
		void init()
		{
			m_bStrStart = true;
			m_bStrEnd = true;
			m_key.Empty();
		}
		bool						m_bStrStart;
		bool						m_bStrEnd;
		xbString					m_key;

		friend xbExpr;
		friend Cond;
	};
public:
	struct xbEXPORT Cond
	{
		Cond()
		{
			m_mode = 0;
			m_bOr = false;
			m_bNot = false;
		}

		bool IsKeyOk(const xbString &str,ulong mode) const; //to use in onKeysOk()

		bool IsOk(xbExpr *pExpr,ulong mode) const;
		bool IsKeysOk(xbExpr *pExpr,ulong mode) const;
		void Dump(int level) const;
	protected:
		void init()
		{
			m_mode = 0;
			m_bOr = false;
			m_bNot = false;
			m_keys.Clear();
			m_conds.Clear();
		}
		ulong						m_mode;
		xbArray<CondKey>			m_keys;

		bool						m_bOr;
		bool						m_bNot;
		xbPtrArray<Cond>			m_conds;

		friend xbExpr;
	private:
		Cond(const Cond &);
		Cond &operator=(const Cond &);
	};
	friend Cond;
protected:

	Cond		m_cond;
	ulong		m_mode;
	int			m_searchType;
	xbString	m_searchStr;

	//*cond*&*cond1*
	//*cond*(*cond1*|*cond2*)
	bool parseSearchExpr(const xbString &searchstr,ulong mode);
	void parseSearchExpr(Cond *pCond, ulong mode, const char **ppStr, char chStop);
	bool makeSearchString(const xbString &searchstr,ulong mode);
	bool makeSearchSubString(const xbString &searchstr,ulong mode);

private:
	xbExpr(const xbExpr &);
	xbExpr &operator=(const xbExpr &);
};

struct xbSubstExecSt;
interface sIxbSubst
{
	virtual bool onSubstVarExpand(xbSubstExecSt &ctx,const xbString &varName,xbString *pVarValue,const xbString &ctxOp,xbOpMode opm,bool bPointCall = false) = 0;
	virtual bool onSubstSubExpand(xbSubstExecSt &ctx,const xbString &subName,const xbArray<xbString> &arrArg,xbString *pVarValue,const xbString &ctxOp,xbOpMode opm,bool bPointCall = false) = 0;
	virtual bool onSubstOperation(xbSubstExecSt &ctx,const xbString &op,xbString &str) = 0;
	virtual bool onSubstOperationError(xbSubstExecSt &ctx,const xbString &op,xbEbase *pE) = 0;
	virtual bool onSubstExecute(xbSubstExecSt &ctx,const xbString &cmdName,const xbString &cmdArgs,bool bPointCall = false) = 0;
	virtual bool onSubstErrorTrace(xbSubstExecSt &ctx,xbEbase *pE,const xbString &token) = 0;
	virtual bool onSubstUrlExpand(xbSubstExecSt &ctx,const xbString &url,const xbString &urlLabel,const xbString &urlHint,xbString *pRet) = 0;
	virtual void onSubstSet(xbSubstExecSt &ctx,const xbString &varName,const xbString &varValue,bool bPointCall) = 0;
};

interface sIxbSubstTrace
{
	virtual void onSubstVarExpandTrace(IxbObject *pThis,const xbString &varName,bool bVarExists) = 0;
};

struct xbEXPORT xbSubstExecSt
{
	xbSubstExecSt()
	{
		m_urlEscCP = CP_UTF8;
		m_pCb = NULL;
		m_pCtx = NULL;
		m_pCbTrace = NULL;
		m_pFmt = NULL;
		m_bKeepFmt = true;
		m_pSepArg=NULL;
		m_pPrevCtx = NULL;
	}
	xbSubstExecSt(sIxbSubst *pCb,LPCSTR pFmt,LPCSTR pCtx,sIxbSubstTrace *pCbTrace,const xbString &cmds,LPCSTR pDfltFmt)
	{
		m_urlEscCP = CP_UTF8;
		m_pCb = pCb;
		m_pCtx = pCtx;
		m_pCbTrace = pCbTrace;
		m_cmds = cmds;
		if (!pFmt || xbStricmp(pFmt,"raw") == 0) 
		{
			m_pFmt = NULL;
			m_bKeepFmt = true;
		}
		else
		{
			m_pFmt = pFmt;
			m_bKeepFmt = false;
		}
		m_pSepArg=NULL;
		m_pPrevCtx = NULL;
		if (pDfltFmt && *pDfltFmt)
			m_currentFmt = pDfltFmt;
	}
	xbSubstExecSt(xbSubstExecSt *pExecSt,const xbString &cmds)
	{
		m_pCb = pExecSt->m_pCb;
		m_pCtx = pExecSt->m_pCtx;
		m_pCbTrace = pExecSt->m_pCbTrace;
		m_cmds = cmds;
		m_bKeepFmt = pExecSt->m_bKeepFmt;
		m_pFmt = pExecSt->m_pFmt;
//		m_currentFmt = pExecSt->m_currentFmt;
		m_pSepArg=NULL;
		m_pPrevCtx = pExecSt;
		m_urlEscCP=pExecSt->m_urlEscCP;
	}
	void substVarStart()
	{
		m_bEscape = true;
		m_escapeMode.Empty();
		m_tokenFmt.Empty();
		m_pSepArg=NULL;
	}
	xbString convert(const xbString &str,LPCSTR pSrcFmt = NULL);
	xbString escape(const xbString &str);

	sIxbSubst	*m_pCb;
	LPCSTR			m_pCtx;
	sIxbSubstTrace *m_pCbTrace;
	xbArray<bool>	m_arrCond;
	xbString		m_cmds;
	LPCSTR			m_pFmt;
	xbString		m_currentFmt;
	xbString		m_escapeMode,m_tokenFmt;
	bool			m_bEscape,m_bKeepFmt;
	LPCSTR			m_pSepArg;
	xbSubstExecSt	*m_pPrevCtx;
	ulong			m_urlEscCP;
	bool toExecute() const;
	void condPop();
	void condPush(bool bVal);
	void condInvert();
	bool isSubCall(const xbString &token,xbString *pSubName,xbString *pSubArgs);
	int getArgs(const xbString &strArg, xbArray<xbString> *pArray, LPCSTR pSeps);
	xbString getEctx(LPCSTR pStep, LPCSTR pToken = NULL);
	void throwError(const xbString &str);
	void close();
	bool ctxValid(const xbString &ctxOp);
	xbString subst(LPCSTR pFmt,const xbString &str,LPCSTR pFmtSrc = NULL);
};

xbEXPORT xbString xbSubstVar(sIxbSubst *pCb,LPCSTR pFmt,const xbString &str,LPCSTR pCtx,sIxbSubstTrace *pCbTrace = NULL,LPCSTR pDfltFmt = NULL);
xbEXPORT void xbSubstExec(sIxbSubst *pCb,const xbString &cmds,LPCSTR pCtx,sIxbSubstTrace *pCbTrace = NULL,bool bSubst = true);
xbEXPORT void xbSubstExec(xbSubstExecSt &ctx,const xbString &cmds,bool bSubst);

xbEXPORT xbString xbSubstVar(xbSubstExecSt &ctx,const xbString &str);
xbEXPORT bool xbSubstVarExpand(xbSubstExecSt &ctx,xbString &token,const xbString &ctxOp,const xbString &substOp);
xbEXPORT void xbSubstOperation(xbSubstExecSt &ctx,xbString &str,const xbArray<xbString> &arrArg);
xbEXPORT bool xbSubstOperationError(xbSubstExecSt &ctx,xbEbase *pE,const xbArray<xbString> &arrArg);
xbEXPORT bool xbSubstExecCmd(xbSubstExecSt &ctx,const xbString &cmdName,const xbString &cmdArgs);
xbEXPORT bool xbSubstBoolEval(xbSubstExecSt &ctx,const xbString &expr);
xbEXPORT bool xbSubstBoolEval_And(xbSubstExecSt &ctx,const xbString &expr);
xbEXPORT bool xbSubstBoolEval_Operator(xbSubstExecSt &ctx,const xbString &expr);
xbEXPORT xbString xbSubstBoolEval_Operand(xbSubstExecSt &ctx,const xbString &expr,xbOpMode opm =xbOp_Required);
xbEXPORT int xbSubstBoolEval_Compare(const xbString &ret1,const xbString &ret2);
xbEXPORT xbString xbSubstEscape(const xbString &str);
xbEXPORT xbString xbSubstEscape2(const xbString &str);

xbEXPORT xbString xbHtmlRemove(const xbString &str,int maxChar,bool keepSimpleHtml,bool keepLine);

xbEXPORT xbString xbSubstFmt(LPCSTR pFmt,const xbString &str,LPCSTR pDfltFmt = NULL,sIxbSubst *pCb = NULL);
xbEXPORT xbString xbSubstNoFmt(LPCSTR pFmt,const xbString &str,LPCSTR pDfltFmt = NULL);


struct xbEXPORT xbSubstForException:public sIxbSubst
{
	xbSubstForException(const xbEbase *pE)
	{
		m_pE = pE;
	}
	virtual bool onSubstVarExpand(xbSubstExecSt &ctx,const xbString &varName,xbString *pVarValue,const xbString &ctxOp,xbOpMode opm,bool bPointCall = false);
	virtual bool onSubstSubExpand(xbSubstExecSt &ctx,const xbString &subName,const xbArray<xbString> &arrArg,xbString *pVarValue,const xbString &ctxOp,xbOpMode opm,bool bPointCall = false)
	{
		return false;
	}
	virtual bool onSubstOperation(xbSubstExecSt &ctx,const xbString &op,xbString &str)
	{
		return false;
	}
	virtual bool onSubstOperationError(xbSubstExecSt &ctx,const xbString &op,xbEbase *pE)
	{
		return false;
	}
	virtual bool onSubstExecute(xbSubstExecSt &ctx,const xbString &cmdName,const xbString &cmdArgs,bool bPointCall = false)
	{
		return false;
	}
	virtual bool onSubstErrorTrace(xbSubstExecSt &ctx,xbEbase *pE,const xbString &token)
	{
		return true;
	}
	virtual bool onSubstUrlExpand(xbSubstExecSt &ctx,const xbString &url,const xbString &urlLabel,const xbString &urlHint,xbString *pRet);
	virtual void onSubstSet(xbSubstExecSt &ctx,const xbString &varName,const xbString &varValue,bool bPointCall)
	{
	}

	const xbEbase *m_pE;
};

#endif
