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

              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 XMLSERIALIZERIMPL_H
#define XMLSERIALIZERIMPL_H

#include "XMLSerializer.h"
#include "XMLPullParser.h"

#include <string>
#include <stack>
#include <iostream>

#include <xercesc/util/XercesDefs.hpp>

#define DEFAULT_ENCODING "LATIN1"

namespace XERCES_CPP_NAMESPACE {
  class XMLFormatter;
  class XMLFormatTarget;
};

/** 
 * Implementation of the XMLSerializer interface.
 */
class XMLSerializerImpl: public virtual XMLSerializer {
  /// Xerces Output formatter.
  XERCES_CPP_NAMESPACE::XMLFormatter *formatter;
  
  /// Xerces format target.
  XERCES_CPP_NAMESPACE::XMLFormatTarget *target;

  /// True if formatter should be deallocated.
  bool isMyFormatter;

  /// True between calls to startDocument() and endDocument()
  bool started;

  /// True if the formatter is escaping certain XML special characters.
  bool escaping;

  /// True if pretty printing is turned on.
  bool prettyPrinting;

  /// The pretty printing tab size.
  int tabSize;

  /// If true elements with no children will be printed using the short form.
  bool shortFormAllowed;

  /// Stack of currently open elements.
  std::stack<std::string> elements;

  /// The type of the last event.
  event_t lastEvent;

public:
  /** 
   * Construct an XMLSerializerImpl.
   * 
   * @param out The output stream to print to.
   */
  XMLSerializerImpl(std::ostream &out) : started(false), escaping(true),
					 prettyPrinting(false),
					 tabSize(2), shortFormAllowed(true),
					 lastEvent(0)
  {createFormatter(out);}

  /** 
   * Construct an XMLSerializerImpl with Xerces XMLFormatter and
   * XMLFormatTarget.
   */
  XMLSerializerImpl(XERCES_CPP_NAMESPACE::XMLFormatter *formatter,
		    XERCES_CPP_NAMESPACE::XMLFormatTarget *target) :
    formatter(formatter), target(target), isMyFormatter(false), 
    started(false), escaping(true), prettyPrinting(false), 
    tabSize(2), shortFormAllowed(true), lastEvent(0) {}

  virtual ~XMLSerializerImpl() {destroyFormatter();}

  void setFormatter(XERCES_CPP_NAMESPACE::XMLFormatter *formatter) {
    destroyFormatter(); // Checks to see if formatter is ours
    this->formatter = formatter;
  }

  /// @return The current element depth.
  int getDepth() {return elements.size();}

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

  virtual void startDocument();
  virtual void startElement(const std::string qname, 
			    attributes_t &attributes);
  virtual void startElement(const std::string qname);
  virtual void characters(const std::string text);
  virtual void endElement();
  virtual void endDocument();
  virtual void comment(const std::string text);
  virtual void processingInstruction(const std::string target, 
				     const std::string data);

  virtual void flush();
  virtual void endl();
  virtual void setEscaping(const bool value) {escaping = value;}
  virtual bool isEscaping() {return escaping;}
  virtual void setPrettyPrinting(const bool value) {prettyPrinting = value;}
  virtual bool isPrettyPrinting() {return prettyPrinting;}
  virtual void setTabSize(const int size) {tabSize = size;}
  virtual int getTabSize() {return tabSize;}
  virtual bool isShortFormAllowed() {return shortFormAllowed;}
  virtual void setShortFormAllowed(const bool x) {shortFormAllowed = x;}
  // End XMLSerializer interface

 protected:
  /// Create a new XMLFormatter from the given ostream.
  void createFormatter(std::ostream &out);

  /// Delete the XMLFormatter if it is ours.
  void destroyFormatter();

  /// Print x * tabSize spaces to the output.
  void indent(const int x);

  /// Print a newline to the output.
  void newLine();
};

#endif
