/**
 * Phoebe DOM Implementation.
 *
 * This is a C++ approximation of the W3C DOM model, which follows
 * fairly closely the specifications in the various .idl files, copies of
 * which are provided for reference.  Most important is this one:
 *
 * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/idl-definitions.html
 *
 * Authors:
 *   Bob Jamison
 *
 * Copyright (C) 2005 Bob Jamison
 *
 *  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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */


#include "domimpl.h"

namespace org
{
namespace w3c
{
namespace dom
{


/**
 *  Test if the given substring exists for the length of the string
 *  in a given buffer
 */
/*
static bool match(const DOMString &buf, char *str)
{
    int pos = 0;
    while (*str)
       {
       if (buf[pos++] != *str++)
           return false;
       }
   return true;
}
*/



/*#########################################################################
## DOMImplementationSourceImpl
#########################################################################*/


/**
 *
 */
DOMImplementationSourceImpl::DOMImplementationSourceImpl()
{
    domImpl     = new DOMImplementationImpl();
}

/**
 *
 */
DOMImplementationSourceImpl::~DOMImplementationSourceImpl()
{
    delete domImpl;
}

/**
 *
 */
DOMImplementation *DOMImplementationSourceImpl::getDOMImplementation(
                           const DOMString &features)
{
    return domImpl;
}

/**
 *
 */
DOMImplementationList DOMImplementationSourceImpl::getDOMImplementationList(
                           const DOMString &features)
{
    return domImplList;
}







/*#########################################################################
## DOMImplementationImpl
#########################################################################*/


/**
 *
 */
DOMImplementationImpl::DOMImplementationImpl()
{
}

/**
 *
 */
DOMImplementationImpl::~DOMImplementationImpl()
{
}

/**
 *
 */
bool DOMImplementationImpl::hasFeature(const DOMString& feature,
                        const DOMString& version)
{
    return false;
}


/**
 *
 */
DocumentTypePtr DOMImplementationImpl::createDocumentType(const DOMString& qualifiedName,
                                 const DOMString& publicId,
                                 const DOMString& systemId)
                                 throw(DOMException)
{
    DocumentTypePtr typeImpl = new DocumentTypeImpl(qualifiedName,
                                         publicId, systemId);
    return typeImpl;
}

/**
 *
 */
DocumentPtr DOMImplementationImpl::createDocument(
                         const DOMString& namespaceURI,
                         const DOMString& qualifiedName,
                         DocumentTypePtr  doctype)
                         throw(DOMException)
{
    DocumentPtr doc = new DocumentImpl(this,
                                       namespaceURI,
                                       qualifiedName,
                                       doctype);
    return doc;
}

/**
 *
 */
DOMObject *DOMImplementationImpl::getFeature(const DOMString& feature,
                         const DOMString& version)

{
    return NULL;
}





/*#########################################################################
## NodeImpl
#########################################################################*/

/**
 * Utility for finding the first Element above
 * a given node.  Used by several methods below
 */
static NodePtr getAncestorElement(NodePtr node)
{
    if (!node.get())
        return NULL;
    node = node->getParentNode();
    //Either quit because I am an element, or because I am null
    while (node.get())
        {
        if (node->getNodeType() == Node::ELEMENT_NODE)
            return node;
        node = node->getParentNode();
        }
    return node;
}

/**
 *
 */
DOMString NodeImpl::getNodeName()
{
    return nodeName;
}

/**
 *
 */
DOMString NodeImpl::getNodeValue() throw (DOMException)
{
    return nodeValue;
}

/**
 *
 */
void NodeImpl::setNodeValue(const DOMString& val) throw (DOMException)
{
    nodeValue = val;
}

/**
 *
 */
unsigned short NodeImpl::getNodeType()
{
    return nodeType;
}

/**
 *
 */
NodePtr NodeImpl::getParentNode()
{
    return parent;
}

/**
 *
 */
NodeList NodeImpl::getChildNodes()
{
    NodeList list;
    for (NodeImplPtr node = firstChild ; node.get() ; node=node->next)
        list.add(node);
    return list;
}

/**
 *
 */
NodePtr NodeImpl::getFirstChild()
{
    return firstChild;
}

/**
 *
 */
NodePtr NodeImpl::getLastChild()
{
    return lastChild;
}

/**
 *
 */
NodePtr NodeImpl::getPreviousSibling()
{
    return prev;
}

/**
 *
 */
NodePtr NodeImpl::getNextSibling()
{
    return next;
}

/**
 *
 */
NamedNodeMap &NodeImpl::getAttributes()
{
    NamedNodeMap &attrs = attributes;
    return attrs;
}


/**
 *
 */
DocumentPtr NodeImpl::getOwnerDocument()
{
    return ownerDocument;
}

/**
 *
 */
NodePtr NodeImpl::insertBefore(const NodePtr newChild,
                               const NodePtr refChild)
                               throw(DOMException)
{
    if (!newChild)
        return NULL;
        
    //if no ref, then just append
    if (!refChild)
        return appendChild(newChild);

    NodeImplPtr newChildImpl = dynamic_cast<NodeImpl *>(newChild.get());
    for (NodeImplPtr n = firstChild ; n.get() ; n=n->next)
        {
        if (n == refChild)
            {
            //link to new
            if (n->prev.get())
                n->prev->next = newChildImpl;
            else
                firstChild = newChildImpl;
            n->prev = newChildImpl;
            //link from new
            newChildImpl->next = n;
            newChildImpl->prev = n->prev;
            //reflect new location
            newChildImpl->parent        = this;
            newChildImpl->ownerDocument = ownerDocument;
            return n;
            }
        }
    return NULL;
}

/**
 *
 */
NodePtr NodeImpl::replaceChild(const NodePtr newChild,
                               const NodePtr oldChild)
                               throw(DOMException)
{
    if (!oldChild)
        return NULL;

    NodeImplPtr newChildImpl = dynamic_cast<NodeImpl *>(newChild.get());
    for (NodeImplPtr n = firstChild ; n.get() ; n=n->next)
        {
        if (n == oldChild)
            {
            //link to new
            if (n->prev.get())
                n->prev->next = newChildImpl;
            else
                firstChild = newChildImpl;
            if (n->next.get())
                n->next->prev = newChildImpl;
            else
                lastChild = newChildImpl;
            //link from new
            newChildImpl->next = n->next;
            newChildImpl->prev = n->prev;
            //reflect new location
            newChildImpl->parent        = this;
            newChildImpl->ownerDocument = ownerDocument;
            return n;
            }
        }
    return NULL;
}

/**
 *
 */
NodePtr NodeImpl::removeChild(const NodePtr oldChild)
                              throw(DOMException)
{
    if (!oldChild)
        return NULL;

    for (NodeImplPtr n = firstChild ; n.get() ; n=n->next)
        {
        if (n == oldChild)
            {
            if (n->prev.get())
                n->prev->next = n->next;
            if (n->next.get())
                n->next->prev = n->prev;
            return n;
            }
        }
    return NULL;
}

/**
 *
 */
NodePtr NodeImpl::appendChild(const NodePtr newChild)
                             throw(DOMException)
{
    if (!newChild)
        return NULL;

    NodeImplPtr newChildImpl =
	     dynamic_cast<NodeImpl *> (newChild.get());

    newChildImpl->parent        = this;
    newChildImpl->ownerDocument = ownerDocument;

    if (!firstChild || !lastChild)
        {
        //Set up our first member
        firstChild = newChildImpl;
        lastChild  = newChildImpl;
        }
    else
        {
        //link at the last position
        lastChild->next    = newChildImpl;
        newChildImpl->prev = lastChild;
        lastChild          = newChildImpl;
        }

    return newChild;
}

/**
 *
 */
bool NodeImpl::hasChildNodes()
{
    return (firstChild != (NodeImpl *)0);
}

/**
 *
 */
NodePtr NodeImpl::cloneNode(bool deep)
{
    NodeImplPtr node    = new NodeImpl(ownerDocument, nodeName);
    node->parent        = parent;
    node->prev          = prev;
    node->next          = next;
    node->userData      = userData;
    node->nodeValue     = nodeValue;

    if (deep)
        {
        node->firstChild = node->lastChild = NULL;
        for (NodeImplPtr child = firstChild ; child.get() ; child=child->next)
            {
            node->appendChild(child->cloneNode(deep));
            }
        }
    else
        {
        node->firstChild = firstChild;
        node->lastChild  = lastChild;
        }

    return node;
}

/**
 *  Concatenate adjoining text subnodes, remove null-length nodes
 */
void NodeImpl::normalize()
{
    //First, concatenate adjoining text nodes
    NodeImplPtr next = (NodeImpl *)0;
    for (NodeImplPtr child = firstChild ; child.get() ; child=next)
        {
        if (child->getNodeType() != Node::TEXT_NODE)
            continue;
        next = NULL;
        DOMString sval = child->getNodeValue();
        for (NodeImplPtr sibling = child->next ; sibling.get() ; sibling=next)
            {
            next = sibling->next;
            if (sibling->getNodeType() != Node::TEXT_NODE)
                break;
            sval.append(sibling->getNodeValue());
            //unlink and delete
            child->next = sibling->next;
            if (sibling->next.get())
                sibling->next->prev = child;
            //delete sibling;
            }
        child->setNodeValue(sval);
        }

    //Next, we remove zero-length text subnodes
    next = NULL;
    for (NodeImplPtr child = firstChild ; child.get() ; child=next)
        {
        next = child->next;
        if (child->getNodeType() != Node::TEXT_NODE)
            continue;
        if (child->getNodeValue().size() == 0)
            {
            //unlink and delete
            if (child->prev.get())
                child->prev->next = child->next;
            if (child->next.get())
                child->next->prev = child->prev;
            //delete child;
            }
        }

}

/**
 *
 */
bool NodeImpl::isSupported(const DOMString& feature,
                           const DOMString& version)
{
    //again, no idea
    return false;
}

/**
 *
 */
DOMString NodeImpl::getNamespaceURI()
{
    return namespaceURI;
}

/**
 *
 */
DOMString NodeImpl::getPrefix()
{
    return prefix;
}

/**
 *
 */
void NodeImpl::setPrefix(const DOMString& val) throw(DOMException)
{
    prefix = val;
    if (prefix.size()>0)
        nodeName = prefix + ":" + localName;
    else
        nodeName = localName;
}

/**
 *
 */
DOMString NodeImpl::getLocalName()
{
    return localName;
}

/**
 *
 */
bool NodeImpl::hasAttributes()
{
    return (attributes.getLength() > 0);
}

/**
 *
 */
DOMString NodeImpl::getBaseURI()
{
    return baseURI;
}

/**
 *
 */
unsigned short NodeImpl::compareDocumentPosition(const NodePtr otherArg)
{
    if (!otherArg || otherArg == (NodePtr )this)
        return 0;//no flags

    NodePtr node;
    NodePtr other = otherArg;

    //Look above me
    for (node=getParentNode() ; node.get() ; node=node->getParentNode())
        if (node == other)
            return DOCUMENT_POSITION_CONTAINED_BY;

    //Look above the other guy. See me?
    for (node=other->getParentNode() ; node.get() ; node=node->getParentNode())
        if (node == (NodePtr )this)
            return DOCUMENT_POSITION_CONTAINS;


    return DOCUMENT_POSITION_DISCONNECTED |
           DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
}

/**
 *
 */
DOMString NodeImpl::getTextContent() throw(DOMException)
{
    DOMString buf;
    if (nodeType == TEXT_NODE          ||
	    nodeType == CDATA_SECTION_NODE ||
		nodeType == COMMENT_NODE       ||
		nodeType == PROCESSING_INSTRUCTION_NODE)
		buf = getNodeValue();
    else if (nodeType == ELEMENT_NODE      ||
	         nodeType == ATTRIBUTE_NODE         ||
		     nodeType == ENTITY_NODE            ||
		     nodeType == ENTITY_REFERENCE_NODE  ||
		     nodeType == DOCUMENT_FRAGMENT_NODE)
		{
		for (NodePtr n = getFirstChild() ; n.get() ;
		     n=n->getNextSibling() )
		    {
            if (n->getNodeType() != COMMENT_NODE &&
		        n->getNodeType() != COMMENT_NODE)
                buf.append(n->getTextContent());
		    }
		}
    return buf;
}


/**
 *
 */
void NodeImpl::setTextContent(const DOMString &val) throw(DOMException)
{
    //Delete children
    /** Not necessary.  Just let smart pointers to their work
	for (NodePtr n = getFirstChild() ; n.get() ;
		           n=n->getNextSibling() )
        delete n;
    */
    firstChild = lastChild = NULL;

    //Replace with a single text node
    NodeImplPtr tnode = new NodeImpl(ownerDocument);
    tnode->nodeType = Node::TEXT_NODE;
    tnode->setNodeValue(val);
    appendChild(tnode);
}


/**
 * From DOM3 Namespace algorithms
 */
DOMString NodeImpl::lookupPrefix(const DOMString &theNamespaceURI)
{

    if (theNamespaceURI.size()==0)
        {
        return DOMString("");
        }

    switch (nodeType)
        {
        case Node::ELEMENT_NODE:
            {
            ElementPtr elem = (Element *)this;
            return lookupNamespacePrefix(theNamespaceURI, elem);
            }
        case Node::DOCUMENT_NODE:
            {
            DocumentPtr doc = (Document *)this;
            ElementPtr elem = doc->getDocumentElement();
            return elem->lookupPrefix(theNamespaceURI);
            }
        case Node::ENTITY_NODE :
        case Node::NOTATION_NODE:
        case Node::DOCUMENT_FRAGMENT_NODE:
        case Node::DOCUMENT_TYPE_NODE:
            return DOMString("");  // type is unknown
        case Node::ATTRIBUTE_NODE:
            {
            AttrPtr attr = (Attr *)this;
            ElementPtr elem = attr->getOwnerElement();
            if ( elem.get() )
                {
                return elem->lookupPrefix(theNamespaceURI);
                }
             return DOMString("");
            }
        default:
            {
            //Get ancestor element, if any
            NodePtr ancestor = getAncestorElement(this);
            if ( ancestor.get() )
               {
               return ancestor->lookupPrefix(theNamespaceURI);
               }
            return DOMString("");
            }
        }//switch
    return DOMString("");
}


/**
 *
 */
bool NodeImpl::isDefaultNamespace(const DOMString &theNamespaceURI)
{
    switch (nodeType)
        {
        case ELEMENT_NODE:
            {
            if ( namespaceURI.size()>0 && prefix.size()==0 )
                {
                return (namespaceURI == theNamespaceURI);
                }
            NodePtr attr = attributes.getNamedItem("xmlns");
            if ( attr.get() )
                {
                return (attr->getNodeValue() == theNamespaceURI);
                }

            NodePtr ancestor = getAncestorElement(this);
            if ( ancestor.get() )
                {
                return ancestor->isDefaultNamespace(theNamespaceURI);
                }
            else
                {
                return false;
                }
            }
        case DOCUMENT_NODE:
            { //just use braces for local declaration
            DocumentPtr doc = (Document *)this;
            ElementPtr elem = doc->getDocumentElement();
            return elem->isDefaultNamespace(theNamespaceURI);
            }
        case ENTITY_NODE:
        case NOTATION_NODE:
        case DOCUMENT_TYPE_NODE:
        case DOCUMENT_FRAGMENT_NODE:
            return false;
        case ATTRIBUTE_NODE:
            {//braces only for scope
            AttrPtr attr = (Attr *)this;
            ElementPtr ownerElement = attr->getOwnerElement();
            if ( ownerElement.get() )
                {
                return ownerElement->isDefaultNamespace(theNamespaceURI);
                }
            else
                {
                return false;
                }
            }
        default:
            {
            NodePtr ancestor = getAncestorElement(this);
            if ( ancestor.get() )
                {
                return ancestor->isDefaultNamespace(theNamespaceURI);
                }
            else
                {
                return false;
                }
            }
        }//switch

    return false;
}


/**
 *
 */
DOMString NodeImpl::lookupNamespaceURI(const DOMString &thePrefix)
{
    switch (nodeType)
        {
        case ELEMENT_NODE:
            {
            if ( namespaceURI.size()>0 && prefix == thePrefix )
                {
                DOMString nsURI = namespaceURI;
                return (nsURI);
                }
            if ( hasAttributes() )
                {
                NamedNodeMap attributes = getAttributes();
                int nrAttrs = attributes.getLength();
                for (int i=0 ; i<nrAttrs ; i++)
                    {
                    NodePtr attr = attributes.item(i);
                    if (attr->getPrefix() == "xmlns" && attr->getLocalName() == thePrefix )
                        { // non default namespace
                        if (attr->getNodeValue().size()>0)
                            {
                            return (attr->getNodeValue());
                            }
                        return DOMString("");
                        }
                    else if (attr->getLocalName() == "xmlns" && thePrefix.size()==0)
                        { // default namespace
                        if (attr->getNodeValue().size()>0)
                            {
                            return (attr->getNodeValue());
                            }
                        return DOMString("");
                        }
                    }
                }

            NodePtr ancestor = getAncestorElement(this);
            if ( ancestor.get() )
                {
                return ancestor->lookupNamespaceURI(thePrefix);
                }
            return DOMString("");
            }
        case DOCUMENT_NODE:
            {
            DocumentPtr doc = (Document *)this;
            ElementPtr elem = doc->getDocumentElement();
            return elem->lookupNamespaceURI(thePrefix);
            }
        case ENTITY_NODE:
        case NOTATION_NODE:
        case DOCUMENT_TYPE_NODE:
        case DOCUMENT_FRAGMENT_NODE:
            return DOMString("");

        case ATTRIBUTE_NODE:
            {
            ElementPtr ownerElement = ((Attr *)this)->getOwnerElement();
            if ( ownerElement.get() )
                {
                return ownerElement->lookupNamespaceURI(thePrefix);
                }
            else
                {
                return DOMString("");
                }
            }
        default:
            {
            NodePtr ancestor = getAncestorElement(this);
            if ( ancestor.get() )
                {
                return ancestor->lookupNamespaceURI(thePrefix);
                }
            else
                {
                return DOMString("");
                }
            }
        }//switch
}


/**
 *
 */
bool NodeImpl::isEqualNode(const NodePtr nodeArg)
{
    if (!nodeArg)
        return false;

    if (nodeArg == (NodePtr )this)
        return true;

    NodePtr node = nodeArg;

    if (getNodeType()     != node->getNodeType()     ||
        getNodeName()     != node->getNodeName()     ||
        getLocalName()    != node->getLocalName()    ||
        getNamespaceURI() != node->getNamespaceURI() ||
        getPrefix()       != node->getPrefix()       ||
        getNodeValue()    != node->getNodeValue()    ||
        getBaseURI()      != node->getBaseURI()      )
        return false;

    return true;
}



/**
 *
 */
DOMObject *NodeImpl::getFeature(const DOMString &feature,
                             const DOMString &version)
{
    //dont know
    return NULL;
}

/**
 *
 */
DOMUserData *NodeImpl::setUserData(const DOMString &key,
                                   const DOMUserData *data,
                                   const UserDataHandler *handler)
{
    UserDataEntry *entry = userDataEntries;
    UserDataEntry *prev  = NULL;
    while (entry)
        {
        if (entry->key == key)
            {
            DOMUserData *oldData = entry->data;
            entry->data    = (DOMUserData *)data;
            entry->handler = (UserDataHandler *)handler;
            return oldData;
            }
        prev  = entry;
        entry = entry->next;
        }

    //Make a new one
    UserDataEntry *newEntry = new UserDataEntry(key, data, handler);
    if (!prev)
        userDataEntries = newEntry;
    else
        prev->next = newEntry;

    return NULL;
}

/**
 *
 */
DOMUserData *NodeImpl::getUserData(const DOMString &key)
{
    UserDataEntry *entry = userDataEntries;
    while (entry)
        {
        if (entry->key == key)
            return entry->data;
        entry = entry->next;
        }
    return NULL;
}



//##################
//# Non-API methods
//##################

/**
 *
 */
void NodeImpl::setNodeName(const DOMString &qualifiedName)
{
    nodeName  = qualifiedName;
    prefix    = "";
    localName = "";
    for (unsigned int i=0 ; i<qualifiedName.size() ; i++)
        {
        int ch = qualifiedName[i];
        if (ch == ':')
            {
            prefix    = localName;
            localName = "";
            }
        else
            {
            localName.push_back((XMLCh)ch);
            }
        }
}

/**
 *
 */
void NodeImpl::setNamespaceURI(const DOMString &theNamespaceURI)
{
    namespaceURI = theNamespaceURI;
}


/**
 * From DOM3 Namespace algorithms
 */
DOMString NodeImpl::lookupNamespacePrefix(const DOMString &theNamespaceURI,
                                          NodePtr originalElement)
{
    if (!originalElement)
        return DOMString("");

    if ( namespaceURI.size()>0 && namespaceURI==theNamespaceURI &&
         prefix.size()>0 &&
         originalElement->lookupNamespaceURI(prefix) == theNamespaceURI)
        {
        return (prefix);
        }

    if ( hasAttributes() )
        {
        NamedNodeMap attributes = getAttributes();
        int nrAttrs = attributes.getLength();
        for (int i=0 ; i<nrAttrs ; i++)
            {
            NodePtr attr = attributes.item(i);
            DOMString attrLocalName = attr->getLocalName();
            if (attr->getPrefix()    == "xmlns" &&
                attr->getNodeValue() == theNamespaceURI &&
                originalElement->lookupNamespaceURI(attrLocalName)
                                     == theNamespaceURI)
                {
                return (attrLocalName);
                }
            }
        }

    //Get ancestor element, if any
    NodeImplPtr ancestor = parent;
    while (ancestor.get() && ancestor->getNodeType()!= Node::ELEMENT_NODE)
        ancestor = ancestor->parent;

    if ( ancestor.get() )
        {
        return ancestor->lookupNamespacePrefix(theNamespaceURI, originalElement);
        }

    return DOMString("");
}


/**
 *
 */
NodeImpl::NodeImpl() : Node()
{
    init();
}


/**
 *
 */
NodeImpl::NodeImpl(const NodeImpl &other) : Node()
{
    init();
    assign(other);
}

/**
 *
 */
NodeImpl &NodeImpl::operator=(const NodeImpl &other)
{
    init();
    assign(other);
    return *this;
}


/**
 *
 */
NodeImpl::NodeImpl(DocumentImplPtr owner) : Node()
{
    init();
    ownerDocument = owner;
}

/**
 *
 */
NodeImpl::NodeImpl(DocumentImplPtr owner, const DOMString &nodeName)
                   : Node()
{
    init();
    ownerDocument = owner;
    setNodeName(nodeName);
}

/**
 *
 */
NodeImpl::NodeImpl(DocumentImplPtr owner, const DOMString &theNamespaceURI,
                      const DOMString &qualifiedName) : Node()
{
    init();
    ownerDocument = owner;
    //if (owner)
    //    namespaceURI  = owner->stringCache(theNamespaceURI);
    setNodeName(qualifiedName);
}



/**
 *
 */
void NodeImpl::init()
{
    nodeType        = 0; //none yet
    nodeValue       = "";
    setNodeName("");
    namespaceURI    = "";
    parent          = NULL;
    prev            = NULL;
    next            = NULL;
    userData        = NULL;
    firstChild      = NULL;
    lastChild       = NULL;
    ownerDocument   = NULL;
    userDataEntries = NULL;
}

/**
 *
 */
void NodeImpl::assign(const NodeImpl &other)
{
    ownerDocument = other.ownerDocument;
    prefix        = other.prefix;
    localName     = other.localName;
    nodeName      = other.nodeName;
    nodeValue     = other.nodeValue;
    namespaceURI  = other.namespaceURI;
    attributes    = other.attributes;
}


/**
 *
 */
NodeImpl::~NodeImpl()
{
    if (userDataEntries)
        delete userDataEntries;
    //Delete children
    /** Use smart pointers.  do not delete explicitly
	for (NodePtr n = getFirstChild() ; n.get() ;
		     n=n->getNextSibling() )
        delete n;
    */
    firstChild = lastChild = (NodeImpl *)0;
}



/*#########################################################################
## CharacterDataImpl
#########################################################################*/


/**
 *
 */
CharacterDataImpl::CharacterDataImpl() : NodeImpl()
{
}

/**
 *
 */
CharacterDataImpl::CharacterDataImpl(DocumentImplPtr owner,
                                     const DOMString &theValue) : NodeImpl()
{
    ownerDocument = owner;
    nodeValue     = theValue;
}

/**
 *
 */
CharacterDataImpl::~CharacterDataImpl()
{
}

/**
 *
 */
DOMString CharacterDataImpl::getData() throw(DOMException)
{
    return nodeValue;
}

/**
 *
 */
void CharacterDataImpl::setData(const DOMString& val) throw(DOMException)
{
    nodeValue = val;
}

/**
 *
 */
unsigned long CharacterDataImpl::getLength()
{
    return nodeValue.size();
}

/**
 *
 */
DOMString CharacterDataImpl::substringData(unsigned long offset,
                        unsigned long count)
                        throw(DOMException)
{
    return nodeValue.substr(offset, count);
}

/**
 *
 */
void CharacterDataImpl::appendData(const DOMString& arg) throw(DOMException)
{
    nodeValue += arg;
}

/**
 *
 */
void CharacterDataImpl::insertData(unsigned long offset,
                const DOMString& arg)
                throw(DOMException)
{
    nodeValue.insert(offset, arg);
}

/**
 *
 */
void CharacterDataImpl::deleteData(unsigned long offset,
                unsigned long count)
                throw(DOMException)
{
    nodeValue.erase(offset, count);
}

/**
 *
 */
void  CharacterDataImpl::replaceData(unsigned long offset,
                  unsigned long count,
                  const DOMString& arg)
                  throw(DOMException)
{
    nodeValue.replace(offset, count, arg);
}






/*#########################################################################
## AttrImpl
#########################################################################*/

/**
 *
 */
DOMString AttrImpl::getName()
{
    return nodeName;
}

/**
 *
 */
bool AttrImpl::getSpecified()
{
    return (nodeValue.size() > 0);
}

/**
 *
 */
DOMString AttrImpl::getValue()
{
    return nodeValue;
}

/**
 *
 */
void AttrImpl::setValue(const DOMString& val) throw(DOMException)
{
    nodeValue = val;
}

/**
 *
 */
ElementPtr AttrImpl::getOwnerElement()
{
    return ownerElement;
}


/**
 *
 */
TypeInfo &AttrImpl::getSchemaTypeInfo()
{
    return typeInfo;
}


/**
 *
 */
bool AttrImpl::getIsId()
{
    return (nodeName == "id");
}



//##################
//# Non-API methods
//##################


void AttrImpl::setOwnerElement(const ElementPtr elem)
{
    ownerElement = elem;
}

/**
 *
 */
AttrImpl::AttrImpl(DocumentImplPtr owner, const DOMString &theName)
                   : NodeImpl()
{
    nodeType     = ATTRIBUTE_NODE;
    ownerDocument = owner;
    setNodeName(theName);
}

/**
 *
 */
AttrImpl::AttrImpl(DocumentImplPtr owner,
                   const DOMString &theNamespaceURI,
                   const DOMString &theQualifiedName)
                   : NodeImpl()
{
    nodeType     = ATTRIBUTE_NODE;
    ownerDocument = owner;
    //if (owner)
    //    namespaceURI  = owner->stringCache(theNamespaceURI);
    setNodeName(theQualifiedName);
}

/**
 *
 */
AttrImpl::~AttrImpl()
{
}





/*#########################################################################
## ElementImpl
#########################################################################*/


/**
 *
 */
DOMString ElementImpl::getTagName()
{
    if (prefix.size() > 0)
        return prefix + ":" + nodeName;
    else
        return nodeName;
}

/**
 *
 */
DOMString ElementImpl::getAttribute(const DOMString& name)
{
    NodePtr node = attributes.getNamedItem(name);
    if (!node || node->getNodeType() != ATTRIBUTE_NODE)
        return DOMString("");
    AttrPtr attr = dynamic_cast<Attr *>(node.get());
    return attr->getValue();
}

/**
 *
 */
void ElementImpl::setAttribute(const DOMString& name,
                  const DOMString& value)
                  throw(DOMException)
{
    AttrImplPtr attr = new AttrImpl(ownerDocument, name);
    attr->setValue(value);
    attr->setOwnerElement(this);
    attributes.setNamedItem(attr);
}

/**
 *
 */
void ElementImpl::removeAttribute(const DOMString& name)
                     throw(DOMException)
{
    attributes.removeNamedItem(name);
}

/**
 *
 */
AttrPtr ElementImpl::getAttributeNode(const DOMString& name)
{
    NodePtr node = attributes.getNamedItem(name);
    if (!node || node->getNodeType() != ATTRIBUTE_NODE)
        return NULL;
    AttrPtr attr = dynamic_cast<Attr *>(node.get());
    return attr;
}

/**
 *
 */
AttrPtr ElementImpl::setAttributeNode(AttrPtr attr)
                      throw(DOMException)
{
    attributes.setNamedItem(attr);
    return attr;
}

/**
 *
 */
AttrPtr ElementImpl::removeAttributeNode(AttrPtr attr)
                         throw(DOMException)
{
    attributes.removeNamedItem(attr->getName());
    return attr;
}


/**
 *
 */
void ElementImpl::getElementsByTagNameRecursive(NodeList &list,
                        const DOMString& name, ElementPtr elem)
{
    if (!elem)
        return;

    if (name == elem->getTagName())
        list.add(elem);
    for (NodePtr node = elem->getFirstChild() ; node.get() ;
	               node=node->getNextSibling())
        {
        if (node->getNodeType() != Node::ELEMENT_NODE)
            continue;
        ElementPtr childElem = dynamic_cast<Element *>(node.get());
        getElementsByTagNameRecursive(list, name, childElem);
        }
}


/**
 *
 */
NodeList ElementImpl::getElementsByTagName(const DOMString& tagName)
{
    NodeList list;
    getElementsByTagNameRecursive(list, tagName, this);
    return list;
}

/**
 *
 */
DOMString ElementImpl::getAttributeNS(const DOMString& namespaceURI,
                         const DOMString& localName)
{
    NodePtr node = attributes.getNamedItemNS(namespaceURI, localName);
    if (!node || node->getNodeType()!=ATTRIBUTE_NODE)
        return DOMString("");
    AttrPtr attr = dynamic_cast<Attr *>(node.get());
    return attr->getValue();
}

/**
 *
 */
void ElementImpl::setAttributeNS(const DOMString& namespaceURI,
                    const DOMString& qualifiedName,
                    const DOMString& value)
                    throw(DOMException)
{
    AttrImplPtr attr = new AttrImpl(ownerDocument, namespaceURI, qualifiedName);
    attr->setValue(value);
    attr->setOwnerElement(this);
    attributes.setNamedItemNS(attr);
}

/**
 *
 */
void ElementImpl::removeAttributeNS(const DOMString& namespaceURI,
                       const DOMString& localName)
                       throw(DOMException)
{
    attributes.removeNamedItemNS(namespaceURI, localName);
}

/**
 *
 */
 AttrPtr ElementImpl::getAttributeNodeNS(const DOMString& namespaceURI,
                        const DOMString& localName)
{
    NodePtr node = attributes.getNamedItemNS(namespaceURI, localName);
    if (!node || node->getNodeType() != ATTRIBUTE_NODE)
        return (Attr *)0;
    AttrPtr attr = dynamic_cast<Attr *>(node.get());
    return attr;
}

/**
 *
 */
AttrPtr ElementImpl::setAttributeNodeNS(AttrPtr attr)
                        throw(DOMException)
{
    attributes.setNamedItemNS(attr);
    return attr;
}


/**
 *
 */
void ElementImpl::getElementsByTagNameNSRecursive(NodeList &list,
             const DOMString& namespaceURI,
			 const DOMString& tagName, ElementPtr elem)
{
    if (!elem)
        return;

    if (namespaceURI == elem->getNamespaceURI() && tagName == elem->getTagName())
        list.add(elem);
    for (NodePtr node = elem->getFirstChild() ; node.get() ; node=node->getNextSibling())
        {
        if (node->getNodeType() != Node::ELEMENT_NODE)
            continue;
        ElementPtr childElem = dynamic_cast<Element *>(node.get());
        getElementsByTagNameNSRecursive(list, namespaceURI, tagName, childElem);
        }
}

/**
 *
 */
NodeList ElementImpl::getElementsByTagNameNS(const DOMString& namespaceURI,
                                const DOMString& localName)
{
    NodeList list;
    getElementsByTagNameNSRecursive(list, namespaceURI, localName, this);
    return list;
}

/**
 *
 */
bool ElementImpl::hasAttribute(const DOMString& attrName)
{
    NodePtr node = attributes.getNamedItem(attrName);
    if (!node || node->getNodeType() != ATTRIBUTE_NODE)
        return false;
    return true;
}

/**
 *
 */
bool ElementImpl::hasAttributeNS(const DOMString& namespaceURI,
                    const DOMString& localName)
{
    NodePtr node = attributes.getNamedItemNS(namespaceURI, localName);
    if (!node || node->getNodeType() != ATTRIBUTE_NODE)
        return false;
    return true;
}

/**
 *
 */
TypeInfo &ElementImpl::getSchemaTypeInfo()
{
    return typeInfo;
}


/**
 *
 */
void ElementImpl::setIdAttribute(const DOMString &name,
                            bool isId) throw (DOMException)
{
    //fixme
}

/**
 *
 */
void ElementImpl::setIdAttributeNS(const DOMString &namespaceURI,
                              const DOMString &localName,
                              bool isId) throw (DOMException)
{
    //fixme
}

/**
 *
 */
void ElementImpl::setIdAttributeNode(const AttrPtr idAttr,
                                bool isId) throw (DOMException)
{
    //fixme
}


//##################
//# Non-API methods
//##################


/**
 *
 */
ElementImpl::ElementImpl() : NodeImpl()
{
    nodeType = ELEMENT_NODE;
}

/**
 *
 */
ElementImpl::ElementImpl(DocumentImplPtr owner, const DOMString &tagName)
                                  : NodeImpl()
{
    nodeType = ELEMENT_NODE;
    ownerDocument = owner;
    setNodeName(tagName);
}

/**
 *
 */
ElementImpl::ElementImpl(DocumentImplPtr owner,
                         const DOMString &theNamespaceURI,
                         const DOMString &qualifiedName) :
                         NodeImpl()
{
    nodeType = ELEMENT_NODE;
    ownerDocument = owner;
    setNodeName(qualifiedName);
}

/**
 *
 */
ElementImpl::~ElementImpl()
{
}


/**
 *
 */
void ElementImpl::normalizeNamespaces()
{
    //printf("### NORMALIZE\n");

    NamedNodeMap attrs = getAttributes();

    //#######################################
    //# Pick up local namespace declarations
    //#######################################
    bindingsClear();  //Reset bindings on this node

    int nrAttrs = attrs.getLength();
    for (int i=0; i<nrAttrs ; i++)
        {
        NodePtr attrNode = attrs.item(i);
        if (attrNode->getNodeType() != Node::ATTRIBUTE_NODE)
            continue;
        AttrImplPtr attr = dynamic_cast<AttrImpl *>(attrNode.get());
        DOMString attrNS     = attr->getNamespaceURI();
        DOMString attrName   = attr->getLocalName();
        DOMString attrPrefix = attr->getPrefix();
        DOMString attrValue  = attr->getNodeValue();
        if (attrName != "xmlns" && attrPrefix != "xmlns")
            continue;

        //is the namespace declaration is invalid?
        if (attrValue == XMLNSNAME || attrName == attrPrefix)
            {
            // Note: The prefix xmlns is used only to declare namespace bindings and
            // is by definition bound to the namespace name http://www.w3.org/2000/xmlns/.
            // It must not be declared. No other prefix may be bound to this namespace name.

            //==> Report an error.
            printf("normalizeNamespaces() error: Namespace %s cannot be reassigned\n",
                        XMLNSNAME);

            }
        else
            {
            //==>  Record the namespace declaration
            attr->setNamespaceURI(XMLNSNAME);
            if (attrPrefix.size() > 0)
                bindingsAdd(attrPrefix, attrValue);
            else
                bindingsAdd("*", attrValue);//default

            }
        }


    //#######################################
    //# Fixup element's namespace
    //#######################################
    if ( namespaceURI.size() > 0 )
        {
        DOMString key = prefix;
        if (key.size() == 0)
            key = "*";
        DOMString binding = bindingsFind(key);
        //Element's prefix/namespace pair (or default namespace, if no prefix)
        // are within the scope of a binding
        if ( binding == namespaceURI )
            {
            //==> do nothing, declaration in scope is inherited

            // See section "B.1.1: Scope of a binding" for an example

            }
        else
            {

            /*
            ==> Create a local namespace declaration attr for this namespace,
            with Element's current prefix (or a default namespace, if
            no prefix). If there's a conflicting local declaration
            already present, change its value to use this namespace.

            See section "B.1.2: Conflicting namespace declaration" for an example
            */
            DOMString attrName = "xmlns";
            if (prefix.size() > 0)
                {
                attrName.append(":");
                attrName.append(prefix);
                }
            setAttribute(attrName, namespaceURI);
            // NOTE that this may break other nodes within this Element's
            // subtree, if they're already using this prefix.
            // They will be repaired when we reach them.
            }
        }
    else  // Element has no namespace URI:
        {
        //###############################################
        //# Bob -- alter this from the specs a bit.
        //#  Since the XmlReader does not set namespaces,
        //#    do it here
        //###############################################
        DOMString localName = getLocalName();
        if ( localName.size()==0 )
            {
            // DOM Level 1 node
            /*
            ==> if in process of validation against a namespace aware schema
            (i.e XML Schema) report a fatal error: the processor can not recover
            in this situation.
            Otherwise, report an error: no namespace fixup will be performed on this node.
            */
            printf("normalizeNamespaces() error: no localName\n");
            }
        else
            {
            // Element has no pseudo-prefix
            //there's a conflicting local default namespace declaration already present
            if ( prefix.size()==0 )
                {
                //==> change its value to use this empty namespace.
                namespaceURI = bindingsFind("*");
                //setAttribute("xmlns", "");
                }
            else  //#BOB .   I added this.
                {
                namespaceURI = bindingsFind(prefix);
                }
            // NOTE that this may break other nodes within this Element's
            // subtree, if they're already using the default namespaces.
            // They will be repaired when we reach them.
            }
        }


    //#######################################
    //# Examine and polish the attributes
    //#######################################
    nrAttrs = attrs.getLength();
    for (int i=0; i<nrAttrs ; i++)// all non-namespace Attrs of Element
        {
        NodePtr attrNode = attrs.item(i);
        if (attrNode->getNodeType() != Node::ATTRIBUTE_NODE)
            continue;
        AttrPtr attr = dynamic_cast<Attr *>(attrNode.get());
        DOMString attrNS     = attr->getNamespaceURI();
        DOMString attrPrefix = attr->getPrefix();
        DOMString attrValue  = attr->getNodeValue();
        if (attrNS == XMLNSNAME)
            continue;

        if ( attrNS.size()>0 ) //Attr[i] has a namespace URI
            {
            DOMString attrBinding = bindingsFind(attrPrefix);
            /*
             if attribute has no prefix (default namespace decl does not apply to attributes)
             OR
             attribute prefix is not declared
             OR
             conflict: attribute has a prefix that conflicts with a binding
                       already active in scope
            */
            if ( attrPrefix.size() == 0 || attrBinding.size() == 0)
                {
                //namespaceURI matches an in scope declaration of one or more prefixes)
                DOMString prefixForNS = lookupNamespacePrefix(attrNS, this);
                if ( prefixForNS.size() > 0 )
                    {
                    // pick the most local binding available;
                    // if there is more than one pick one arbitrarily

                    //==> change attribute's prefix.
                    attr->setPrefix(prefixForNS);
                    }
                else
                    {
                    // the current prefix is not null and it has no in scope declaration)
                    if ( attrPrefix.size() > 0 || attrBinding.size() == 0 )
                        {
                        //==> declare this prefix
                        DOMString newAttrName = "xmlns:";
                        newAttrName.append(attrPrefix);
                        setAttribute(newAttrName, attrNS);
                        bindingsAdd(attrPrefix, attrNS);
                        }
                    else
                        {
                        // find a prefix following the pattern "NS" +index (starting at 1)
                        // make sure this prefix is not declared in the current scope.
                        // create a local namespace declaration attribute

                        //==> declare this prefix
                        char buf[16];
                        sprintf(buf, "%d" , ownerDocument->namespaceIndex++);
                        DOMString newPrefix = "NS";
                        newPrefix.append(buf);
                        DOMString newAttrName = "xmlns:";
                        newAttrName.append(newPrefix);
                        setAttribute(newAttrName, attrNS);
                        bindingsAdd(newPrefix, attrNS);
                        //==> change attribute's prefix.
                        }
                    }
                }
            }
        else  // Attr has no namespace URI
            {
            // Attr has no localName
            if ( attr->getLocalName().size() == 0 )
                {
                // DOM Level 1 node
                /*
                ==> if in process of validation against a namespace aware schema
                (i.e XML Schema) report a fatal error: the processor can not recover
                in this situation.
                Otherwise, report an error: no namespace fixup will be performed on this node.
                */
                printf("normalizeNamespaces:  no local name for attribute\n");
                }
            else
                {
                // attr has no namespace URI and no prefix
                // no action is required, since attrs don't use default
                //==> do nothing
                }
            }
        } // end for-all-Attrs


    //#######################################
    //# Recursively normalize children
    //#######################################
    for (NodePtr child=getFirstChild() ; child.get() ; child=child->getNextSibling())
        {
        if (child->getNodeType() != Node::ELEMENT_NODE)
            continue;
        ElementImplPtr childElement = dynamic_cast<ElementImpl *>(child.get());
        childElement->normalizeNamespaces();
        }

}


/*#########################################################################
## TextImpl
#########################################################################*/


/**
 *
 */
TextImpl::TextImpl() : CharacterDataImpl()
{
    nodeType = TEXT_NODE;
    nodeName = "#text";
}


/**
 *
 */
TextImpl::TextImpl(DocumentImplPtr owner, const DOMString &value)
                               : CharacterDataImpl()
{
    nodeType      = TEXT_NODE;
    nodeName      = "#text";
    ownerDocument = owner;
    nodeValue     = value;
}


/**
 *
 */
TextImpl::~TextImpl()
{
}

/**
 *
 */
TextPtr TextImpl::splitText(unsigned long offset)
                throw(DOMException)
{
    return NULL;
}

/**
 *
 */
bool TextImpl::getIsElementContentWhitespace()
{
    return false;
}

/**
 *
 */
DOMString TextImpl::getWholeText()
{
    return nodeValue;
}


/**
 *
 */
TextPtr TextImpl::replaceWholeText(const DOMString &content)
                             throw(DOMException)
{
    return NULL;
}


/*#########################################################################
## CommentImpl
#########################################################################*/

/**
 *
 */
CommentImpl::CommentImpl() : CharacterDataImpl()
{
    nodeType = COMMENT_NODE;
    nodeName = "#comment";
}


/**
 *
 */
CommentImpl::CommentImpl(DocumentImplPtr owner, const DOMString &value)
                       : CharacterDataImpl()
{
    nodeType      = COMMENT_NODE;
    nodeName      = "#comment";
    ownerDocument = owner;
    nodeValue     = value;
}


/**
 *
 */
CommentImpl::~CommentImpl()
{
}







/*#########################################################################
## UserDataHandlerImpl
#########################################################################*/



/**
 *
 */
UserDataHandlerImpl::UserDataHandlerImpl()
{
}


/**
 *
 */
UserDataHandlerImpl::~UserDataHandlerImpl()
{
}

/**
 *
 */
void UserDataHandlerImpl::handle(unsigned short operation,
                     const DOMString &key,
                     const DOMUserData *data,
                     const NodePtr src,
                     const NodePtr dst)
{
    //do nothing.  do we need anything here?
}



/*#########################################################################
## DOMErrorImpl
#########################################################################*/



/**
 *
 */
DOMErrorImpl::DOMErrorImpl()
{
}


/**
 *
 */
DOMErrorImpl::~DOMErrorImpl()
{
}

/**
 *
 */
unsigned short DOMErrorImpl::getSeverity()
{
    return severity;
}

/**
 *
 */
DOMString DOMErrorImpl::getMessage()
{
    return message;
}

/**
 *
 */
DOMString DOMErrorImpl::getType()
{
    return type;
}

/**
 *
 */
DOMObject *DOMErrorImpl::getRelatedException()
{
    return NULL;
}

/**
 *
 */
DOMObject *DOMErrorImpl::getRelatedData()
{
    return NULL;
}

/**
 *
 */
DOMLocator *DOMErrorImpl::getLocation()
{
    //really should fill this in
    return NULL;
}




/*#########################################################################
## DOMErrorHandlerImpl
#########################################################################*/



/**
 *
 */
DOMErrorHandlerImpl::DOMErrorHandlerImpl()
{
}


/**
 *
 */
DOMErrorHandlerImpl::~DOMErrorHandlerImpl()
{
}

/**
 *
 */
bool DOMErrorHandlerImpl::handleError(const DOMError *error)
{
    if (!error)
        return false;
    return true;
}




/*#########################################################################
## DOMLocatorImpl
#########################################################################*/


/**
 *
 */
DOMLocatorImpl::DOMLocatorImpl()
{
}


/**
 *
 */
DOMLocatorImpl::~DOMLocatorImpl()
{
}


/**
 *
 */
long DOMLocatorImpl::getLineNumber()
{
    return lineNumber;
}

/**
 *
 */
long DOMLocatorImpl::getColumnNumber()
{
    return columnNumber;
}

/**
 *
 */
long DOMLocatorImpl::getByteOffset()
{
    return byteOffset;
}

/**
 *
 */
long DOMLocatorImpl::getUtf16Offset()
{
    return utf16Offset;
}


/**
 *
 */
NodePtr DOMLocatorImpl::getRelatedNode()
{
    return relatedNode;
}


/**
 *
 */
DOMString DOMLocatorImpl::getUri()
{
    return uri;
}



/*#########################################################################
## DOMConfigurationImpl
#########################################################################*/


/**
 *
 */
DOMConfigurationImpl::DOMConfigurationImpl()
{
}


/**
 *
 */
DOMConfigurationImpl::~DOMConfigurationImpl()
{
}

/**
 *
 */
void DOMConfigurationImpl::setParameter(const DOMString &name,
                          const DOMUserData *value) throw (DOMException)
{
}

/**
 *
 */
DOMUserData *DOMConfigurationImpl::getParameter(const DOMString &name)
                                  throw (DOMException)
{
    return NULL;
}

/**
 *
 */
bool DOMConfigurationImpl::canSetParameter(const DOMString &name,
                             const DOMUserData *data)
{
    return false;
}

/**
 *
 */
DOMStringList *DOMConfigurationImpl::getParameterNames()
{
    return NULL;
}



/*#########################################################################
## CDATASectionImpl
#########################################################################*/

/**
 *
 */
CDATASectionImpl::CDATASectionImpl() : TextImpl()
{
    nodeType = CDATA_SECTION_NODE;
    nodeName = "#cdata-section";
}

/**
 *
 */
CDATASectionImpl::CDATASectionImpl(DocumentImplPtr owner, const DOMString &theValue)
                                 : TextImpl()
{
    nodeType      = CDATA_SECTION_NODE;
    nodeName      = "#cdata-section";
    ownerDocument = owner;
    nodeValue     = theValue;
}


/**
 *
 */
CDATASectionImpl::~CDATASectionImpl()
{
}





/*#########################################################################
## DocumentTypeImpl
#########################################################################*/

/**
 *
 */
DocumentTypeImpl::DocumentTypeImpl(const DOMString& theName,
                                   const DOMString& thePublicId,
                                   const DOMString& theSystemId)
                                  : NodeImpl()
{
    nodeType = DOCUMENT_TYPE_NODE;
    nodeName = theName;
    publicId = thePublicId;
    systemId = theSystemId;
}

/**
 *
 */
DocumentTypeImpl::~DocumentTypeImpl()
{
}

/**
 *
 */
DOMString DocumentTypeImpl::getName()
{
    return nodeName;
}

/**
 *
 */
NamedNodeMap DocumentTypeImpl::getEntities()
{
    return entities;
}

/**
 *
 */
NamedNodeMap DocumentTypeImpl::getNotations()
{
    return notations;
}

/**
 *
 */
DOMString DocumentTypeImpl::getPublicId()
{
    return publicId;
}

/**
 *
 */
DOMString DocumentTypeImpl::getSystemId()
{
    return systemId;
}

/**
 *
 */
DOMString DocumentTypeImpl::getInternalSubset()
{
    return DOMString("");
}






/*#########################################################################
## NotationImpl
#########################################################################*/



/**
 *
 */
NotationImpl::NotationImpl(DocumentImplPtr owner) : NodeImpl()
{
    nodeType = NOTATION_NODE;
    ownerDocument = owner;
}


/**
 *
 */
NotationImpl::~NotationImpl()
{
}

/**
 *
 */
DOMString NotationImpl::getPublicId()
{
    return publicId;
}

/**
 *
 */
DOMString NotationImpl::getSystemId()
{
    return systemId;
}








/*#########################################################################
## EntityImpl
#########################################################################*/


/**
 *
 */
EntityImpl::EntityImpl() : NodeImpl()
{
    nodeType = ENTITY_NODE;
}


/**
 *
 */
EntityImpl::EntityImpl(DocumentImplPtr owner) : NodeImpl()
{
    nodeType = ENTITY_NODE;
    ownerDocument = owner;
}


/**
 *
 */
EntityImpl::~EntityImpl()
{
}

/**
 *
 */
DOMString EntityImpl::getPublicId()
{
    return publicId;
}

/**
 *
 */
DOMString EntityImpl::getSystemId()
{
    return systemId;
}

/**
 *
 */
DOMString EntityImpl::getNotationName()
{
    return notationName;
}

/**
 *
 */
DOMString EntityImpl::getInputEncoding()
{
    return inputEncoding;
}

/**
 *
 */
DOMString EntityImpl::getXmlEncoding()
{
    return xmlEncoding;
}

/**
 *
 */
DOMString EntityImpl::getXmlVersion()
{
    return xmlVersion;
}






/*#########################################################################
## EntityReferenceImpl
#########################################################################*/



/**
 *
 */
EntityReferenceImpl::EntityReferenceImpl() : NodeImpl()
{
    nodeType = ENTITY_REFERENCE_NODE;
}


/**
 *
 */
EntityReferenceImpl::EntityReferenceImpl(DocumentImplPtr owner,
                                         const DOMString &theName)
                                         : NodeImpl()
{
    nodeType = ENTITY_REFERENCE_NODE;
    nodeName = theName;
    ownerDocument = owner;
}


/**
 *
 */
EntityReferenceImpl::~EntityReferenceImpl()
{
}



/*#########################################################################
## ProcessingInstructionImpl
#########################################################################*/




/**
 *
 */
ProcessingInstructionImpl::ProcessingInstructionImpl(): NodeImpl()
{
    nodeType = PROCESSING_INSTRUCTION_NODE;
}



/**
 *
 */
ProcessingInstructionImpl::ProcessingInstructionImpl(DocumentImplPtr owner,
                                                     const DOMString &target,
                                                     const DOMString &data)
                                                     : NodeImpl()
{
    nodeType      = PROCESSING_INSTRUCTION_NODE;
    ownerDocument = owner;
    nodeName      = target;
    nodeValue     = data;
}


/**
 *
 */
ProcessingInstructionImpl::~ProcessingInstructionImpl()
{
}




/**
 *
 */
DOMString ProcessingInstructionImpl::getTarget()
{
    return nodeName;
}

/**
 *
 */
DOMString ProcessingInstructionImpl::getData()
{
    return nodeValue;
}

/**
 *
 */
void ProcessingInstructionImpl::setData(const DOMString& val) throw(DOMException)
{
     //do something here
}







/*#########################################################################
## DocumentFragmentImpl
#########################################################################*/

/**
 *
 */
DocumentFragmentImpl::DocumentFragmentImpl() : NodeImpl()
{
    nodeType = DOCUMENT_FRAGMENT_NODE;
    nodeName = "#document-fragment";
}


/**
 *
 */
DocumentFragmentImpl::DocumentFragmentImpl(DocumentImplPtr owner) : NodeImpl()
{
    nodeType = DOCUMENT_FRAGMENT_NODE;
    nodeName = "#document-fragment";
    ownerDocument = owner;
}


/**
 *
 */
DocumentFragmentImpl::~DocumentFragmentImpl()
{
}






/*#########################################################################
## DocumentImpl
#########################################################################*/



/**
 *
 */
DocumentTypePtr DocumentImpl::getDoctype()
{
    return doctype;
}

/**
 *
 */
DOMImplementation *DocumentImpl::getImplementation()
{
    return parent;
}

/**
 *
 */
ElementPtr DocumentImpl::getDocumentElement()
{
    return documentElement;
}

/**
 *
 */
ElementPtr DocumentImpl::createElement(const DOMString& tagName)
                       throw(DOMException)
{
    ElementPtr elem = new ElementImpl(this, tagName);
    return elem;
}

/**
 *
 */
DocumentFragmentPtr DocumentImpl::createDocumentFragment()
{
    DocumentFragmentPtr frag = new DocumentFragmentImpl(this);
    return frag;
}

/**
 *
 */
TextPtr DocumentImpl::createTextNode(const DOMString& data)
{
    TextPtr text = new TextImpl(this, data);
    return text;
}

/**
 *
 */
CommentPtr DocumentImpl::createComment(const DOMString& data)
{
    CommentPtr comment = new CommentImpl(this, data);
    return comment;
}

/**
 *
 */
CDATASectionPtr DocumentImpl::createCDATASection(const DOMString& data)
                                 throw(DOMException)
{
    CDATASectionPtr cdata = new CDATASectionImpl(this, data);
    return cdata;
}

/**
 *
 */
ProcessingInstructionPtr 
DocumentImpl::createProcessingInstruction(const DOMString& target,
                                          const DOMString& data)
                                          throw(DOMException)
{
    ProcessingInstructionPtr pi =
        new ProcessingInstructionImpl(this, target, data);
    return pi;
}

/**
 *
 */
AttrPtr DocumentImpl::createAttribute(const DOMString& attrName)
                      throw(DOMException)
{
    AttrPtr attr = new AttrImpl(this, attrName);
    return attr;
}

/**
 *
 */
EntityReferencePtr DocumentImpl::createEntityReference(const DOMString& erName)
                                       throw(DOMException)
{
    EntityReferencePtr ref = new EntityReferenceImpl(this, erName);
    return ref;
}


/**
 *
 */
NodeList DocumentImpl::getElementsByTagName(const DOMString& tagname)
{
    NodeList list;
    ElementImpl::getElementsByTagNameRecursive(list,
                     tagname, documentElement);
    return list;
}


/**
 *
 */
NodePtr DocumentImpl::importNode(const NodePtr importedNode,
                 bool deep)
                 throw(DOMException)
{
    return NULL;
}

/**
 *
 */
ElementPtr DocumentImpl::createElementNS(const DOMString& namespaceURI,
                         const DOMString& qualifiedName)
                         throw(DOMException)
{
    ElementPtr elem = new ElementImpl(this, namespaceURI, qualifiedName);
    return elem;
}

/**
 *
 */
AttrPtr DocumentImpl::createAttributeNS(const DOMString& namespaceURI,
                        const DOMString& qualifiedName)
                        throw(DOMException)
{
    AttrPtr attr = new AttrImpl(this, namespaceURI, qualifiedName);
    return attr;
}


/**
 *
 */
NodeList DocumentImpl::getElementsByTagNameNS(const DOMString& namespaceURI,
                                 const DOMString& localName)
{
    NodeList list;
    ElementImpl::getElementsByTagNameNSRecursive(list, namespaceURI,
                          localName, documentElement);
    return list;
}

/**
 *
 */
ElementPtr DocumentImpl::getElementById(const DOMString& elementId)
{
    for (NamedElementItem *entry = elementsById.next; entry ; entry=entry->next)
        if (entry->name == elementId)
            return entry->elem;
    return NULL;
}


/**
 *
 */
DOMString DocumentImpl::getInputEncoding()
{
    return inputEncoding;
}


/**
 *
 */
DOMString DocumentImpl::getXmlEncoding()
{
    return xmlEncoding;
}

/**
 *
 */
bool DocumentImpl::getXmlStandalone()
{
    return xmlStandalone;
}

/**
 *
 */
void DocumentImpl::setXmlStandalone(bool val) throw (DOMException)
{
    xmlStandalone = val;
}

/**
 *
 */
DOMString DocumentImpl::getXmlVersion()
{
    return xmlVersion;
}

/**
 *
 */
void DocumentImpl::setXmlVersion(const DOMString &version) throw (DOMException)
{
    xmlVersion = version;
}

/**
 *
 */
bool DocumentImpl::getStrictErrorChecking()
{
    return strictErrorChecking;
}

/**
 *
 */
void DocumentImpl::setStrictErrorChecking(bool val)
{
    strictErrorChecking = val;
}


/**
 *
 */
DOMString DocumentImpl::getDocumentURI()
{
    return documentURI;
}

/**
 *
 */
void DocumentImpl::setDocumentURI(const DOMString &uri)
{
    //documentURI = stringCache(uri);
}

/**
 *
 */
NodePtr DocumentImpl::adoptNode(const NodePtr source) throw (DOMException)
{
    return (NodePtr )source;
}

/**
 *
 */
DOMConfiguration *DocumentImpl::getDomConfig()
{
    return domConfig;
}

/**
 *
 */
void DocumentImpl::normalizeDocument()
{
    //i assume that this means adjusting namespaces & prefixes
    if (documentElement.get())
        documentElement->normalizeNamespaces();
}

/**
 *
 */
NodePtr DocumentImpl::renameNode(const NodePtr node,
                               const DOMString &namespaceURI,
                               const DOMString &qualifiedName)
                               throw (DOMException)
{
    NodeImplPtr nodeImpl = dynamic_cast<NodeImpl *> (node.get());
    nodeImpl->setNodeName(qualifiedName);
    return node;
}



//##################
//# Non-API methods
//##################

/**
 *
 */
DocumentImpl::DocumentImpl(const DOMImplementation *domImpl,
                 const DOMString &theNamespaceURI,
                 const DOMString &theQualifiedName,
                 const DocumentTypePtr theDoctype) : NodeImpl()
{
    nodeType        = DOCUMENT_NODE;
    nodeName        = "#document";
    parent          = (DOMImplementation *)domImpl;
    //documentURI     = stringCache(theNamespaceURI);
    qualifiedName   = theQualifiedName;
    if (theDoctype.get()) //only assign if not null.
        doctype     = theDoctype;
    else
        doctype     = new DocumentTypeImpl("", "", "");
    documentElement = new ElementImpl(this, "root");
    namespaceIndex  = 0;
}


/**
 *
 */
DocumentImpl::~DocumentImpl()
{
    documentElement = NULL;
}












}  //namespace dom
}  //namespace w3c
}  //namespace org



/*#########################################################################
## E N D    O F    F I L E
#########################################################################*/




