// Copyright (c) 2002 David Muse
// See the COPYING file for more information.

#ifndef RUDIMENTS_XMLDOMNODE_H
#define RUDIMENTS_XMLDOMNODE_H

#include <rudiments/private/xmldomnodeincludes.h>

// The xmldomnode class provides a generic container for DOM tree elements.
// One can navigate the nodes of the tree, modify the tree and read or modify
// the data that the nodes contain by calling methods in this class.
//
// A DOM tree node can be one of the following:
//      the document root
//      a tag 
//      a tag attribute
//      a segment of text
//      a comment
//      a segment of CDATA
//
// Each node may contain the following data, though for some node types, the
// data container is unused:
//      type
//      name
//      value
//      parent node
//      next sibling
//      previous sibling
//      a list of attribute nodes
//      a list of child nodes
//      
// Here is a breakdown by node type:
//
//      For the document root:
//              type - ROOT_XMLDOMNODETYPE
//              name - "document"
//              value - unused
//              parent node - unused
//              next sibling - unused
//              previous sibling - unused
//              a list of attribute nodes - unused
//              a list of child nodes - the xml version tag, the doctype tag
//                                      and the top-level enclosing tag
//
//      For a tag:
//              type - TAG_XMLDOMNODETYPE
//              name - the tag name
//              value - unused
//              parent node - the parent tag or document root
//              next sibling - can be another tag, a segment of text,
//                                       a comment or a segment of cdata
//              previous sibling - can be another tag, a segment of text,
//                                       a comment or a segment of cdata
//              a list of attribute nodes - a list of attribute nodes
//              a list of child nodes - a list of tags, text segments, comments
//                                      and/or cdata segments
//
//      For a tag attribute:
//              type - ATTRIBUTE_XMLDOMNODETYPE
//              name - the attribute name
//              value - the attribute value
//                  (note that for tags with standalone
//                  attributes, the name and value are the same)
//              parent node - the tag containing the attributes
//              next sibling - the next attribute
//              previous sibling - the previous attribute
//              a list of attribute nodes - unused
//              a list of child nodes - unused
//
//      For a segment of text:
//              type - TEXT_XMLDOMNODETYPE
//              name - "text"
//              value - the text itself
//              parent node - the tag containing the text
//              next sibling - can be a tag, a comment or a segment of cdata
//              previous sibling - can be a tag, a comment or a segment of cdata
//              a list of attribute nodes - unused
//              a list of child nodes - unused
//
//      For a comment:
//              type - COMMENT_XMLDOMNODETYPE
//              name - "comment"
//              value - the comment itself
//              parent node - the tag containing the comment
//              next sibling - can be a tag, a segment of text, another
//                              comment or a segment of cdata
//              previous sibling - can be a tag, a segment of text, another
//                              comment or a segment of cdata
//              a list of attribute nodes - unused
//              a list of child nodes - unused
//
//      For a segment of cdata:
//              type - CDATA_XMLDOMNODETYPE
//              name - "cdata"
//              value - the cdata itself
//              parent node - the tag containing the cdata
//              next sibling - can be a tag, a segment of text, a comment
//                              or another segment of cdata
//              previous sibling - can be a tag, a segment of text, a comment
//                              or another segment of cdata
//              a list of attribute nodes - unused
//              a list of child nodes - unused

