/*
 *  Open BEAGLE
 *  Copyright (C) 2001-2004 by Christian Gagne and Marc Parizeau
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser 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
 *
 *  Contact:
 *  Laboratoire de Vision et Systemes Numeriques
 *  Departement de genie electrique et de genie informatique
 *  Universite Laval, Quebec, Canada, G1V 4J7
 *  http://vision.gel.ulaval.ca
 *
 */

/*!
 *  \file   beagle/XMLNode.hpp
 *  \brief  Definition of class XMLNode.
 *  \author Marc Parizeau
 *  \author Christian Gagne
 *  $Revision: 1.8 $
 *  $Date: 2004/04/08 14:49:34 $
 */

#ifndef Beagle_XMLNode_hpp
#define Beagle_XMLNode_hpp

#include <queue>
#include <map>

#include "beagle/config.hpp"
#include "beagle/macros.hpp"
#include "beagle/Object.hpp"
#include "beagle/AllocatorT.hpp"
#include "beagle/ContainerT.hpp"
#include "beagle/PointerT.hpp"
#include "beagle/Tokenizer.hpp"


namespace Beagle {

// Forward declaration
class XMLParser;
class XMLStreamer;


/*!
 *  \class XMLNode beagle/XMLNode.hpp "beagle/XMLNode.hpp"
 *  \brief XML parse tree node.
 *  \ingroup OOF
 *  \ingroup IO
 *  \note  This class is mostly based on class XML::Parser::Node of Marc Parizeau, with some
 *    minor modifications to comply with Open BEAGLE conventions.
 *
 *  A tree node can represent either XML tags or simple string content. An XML tag has a name which
 *  can be retrieved using member function Node::getTagName, and attribute values that can be fetched
 *  using member function Node::getTagAttribute. Tag content, including any embedded tags, is
 *  represented by child nodes. A Node can parse itself from a stream Tokenizer. The n-ary sub-tree
 *  structure is constructed using a classic pair of child and sibling linked lists of nodes. Any
 *  parse error throws an Beagle::IOException.
 *
 */
class XMLNode : public Object {

public:

  //! XMLNode allocator type.
  typedef AllocatorT< XMLNode, Object::Alloc >
          Alloc;
  //! XMLNode handle type.
  typedef PointerT< XMLNode, Object::Handle >
          Handle;
  //! XMLNode bag type.
  typedef ContainerT< XMLNode, Object::Bag >
          Bag;

  //! Types of parse tree node.
  enum Type {
    eDecl,     //!< Declarative tag ("<? ... ?>").
    eSpecial,  //!< Special tag ("<! ... >").
    eTag,      //!< Regular data tag.
    eString    //!< Simple string.
  };

  explicit XMLNode(Handle inChild=NULL, Handle inSibling=NULL);
           XMLNode(const XMLNode& inNode);
  virtual ~XMLNode();

  XMLNode& operator=(const XMLNode& inNode);

  static PointerT<XMLNode,Object::Handle>
    find(std::queue< PointerT<XMLNode,Object::Handle> >& ioQueue,
         std::string inValue, Type inType=eTag);
  PointerT<XMLNode,Object::Handle> find(std::string inValue, Type inType=eTag)const;
  std::string     getTagAttribute(std::string inName) const;
  void            insertFirstChild(PointerT<XMLNode,Object::Handle> inChild);
  void            insertNextSibling(PointerT<XMLNode,Object::Handle> inSibling);
  void            removeFirstChild();
  void            removeNextSibling();
  void            setTagAttribute(std::string inName, std::string inValue);
  void            setTagName(std::string inName);
  void            setType(Type inType);
  void            setValue(std::string inValue);
  void            serializeXML(XMLStreamer& outStream, bool inIndent=true) const;

  /*!
   *  \return Tag's first child node.
   */
  inline Handle getFirstChild() const
  {
    return mChild;
  }

  /*!
   *  \return Tag's next sibling node.
   */
  inline Handle getNextSibling() const
  {
    return mSibling;
  }

  /*!
   *  \return Constant reference to attribute map of XML node.
   */
  const std::map<std::string,std::string>& getAttributeMap() const
  {
    return mAttributes;
  }

  /*!
   *  \return Reference to attribute map of XML node.
   */
  std::map<std::string,std::string>& getAttributeMap()
  {
    return mAttributes;
  }
  
  /*!
   *  \return Tag name.
   *  \warning Valid only for tag nodes (\see XMLNode::getType).
   */
  inline std::string getTagName() const
  {
    return mValue;
  }

  /*!
   *  \return Node's type (\see enum XMLNode::Type).
   */
  inline Type getType() const
  {
    return mType;
  }

  /*!
   *  \return Node's value (same as Node::getTagName for tag nodes).
   */
  inline std::string getValue() const
  {
    return mValue;
  }

protected:

  static PointerT<XMLNode,Object::Handle> parse(Tokenizer& inTokenizer);
  void   parseAttributeList(Tokenizer& inTokenizer, std::string& outToken);
  void   parseStartTag(Tokenizer& inTokenizer, std::string& outToken);

  Type        mType;                    //!< Type of node.
  std::string mValue;                   //!< Value of node (either tag name or string content).
  std::map<std::string,std::string> mAttributes; //!< Map of node attributes (for tag nodes only).
  Handle      mChild;                   //!< First child node.
  Handle      mSibling;                 //!< Next sibling node.

  friend class Beagle::XMLParser;       //!< Parser class for simple XML documents is friend.
  
};

}

#endif // Beagle_XMLNode_hpp

