#ifndef _xbXML_
#define _xbXML_
/*<<<***************************************************************************
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: xbXml
#Project: xdcBase
////////////////////////////////////////////////////////////////////////////////
#Author: Marc MIRTI MANCINELLI
#History:
<15/09/2013: creation.
12/02/2014: this notice inserted.
***************************************************************************>>>*/

#ifndef _xbXMLITF_
#	include "xbXmlItf.h"
#endif

//Basic xml style parser without dtd support
class xbEXPORT xbXmlParser:public xbBase,public sIxbXmlSource
{
public:
	xbXmlParser()
	{
		m_bInit = false;
	}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(sIxbXmlSource);
		return xbBase::GetInterface(riid,ppInterf);
	}

	virtual void ParseStart(IxbXmlTarget *pTarget,LPCSTR pFileName,void *pData = NULL,ulong offsInFile = 0,int col = 0,int line = 1);
	virtual void Parse(const char *pStr,DWORD cByteCnt);
	virtual void ParseEnd(bool bOk = true);

	virtual xbString SectionAsText() const;

//methods of sIxbXmlSource
//	virtual void			SetTarget(IxbXmlTarget *pTarget) {checkInit();m_prTarget = pTarget;}
	virtual IxbXmlTarget	*GetTarget() const {checkInit();return m_prTarget;}

	virtual void			PushTarget(IxbXmlTarget *pTarget);
	virtual IxbXmlTarget	*PopTarget(IxbXmlTarget *pTarget,xbOpMode opm =xbOp_Required);

	virtual int				GetFlagCount() const {checkInit();return m_Flags.GetLength();}
	virtual bool			GetFlag(int no,xbXmlFlag *pFlg) const;
	virtual bool			EnumFlag(int &idx,xbXmlFlag *pFlg) const;
	virtual bool			EnumFlag(int &idx,xbXmlFlag **ppFlg) const;
	virtual bool			GetFlag(const xbString &name,xbXmlFlag *pFlg) const;
	virtual bool			GetFlagValue(const xbString &name,xbString *pValue,LPCSTR pDfltVal = NULL) const;
	virtual const xbXmlFlag	*GetFlagPtr(int no) const;
	virtual const xbXmlFlag	*GetFlagPtr(const xbString &name) const;

	virtual void			SetTextIgnore(bool bVal) {checkInit();m_bIgnoreText = bVal;}
	virtual void			SetTextTrim(bool bVal) {checkInit();m_bTrimText = bVal;}
	virtual void			SetSectIgnore(bool bVal)  {checkInit();m_bIgnoreSect = bVal;}

	virtual bool			GetTextIgnore() const {checkInit();return m_bIgnoreText;}
	virtual bool			GetTextTrim() const {checkInit();return m_bTrimText;}
	virtual bool			GetSectIgnore() const {checkInit();return m_bIgnoreSect;}
	virtual bool			IsSectComment() const {checkInit();return m_bInSectionComment;}

	virtual void			SetCaseSensitive(bool bVal) {checkInit();m_bCaseDep = bVal;}
	virtual int				Compare(const xbString &name1,const xbString &name2) const
	{
		checkInit();
		if (m_bCaseDep) return name1.Compare(name2);
		return name1.CompareNoCase(name2);
	}
	virtual int				Compare(const xbString &name1,const xbString &name2,int lg) const
	{
		checkInit();
		if (m_bCaseDep) return xbStrncmp(name1,name2,lg);
		return xbStrnicmp(name1,name2,lg);
	}

	virtual xbString		GetFlagStr(const xbString &name,LPCSTR pDfltVal = NULL) const
	{
		xbString ret;
		GetFlagValue(name,&ret,pDfltVal);
		return ret;
	}
	virtual long			GetFlagLong(const xbString &name,long dflt = 0) const
	{
		xbString ret;
		if (!GetFlagValue(name,&ret)) return dflt;
		long nb;
		::xbStrToLong(ret,&nb,0,NULL);
		return nb;
	}
	virtual bool			GetFlagLong(const xbString &name,long *pLong) const
	{
		xbString ret;
		if (!GetFlagValue(name,&ret)) return false;
		return ::xbStrToLong(ret,pLong,0,NULL)>0;
	}
	virtual bool			GetFlagBool(const xbString &name,bool dflt = false) const
	{
		xbString ret;
		if (!GetFlagValue(name,&ret)) return dflt;
		return xbStrToBool(ret);
	}
	virtual bool			GetFlagBool(const xbString &name,bool *pBool) const
	{
		const xbXmlFlag *pFlg = getFlag(name);
		if (!pFlg) return false;
		if (pFlg && !pFlg->m_bValue)
		{
			if (pBool) *pBool = true;
			return true;
		}
		if (pBool) *pBool = xbStrToBool(pFlg->GetUnescValue());
		return true;
	}
	virtual bool			GetFlagBool(const xbString &name,xbBool *pBool) const
	{
		const xbXmlFlag *pFlg = getFlag(name);
		if (!pFlg) return false;
		if (pFlg && !pFlg->m_bValue)
		{
			if (pBool) *pBool = true;
			return true;
		}
		if (pBool) pBool->Set(pFlg->GetUnescValue());
		return true;
	}
	virtual bool			GetFlagColor(const xbString &name,xbColor *pColor) const
	{
		xbString ret;
		if (!GetFlagValue(name,&ret)) return false;
		if (!pColor) return true;
		
		pColor->Set(ret);
		return true;
	}
	virtual void			*GetData() const
	{
		checkInit();
		return m_pData;
	}
	virtual void warning(const xbString &msg,const xbXmlPos &pos,LPCSTR pCtx = NULL)
	{
		warning(msg,pos.m_col,pos.m_line);
	}
	virtual void error(const xbString &msg,const xbXmlPos &pos,LPCSTR pCtx = NULL)
	{
		error(msg,pos.m_col,pos.m_line);
	}
	virtual void warning(const xbString &msg,int col = -1,int line = -1,LPCSTR pCtx = NULL);
	virtual void error(const xbString &msg,int col = -1,int line = -1,LPCSTR pCtx = NULL);
	virtual xbString GetFileName() const {return m_FileName;}
	virtual xbXmlPos GetCurrentPosition() const {return xbXmlPos(m_col,m_line,m_offsInFile,-1);}
	virtual bool xmlTolerance() {return false;}

	virtual void			SetTabSize(int val) {m_tabSize = val;}
	virtual int				GetTabSize() const {return m_tabSize;}
	virtual int				TabAlign(int col) const {return tabAlign(col);}