#ifdef RUDIMENTS_NAMESPACE
namespace rudiments {
#endif

// node types
enum xmldomnodetype {
        NULL_XMLDOMNODETYPE=0,
        ROOT_XMLDOMNODETYPE,
        TAG_XMLDOMNODETYPE,
        ATTRIBUTE_XMLDOMNODETYPE,
        TEXT_XMLDOMNODETYPE,
        COMMENT_XMLDOMNODETYPE,
        CDATA_XMLDOMNODETYPE
};

class xmldom;
class xmldomnodeprivate;

class xmldomnode {
        public:
                        xmldomnode(xmldom *dom, xmldomnode *nullnode);
                                // Creates a new node and intializes its
                                // member variables to NULL.
                                //
                                // Your application should pass in a special
                                // "nullnode" which may be created by the
                                // static method createNullNode() below.
                                //
                                // This will keep command chaining like this:
                                //
                                // mynode->getChild("node1")->
                                //  getChild("node2")->getName("node3");
                                //
                                // from causing the program to crash trying to
                                // dereference a NULL pointer if, for example,
                                // "node2" doesn't exist.
                        xmldomnode(xmldom *dom,
                                        xmldomnode *nullnode,
                                        xmldomnodetype type,
                                        const char *name, const char *value);
                                // Creates a new node (as above) and intializes
                                // its member variables to the values passed in.
                        ~xmldomnode();
                                // Deletes the node, all attribute nodes and
                                // optionally all child nodes, recursively.



                static        xmldomnode      *createNullNode(xmldom *dom);
                                        // Creates a special "null node" whose
                                        // parent, next sibling and previous
                                        // siblings point back to itself.
                                        //
                                        // This special node should be passed
                                        // in when creating new xmldomnodes.
                                        //
                                        // This method allocates xmldomnode
                                        // internally and passes a pointer
                                        // back.  The calling program must
                                        // ultimately deallocate the node.


                // These methods control the behavior when the node is deleted.
                void          cascadeOnDelete();
                                // Instructs the destructor to recursively
                                // delete all child nodes. (the default)
                void          dontCascadeOnDelete();
                                // Instructs the destructor not to recursively
                                // delete all child nodes.


                // These methods provide read-access to the data
                // contained in the node.
                xmldomnodetype  getType() const;
                                // Returns the node type.
                const char    *getName() const;
                                // Returns the node name.
                const char    *getValue() const;
                                // Returns the node value.


                xmldomnode      *getParent() const;
                                // Returns a pointer to the parent node or the
                                // nullnode if none exists.
                xmldomnode      *getPreviousSibling() const;
                                // Returns a pointer to the previous sibling
                                // node or the nullnode if none exists.
                xmldomnode      *getPreviousTagSibling() const;
                                // Returns a pointer to the previous sibling
                                // node whose type is TAG_XMLDOMNODE.  If no
                                // match is found, nullnode is returned.
                xmldomnode      *getPreviousTagSibling(const char *name) const;
                                // Returns the previous sibling node named
                                // "name" whose type is TAG_XMLDOMNODE or the
                                // nullnode if not found.
                xmldomnode      *getPreviousTagSibling(const char *name,
                                        const char *attributename,
                                        const char *attributevalue) const;
                                // Returns the previous sibling node named
                                // "name" with an attribute named
                                // "attributename" with value "attributevalue"
                                // whose type is TAG_XMLDOMNODE.  If "name" is
                                // null, then the name of the child node is not
                                // checked, and the first child node with any
                                // name (with matching attribute name/value)
                                // will be returned.  If no match is found,
                                // nullnode is returned.
                xmldomnode      *getNextSibling() const;
                                // Returns a pointer to the next sibling node
                                // or the nullnode if none exists.
                xmldomnode      *getNextTagSibling() const;
                                // Returns a pointer to the next sibling node
                                // whose type is TAG_XMLDOMNODE.  If no match
                                // is found, nullnode is returned.
                xmldomnode      *getNextTagSibling(const char *name) const;
                                // Returns the next sibling node named "name"
                                // whose type is TAG_XMLDOMNODE or the nullnode
                                // if not found.
                xmldomnode      *getNextTagSibling(const char *name,
                                        const char *attributename,
                                        const char *attributevalue) const;
                                // Returns the next sibling node named "name"
                                // with an attribute named "attributename" with
                                // value "attributevalue" whose type is
                                // TAG_XMLDOMNODE.  If "name" is null,
                                // then the name of the child node is not
                                // checked, and the first child node with any
                                // name (with matching attribute name/value)
                                // will be returned.  If no match is found,
                                // nullnode is returned.


