/***************************************************************************
                          SIMPLY POWERFUL TOOLKIT (SPTK)
                          CXmlParser.h  -  description
                             -------------------
    begin                : Sun May 22 2003
    based on the code    : Mikko Lahteenmaki <Laza@Flashmail.com>
    copyright            : (C) 2003-2006 by Alexey S.Parshin
    email                : alexeyp@gmail.com
 ***************************************************************************/

/***************************************************************************
   This library is free software; you can redistribute it and/or modify it 
   under the terms of the GNU Library General Public License as published by
   the Free Software Foundation; either version 2 of the License, or (at 
   your option) any later version.

   This library 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 Library
   General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; if not, write to the Free Software Foundation, 
   Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.

   Please report all bugs and problems to "alexeyp@gmail.com"
 ***************************************************************************/

#ifndef _FL_XMLPARSER_H_
#define _FL_XMLPARSER_H_

#include "CXml.h"
#include "CXmlHandler.h"
#include "CXmlTokenizer.h"

namespace sptk {

   /// @addtogroup XML
   /// @{

	class CXmlNode;
	class CXmlDoc;

	typedef CXmlNode* CXmlNodePtr;  ///< CXmlNodePtr type definition

   /// @brief XML parser (internal).
   ///
   /// The parser is non-validating parser. It cannot handle external DTD's at all.
   /// Internal DTD's are partially handled, i.e. custom entities are parsed, though
   /// parameter entities are not supported. 
   /// Parser expands entitied during parsing, so entity reference nodes are not supported either.
   /// I.e. cdata/attributes stored to node or send to SAX handler, are already expanded.
	class CXmlParser {
		friend class CXmlTokenizer;

	public:
      /// Parses new XML/HTML document from stream. throws CXmlException on error.
      /// You can set own tokenizer, e.g. which reads data from net.
      /// @param doc CXmlDoc&, destination XML/HTML document. It's cleared before parse begins.
      /// @param tokenizer CXmlTokenizer &, stream for document data to parse.
      /// @param locator CXmlLocator *, locator for tokenizer. If error occurs, you can get position from here.
      /// @param htmlMode bool, document is parsed in HTML mode, for XML this should be always false.
		static void createDOM(CXmlDoc& doc,CXmlTokenizer &tokenizer, CXmlLocator *locator=0, bool htmlMode=false);

      /// Parses new XML/HTML document from stream. throws CXmlException on error.
      /// @param doc CXmlDoc&, destination XML/HTML document. It's cleared before parse begins.
      /// @param buffer CBuffer&, pointer to data for parse.
      /// @param locator CXmlLocator *, locator for tokenizer. If error occurs, you can get position from here.
      /// @param htmlMode bool, document is parsed in HTML mode, for XML this should be always false.
		static void createDOM(CXmlDoc& doc,const CBuffer& buffer, CXmlLocator *locator=0, bool htmlMode=false);

      /// Parse XML/HTML document in SAX mode. 
		/// This is good for large XML documents, where keeping nodes in memory
		/// would take too much memory. While parsing document, handler methods are called.
		/// @param handler CXmlHandler &, SAX handler to use catch events.
		/// @param tokenizer CXmlTokenizer &, stream for document data to parse.
		/// @param htmlMode bool, document is parsed in HTML mode, for XML this should be always false.
		/// @see CXmlHandler
		static bool createSAX(CXmlHandler &handler, CXmlTokenizer &tokenizer, bool htmlMode=false);

      /// Parse XML/HTML document in SAX mode. 
		/// This is good for large XML documents, where keeping nodes in memory
		/// would take too much memory. While parsing document, handler methods are called.
		/// @param handler CXmlHandler &, SAX handler to use catch events.
		/// @param buffer const CBuffer&, pointer to data for parse.
		/// @param htmlMode bool, document is parsed in HTML mode, for XML this should be always false.
		/// @see CXmlHandler
		static bool createSAX(CXmlHandler &handler, const CBuffer& buffer, bool htmlMode=false);

      /// Sets the SAX event handler. If handler is NULL, SAX events are ignored
		/// and nodes are stored to DOM tree.
		/// @param handler CXmlHandler *, event handler to set
		void handler(CXmlHandler *handler) { m_eventhandler = handler; }

      /// Returns current SAX event handler, NULL if none specific.
		CXmlHandler *handler() const { return m_eventhandler; }

	protected:
      /// Create new parser.
		/// @param tokenizer is used as stream tokenizer.
		CXmlParser(CXmlTokenizer &tokenizer);

      /// Parse subnodes until end-of-stream 
		bool parseDocument(CXmlDoc *doc);

      /// Parse doctype declaration 
		bool parseDocType(CXmlDocType *doc);

      /// Parse a node and its subnodes 
		bool parseNode(CXmlNode *parentNode, CXmlNodePtr& newNode);

      /// Parse an XML node attributes to attr 
		bool parseAttributes(CXmlDoc *doc, CXmlAttributes *attr);

      /// Parse a comment (<!-- -->) 
		bool parseComment(CXmlNode *parentNode,CXmlNodePtr& newNode);

      /// Turn HTML mode on/off
		void htmlMode(bool val) { m_htmlMode = val; }

      /// Return current mode of parser 
		bool htmlMode() const { return m_htmlMode; }

	private:

		CXmlTokenizer &tokenizer;         ///< Stream tokenizer
		CXmlHandler   *m_eventhandler;    ///< Event handler pointer

		bool        m_htmlMode;           ///< Html mode parsing flag
		bool        tag_end;              ///< Tag end flag
		int         force_ret;            ///< Force return
		std::string last_block;           ///< Last Block
		std::string parent_name;          ///< Parent name
	};	
   /// @}
}
#endif