protected:
	void textFeed();
	void sectionFeed();
	void sectionClear();
	void flagFeed(bool bEnd);
	int tabAlign(int col) const;
public:
	inline void checkInit() const
	{
		if (!m_bInit) 
			xbThrow xbExmlParser("xbXmlParser::checkInit() : object not initialized : ParseStart() not called");
	}
	inline bool isInit() const
	{
		return m_bInit;
	}
protected:

	const xbXmlFlag *getFlag(const xbString &name) const;

	xbArray<xbXmlFlag>					m_Flags;
	xbRefPtr<IxbXmlTarget>				m_prTarget;
	xbArray< xbRefPtr<IxbXmlTarget> >	m_arrTarget;

	xbXmlPos		m_sectPos,m_txtPos;
	xbString		m_txt,m_sect;
	int				m_tabSize;
	bool			m_bInSection;			//< ... >
	bool			m_bInSectionComment;	//<!-- ... -->
	bool			m_bEndSect;
	bool			m_bSectTerminated;
	bool			m_bTxtLineStart;
	LPCSTR			m_pSectTextStart,m_pSectTextEnd;
	xbString		m_sectText;

	bool			m_bInFlag;				//<section flag1=...  flag2=... ...>
	xbXmlFlag		m_flag;

	int				m_cSpace;
	int				m_chInStr;
	bool			m_bEscInStr;

	bool			m_bIgnoreText,m_bIgnoreSect;
	bool			m_bTrimText;

	bool			m_bCaseDep;

	int				m_col,m_line;
	ulong			m_offsInFile;
	xbString		m_FileName;

	void			*m_pData;

	bool			m_bInit;

	inline void startPos(xbXmlPos *pPos) const
	{
		pPos->m_offsInFile = m_offsInFile - 1;
		pPos->m_col = m_col;
		pPos->m_line = m_line;
		pPos->m_lgInFile = 0;
	}
	inline void endPos(xbXmlPos *pPos) const
	{
		xbAssert(pPos->m_lgInFile >= 0);
		pPos->m_lgInFile = m_offsInFile - pPos->m_offsInFile;
		xbAssert(pPos->m_lgInFile >= 0);
	}
};

#endif