                int           getChildCount() const;
                                // Returns the number of immediate child nodes.
                xmldomnode      *getChild(const char *name) const;
                                // Returns the child node named "name"
                                // or the nullnode if not found.
                xmldomnode      *getChild(int position) const;
                                // Returns the child node at index "position"
                                // or the nullnode if not found.
                xmldomnode      *getChild(const char *name,
                                                const char *attributename,
                                                const char *attributevalue)
                                                const;
                                // Returns the first child node named "name"
                                // with an attribute named "attributename" with
                                // value "attributevalue".  If "name" is null,
                                // then the name of the child node is not
                                // checked, and the first child node with any
                                // name (with matching attribute name/value)
                                // will be returned.  If no match is found,
                                // nullnode is returned.
                xmldomnode      *getFirstTagChild() const;
                                // Returns the first child node whose type is
                                // TAG_XMLDOMNODE.  If no match is found,
                                // nullnode is returned.
                xmldomnode      *getFirstTagChild(const char *name) const;
                                // Returns the first child node named "name"
                                // whose type is TAG_XMLDOMNODE.  If no match
                                // is found, nullnode is returned.
                xmldomnode      *getFirstTagChild(const char *name,
                                                const char *attributename,
                                                const char *attributevalue)
                                                const;
                                // Returns the first child node named "name"
                                // with an attribute named "attributename" with
                                // value "attributevalue" whose type is
                                // TAG_XMLDOMNODE.  If "name" is null,
                                // then the name of the child node is not
                                // checked, and the first child node with any
                                // name (with matching attribute name/value)
                                // will be returned.  If no match is found,
                                // nullnode is returned.


                int           getAttributeCount() const;
                                // Returns the number of attributes.
                xmldomnode      *getAttribute(const char *name) const;
                                // Returns the attribute named "name"
                                // or the nullnode if not found.
                xmldomnode      *getAttribute(int position) const;
                                // Returns the attribute node at index
                                // "position" or the nullnode if not found.
                const char    *getAttributeValue(const char *name) const;
                                // Returns the value of the attribute named
                                // "name" or the nullnode if not found.
                const char    *getAttributeValue(int position) const;
                                // Returns the value of the attribute node at
                                // index "position" or the nullnode if not
                                // found.
                constnamevaluepairs     *getAttributes() const;
                                // Returns the attribute names and values in
                                // a constnamevaluepairs dictionary.  The
                                // instance of constnamevaluepairs is allocated
                                // internally and must be deleted by the
                                // calling program.  Returns NULL if the node
                                // is a nullNode and an empty dictionary if the
                                // node has no attributes.

                xmldomnode      *getNullNode() const;
                                // Returns the nullnode used by this node.
                bool          isNullNode() const;
                                // Returns true if this node is the special
                                // nullnode and false otherwise.


                // These methods provide write-access to the data contained in
                // the node.  These methods can also be used to move nodes
                // around in the tree, and insert or delete them.
                void  setType(xmldomnodetype type);
                        // Sets the node type to "type".
                void  setName(const char *name);
                        // Sets the node name to "name".
                void  setValue(const char *value);
                        // Sets the node value to "value".

                void  setParent(xmldomnode *parent);
                        // Sets the parent of the node to "parent".
                void  setPreviousSibling(xmldomnode *previous);
                        // Sets the previous sibling of the node to "previous".
                void  setNextSibling(xmldomnode *next);
                        // Sets the next sibling of the node to "next".

                bool  insertChild(xmldomnode *child, int position);
                        // Inserts "child" into the list of child nodes at
                        // "position".  The position of the next sibling
                        // (and all successive siblings) is incremented.
                bool  appendChild(xmldomnode *child);
                        // Appends "child" to the list of child nodes.
                bool  deleteChild(int position);
                        // Deletes the child node at "position".  The position
                        // of the next sibling (and all successive siblings)
                        // is decremented.
                bool  deleteChild(xmldomnode *child);
                        // Searches the list of child nodes for "child" and
                        // deletes it.  The position of the next sibling (and
                        // all successive siblings) is decremented.

