/*******************************************************************\

              Copyright (C) 2003 Joseph Coffland

    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 option) 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.

            For information regarding this software email
                   jcofflan@users.sourceforge.net

\*******************************************************************/


#ifndef XMLPULLPARSERIMPL_H
#define XMLPULLPARSERIMPL_H

#include "XMLPullParser.h"
#include "XMLParseEvent.h"

#include <string>
#include <iostream>
#include <list>

#include <xercesc/util/XercesDefs.hpp>
#include <xercesc/framework/XMLPScanToken.hpp>
#include <xercesc/sax2/ContentHandler.hpp>

#include <XercesUtils/BasicErrorHandler.h>

namespace XERCES_CPP_NAMESPACE {
  class SAX2XMLReader;
  class Locator;
  class Attributes;
  class SAXParserException;
  class InputSource;
};

/**
 * The default implementation of the XMLPullParser interface.
 *
 * Implemented on top of Xerces C++.
 * See http://xml.apache.org/xerces-c/index.html
 */
class XMLPullParserImpl: public XMLPullParser, 
			 public XERCES_CPP_NAMESPACE::ContentHandler {
  /// Xerces C++ parser
  XERCES_CPP_NAMESPACE::SAX2XMLReader *parser;

  /// Incremental parse token.
  XERCES_CPP_NAMESPACE::XMLPScanToken token;

  /// A Xerces error handler.
  BasicErrorHandler errorHandler;

  /**
   * Tracks where we are in the XML document.  This is not always in sink with
   * the current parse event.
   */  
  const XERCES_CPP_NAMESPACE::Locator *locator;

  /// The current XML element depth.
  int depth;

  /// True if we are in the process of parsing XML.
  bool inParse;

  /// The global parse event mask.
  event_t globalMask;

  /// The parse event queue type declaration.
  typedef std::list<XMLParseEvent *> eventQueue_t;

  /// The parse event queue.
  eventQueue_t eventQueue;

  /// The current parse event.
  XMLParseEvent *currentEvent;


public:
  XMLPullParserImpl();
  virtual ~XMLPullParserImpl();

protected:
  /// Allocate a new parser.
  void createParser();
  
  /// Empty the event queue.
  void clearEvents();

  /// Reset the parser state.
  void reset();

  /// Push an event on the event queue.
  void pushEvent(XMLParseEvent *event) {eventQueue.push_back(event);}

  /// Parse more data to get more events.
  void pumpEvents();

public:

  /** 
   * Initialize the parser with a Xerces C++ InputSource.
   * 
   * @param in The input source.
   */
  virtual void initParse(const XERCES_CPP_NAMESPACE::InputSource &in);

  /** 
   * @return The Xerces C++ SAX2XMLReader.
   */
  XERCES_CPP_NAMESPACE::SAX2XMLReader *getParser() {return parser;}

  // Begin XMLPullParser interface
  virtual void deserialize(const std::string targetNamespace,
			   const std::string topElementName,
			   XMLSerializable &serializable);

  virtual BasicFileLocation getLocation();
  virtual int getDepth() {return depth;}
  virtual int getLineNumber();
  virtual int getColumnNumber();
  virtual unsigned int getNumAttributes();
  virtual const XMLAttrib &getAttribute(const unsigned int index);
  virtual const XMLAttrib &getAttribute(const std::string name,
					const std::string uri = "");
  virtual int findAttribute(const std::string name,
			    const std::string uri = "");
  virtual std::string getName();
  virtual std::string getNamespace();
  virtual std::string getPrefix();
  virtual std::string getText();
  virtual void assertName(const std::string name);
  virtual void assertNamespace(const std::string uri);
  virtual bool isWhitespace();
  virtual bool isEmptyElementTag();
  virtual void skip(event_t mask);
  virtual event_t next();
  virtual event_t next(event_t mask);
  virtual event_t getEventType();

  /**
   * See http://xml.apache.org/xerces-c/program-sax.html#SAXFeatures
   * for a list of supported features.
   */
  virtual void setFeature(const std::string name, bool state);

  /**
   * See http://xml.apache.org/xerces-c/program-sax.html#SAXFeatures
   * for a list of supported features.
   */
  virtual bool getFeature(const std::string name);
  virtual void *getProperty(const std::string name);
  virtual void setProperty(const std::string name, void *value);
  virtual bool check(event_t event) {return event == getEventType();}
  virtual void assertEvent(event_t event, const std::string msg = "");
  virtual void match(event_t event, const std::string msg = "");
  virtual void match(event_t event, event_t mask, std::string msg = "");
  virtual std::string matchSimple();

  virtual void resetParser();
  virtual void initParse(std::istream &in);
  virtual void initParse(const std::string filename);
  virtual void preparseSchema(std::istream &schema);

  virtual void setEventMask(event_t mask) {globalMask = ANY_EVENT & mask;}
  virtual event_t getEventMask() {return globalMask;}
  // End XMLPullParser interface


  // Start Xerces ContentHandler interface
  /// See http://xml.apache.org/xerces-c/apiDocs/classContentHandler.html
  virtual void characters(const XMLCh *const chars,
			  const unsigned int length);

  /// See http://xml.apache.org/xerces-c/apiDocs/classContentHandler.html
  virtual void endDocument();

  /// See http://xml.apache.org/xerces-c/apiDocs/classContentHandler.html
  virtual void endElement(const XMLCh *const uri,
			  const XMLCh *const localname,
			  const XMLCh *const qname);

  /// See http://xml.apache.org/xerces-c/apiDocs/classContentHandler.html
  virtual void ignorableWhitespace(const XMLCh *const chars,
				   const unsigned int length)
  {characters(chars, length);}

  /// See http://xml.apache.org/xerces-c/apiDocs/classContentHandler.html
  virtual void processingInstruction(const XMLCh *const target,
				     const XMLCh *const data);

  /// See http://xml.apache.org/xerces-c/apiDocs/classContentHandler.html
  virtual void setDocumentLocator
  (const XERCES_CPP_NAMESPACE::Locator *const locator)
  {this->locator = locator;}

  /// See http://xml.apache.org/xerces-c/apiDocs/classContentHandler.html
  virtual void startDocument();

  /// See http://xml.apache.org/xerces-c/apiDocs/classContentHandler.html
  virtual void startElement(const XMLCh *const uri,
			    const XMLCh *const localname,
			    const XMLCh *const qname,
			    const XERCES_CPP_NAMESPACE::Attributes &attrs);

  /// See http://xml.apache.org/xerces-c/apiDocs/classContentHandler.html
  virtual void startPrefixMapping(const XMLCh *const prefix,
				  const XMLCh *const uri);

  /// See http://xml.apache.org/xerces-c/apiDocs/classContentHandler.html
  virtual void endPrefixMapping(const XMLCh *const prefix);

  /// See http://xml.apache.org/xerces-c/apiDocs/classContentHandler.html
  virtual void skippedEntity(const XMLCh *const name);
  // End Xerces ContentHandler interface
};

#endif