                bool  insertText(const char *value, int position);
                        // Inserts a child node of type TEXT_XMLDOMNODE with
                        // value "value" into the list of child nodes at
                        // "position".  The position of the next sibling
                        // (and all successive siblings) is incremented.
                bool  appendText(const char *value);
                        // Appends a child node of type TEXT_XMLDOMNODE with
                        // value "value" to the list of child nodes.

                bool  insertAttribute(xmldomnode *attribute, int position);
                        // Inserts "attribute" into the list of attributes at
                        // "position".  The position of the next attribute
                        // (and all successive attributes) is incremented.
                bool  appendAttribute(xmldomnode *attribute);
                        // Appends "attribute" to the list of attributes.
                bool  insertAttribute(const char *name, const char *value,
                                        int position);
                        // Creates an attribute node with "name" and "value"
                        // and inserts it into the list of attributes at
                        // "position".  The position of the next attribute
                        // (and all successive attributes) is incremented.
                bool  appendAttribute(const char *name, const char *value);
                        // Creates an attribute node with "name" and "value"
                        // and appends it to the list of attributes.
                bool  deleteAttribute(int position);
                        // Deletes the attribute at "position".  The position
                        // of the next attribute (and all successive attributes)
                        // is decremented.
                bool  deleteAttribute(const char *name);
                        // Searches the list of attribute nodes for an attribute
                        // named "name" and deletes it.  The position of the
                        // next attribute (and all successive attributes) is
                        // decremented.
                bool  deleteAttribute(xmldomnode *attribute);
                        // Searches the list of attribute nodes for "attribute"
                        // and deletes it.  The position of the next attribute
                        // (and all successive attributes) is decremented.


                stringbuffer    *xml() const;
                                // Allocates a stringbuffer, writes a textual
                                // representation of the tree starting at this
                                // node to it and returns the stringbuffer;
                                // The calling program must deallocate the
                                // stringbuffer.

                stringbuffer    *getPath() const;
                                // If the xmldomnode is an element, returns the
                                // "path" of the xmldomnode.  The path will have
                                // the following form:
                                //
                                // /element[index]/element[index]/...
                                //
                                // The return value is allocated inside the
                                // method and must be deallocated by the calling
                                // program.
                xmldomnode      *getChildByPath(const char *path) const;
                                // Returns the child element with "path" of the
                                // form:
                                //
                                // /element[index]/element[index]/...
                                //
                                // Returns the null node if the specified
                                // element was not found.
                xmldomnode      *getAttributeByPath(const char *path,
                                                        int position) const;
                                // Returns the attribute node at index
                                // "position" of the child element with "path"
                                // of the form:
                                //
                                // /element[index]/element[index]/...
                                //
                                // Returns the null node if the specified
                                // element was not found.
                xmldomnode      *getAttributeByPath(const char *path,
                                                        const char *name) const;
                                // Returns the attribute node named "name"
                                // of the child element with "path" of the form:
                                //
                                // /element[index]/element[index]/...
                                //
                                // Returns the null node if the specified
                                // element was not found.
                const char    *getAttributeValueByPath(const char *path,
                                                        int position) const;
                                // Returns the value of the attribute at index
                                // "position" of the child element with "path"
                                // of the form:
                                //
                                // /element[index]/element[index]/...
                                //
                                // Returns the null node if the specified
                                // element was not found.
                const char    *getAttributeValueByPath(const char *path,
                                                        const char *name) const;
                                // Returns the value of the attribute named
                                // "name" of the child element with "path" of
                                // the form:
                                //
                                // /element[index]/element[index]/...
                                //
                                // Returns the null node if the specified
                                // element was not found.

        #include <rudiments/private/xmldomnode.h>
};

#ifdef RUDIMENTS_NAMESPACE
}
#endif

#endif