/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights 
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *	  notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *	  notice, this list of conditions and the following disclaimer in
 *	  the documentation and/or other materials provided with the
 *	  distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *	  if any, must include the following acknowledgment:  
 *		 "This product includes software developed by the
 *		  Apache Software Foundation (http://www.apache.org/)."
 *	  Alternately, this acknowledgment may appear in the software itself,
 *	  if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *	  not be used to endorse or promote products derived from this
 *	  software without prior written permission. For written 
 *	  permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *	  nor may "Apache" appear in their name, without prior written
 *	  permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.	IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
#include "XercesDocumentBridge.hpp"



#include <algorithm>
#include <cassert>



#include <dom/DOM_Node.hpp>
#include <dom/DOM_DOMException.hpp>



#include <PlatformSupport/STLHelper.hpp>



#include <DOMSupport/DOMServices.hpp>



#include <XalanDOM/XalanDocumentType.hpp>
#include <XalanDOM/XalanElement.hpp>



#include "XercesAttrBridge.hpp"
#include "XercesCommentBridge.hpp"
#include "XercesCDATASectionBridge.hpp"
#include "XercesDOM_NodeHack.hpp"
#include "XercesDOMException.hpp"
#include "XercesDOMImplementationBridge.hpp"
#include "XercesDocumentFragmentBridge.hpp"
#include "XercesDocumentTypeBridge.hpp"
#include "XercesElementBridge.hpp"
#include "XercesEntityBridge.hpp"
#include "XercesEntityReferenceBridge.hpp"
#include "XercesNodeListBridge.hpp"
#include "XercesNotationBridge.hpp"
#include "XercesProcessingInstructionBridge.hpp"
#include "XercesTextBridge.hpp"



XercesDocumentBridge::XercesDocumentBridge(
			const DOM_Document&		theXercesDocument,
			bool					buildBridge) :
	XalanDocument(),
	m_xercesDocument(theXercesDocument),
	m_documentElement(0),
	m_children(theXercesDocument.getChildNodes(),
			   m_navigator),
	m_cachedNodeLists(theXercesDocument,
					  m_navigator),
	m_nodeMap(),
	m_domImplementation(new XercesDOMImplementationBridge(theXercesDocument.getImplementation())),
	m_navigators(1, XercesBridgeNavigator(this, !buildBridge)),
	m_navigator(m_navigators.front()),
	m_nodes(),
	m_doctype(0),
	m_mappingMode(!buildBridge),
	m_indexValid(false)
#if defined(XALAN_USE_BLOCK_ALLOCATORS)
	, m_elementAllocator(25),
	m_textAllocator(25),
	m_attributeAllocator(25)
#endif
{
#if !defined(XALAN_NO_NAMESPACES)
	using std::make_pair;
#endif

	if (m_mappingMode == false)
	{
		// The document index is always 1...
		m_navigator.setIndex(1);

		// OK, let's build the nodes.  This makes things
		// thread-safe, so the document can be shared...
		buildBridgeNodes();
	}
	else
	{
		m_nodeMap.addAssociation(m_xercesDocument, this);
	}
}



XercesDocumentBridge::~XercesDocumentBridge()
{
	destroyBridge();
}



XalanNode*
XercesDocumentBridge::mapNode(const DOM_Node&	theXercesNode) const
{
	return mapNode(XercesDOM_NodeHack::getImpl(theXercesNode));
}



XalanNode*
XercesDocumentBridge::mapNode(NodeImpl*		theXercesNodeImpl) const
{
	XalanNode*	theXalanNode = 0;

	if (theXercesNodeImpl != 0)
	{
		theXalanNode = m_nodeMap.getNode(theXercesNodeImpl);

		if (theXalanNode == 0)
		{
			XercesDOM_NodeHack	theHack(theXercesNodeImpl);

			if (theHack != m_xercesDocument &&
					theHack.getOwnerDocument() != m_xercesDocument &&
				theHack.getParentNode() != m_xercesDocument)
			{
				throw XalanDOMException(XalanDOMException::WRONG_DOCUMENT_ERR);
			}
			else if (m_mappingMode == true)
			{
				// OK, we haven't yet created a bridge not, so go ahead and
				// create one.
				theXalanNode = createBridgeNode(theHack, 0, true);
				assert(theXalanNode != 0);
			}
		}
	}

	return theXalanNode;
}



DOM_Node
XercesDocumentBridge::mapNode(const XalanNode*	theXalanNode) const
{
	DOM_Node	theXercesNode;

	if (theXalanNode != 0)
	{
		theXercesNode = m_nodeMap.getNode(theXalanNode);

		if (theXercesNode.isNull() == true)
		{
			throw XalanDOMException(XalanDOMException::WRONG_DOCUMENT_ERR);
		}
	}

	return theXercesNode;
}



DOM_Attr
XercesDocumentBridge::mapNode(const XalanAttr* 	theXalanNode) const
{
	NodeImpl* const		theXercesNodeImpl =
		mapNodeToImpl(theXalanNode);

#if defined(XALAN_OLD_STYLE_CASTS)
	return XercesDOM_AttrHack((AttrImpl*)theXercesNodeImpl);
#else
	return XercesDOM_AttrHack(reinterpret_cast<AttrImpl*>(theXercesNodeImpl));
#endif
}



NodeImpl*
XercesDocumentBridge::mapNodeToImpl(const XalanNode* 	theXalanNode) const
{
	NodeImpl*	theXercesNodeImpl = 0;

	if (theXalanNode != 0)
	{
		theXercesNodeImpl = m_nodeMap.getNodeImpl(theXalanNode);

		if (theXercesNodeImpl == 0)
		{
			throw XalanDOMException(XalanDOMException::WRONG_DOCUMENT_ERR);
		}
	}

	return theXercesNodeImpl;
}



XalanAttr*
XercesDocumentBridge::mapNode(const DOM_Attr& 	theXercesNode) const
{
#if defined(XALAN_OLD_STYLE_CASTS)
	return (XercesAttrBridge*)mapNode(XercesDOM_NodeHack::getImpl(theXercesNode));
#else
	return static_cast<XercesAttrBridge*>(mapNode(XercesDOM_NodeHack::getImpl(theXercesNode)));
#endif
}



XalanElement*
XercesDocumentBridge::mapNode(const DOM_Element& 	theXercesNode) const
{
#if defined(XALAN_OLD_STYLE_CASTS)
	return (XercesElementBridge*)mapNode(XercesDOM_NodeHack::getImpl(theXercesNode));
#else
	return static_cast<XercesElementBridge*>(mapNode(XercesDOM_NodeHack::getImpl(theXercesNode)));
#endif
}



void
XercesDocumentBridge::destroyBridge()
{
#if !defined(XALAN_NO_NAMESPACES)
	using std::for_each;
#endif

	// Set this to null, since it will be deleted
	// by the next for_each...
	m_doctype = 0;

	// m_bridgeMap contains all of the nodes that
	// are still alive...
	for_each(m_nodes.begin(),
			 m_nodes.end(),
			 DeleteFunctor<XalanNode>());

	// Clear everything out, since we just delete everything...
	m_nodes.clear();

	// Clear out all of the navigators, except ours...
	m_navigators.erase(m_navigators.begin() + 1, m_navigators.end());

	// Clear the node map...
	m_nodeMap.clear();

	m_indexValid = false;

	m_mappingMode = true;
}



void
XercesDocumentBridge::rebuildBridge()
{
	destroyBridge();

	buildBridgeNodes();
}



XercesBridgeNavigator&
XercesDocumentBridge::pushNavigator(bool	mappingMode) const
{
	XercesDocumentBridge* const		This =
#if defined(XALAN_OLD_STYLE_CASTS)
		(XercesDocumentBridge*)this;
#else
		const_cast<XercesDocumentBridge*>(this);
#endif

	This->m_navigators.push_back(XercesBridgeNavigator(This, mappingMode));

	return This->m_navigators.back();
}



XercesDocumentTypeBridge*
XercesDocumentBridge::createBridgeNode(
			const DOM_DocumentType&		theDoctype,
			unsigned long				theIndex,
			bool						mapNode) const
{
	// This is a special case, since there is only one
	// doctype node allowed...
	assert(m_doctype == 0);
	assert(m_xercesDocument.getDoctype().isNull() == false &&
		   m_xercesDocument.getDoctype() == theDoctype);

	// Create a navigator...
	XercesBridgeNavigator&	theNavigator = pushNavigator(mapNode);

	theNavigator.setIndex(theIndex);

#if defined(XALAN_NO_MUTABLE)
	XercesDocumentBridge* const		This =
		(XercesDocumentBridge*)this;

	// Update the member variable for the new instance.
	This->m_doctype = new XercesDocumentTypeBridge(theDoctype, theNavigator);

	if (mapNode == true)
	{
		This->m_nodeMap.addAssociation(theDoctype, m_doctype);
	}

	This->m_nodes.push_back(m_doctype);
#else
	// Update the member variable for the new instance.
	m_doctype = new XercesDocumentTypeBridge(theDoctype, theNavigator);

	if (mapNode == true)
	{
		m_nodeMap.addAssociation(theDoctype, m_doctype);
	}

	m_nodes.push_back(m_doctype);
#endif

	return m_doctype;
}



XercesElementBridge*
XercesDocumentBridge::createBridgeNode(
			const DOM_Element& 	theXercesNode,
			unsigned long		theIndex,
			bool				mapNode) const
{
	// Create a navigator...
	XercesBridgeNavigator&	theNavigator = pushNavigator(mapNode);

	theNavigator.setIndex(theIndex);

#if defined(XALAN_NO_MUTABLE)
	XercesDocumentBridge* const		This =
		(XercesDocumentBridge*)this;

	XercesElementBridge* const	theBridge =
#if defined(XALAN_USE_BLOCK_ALLOCATORS)
		This->m_elementAllocator.create(theXercesNode,
										theNavigator);
#else
		new XercesElementBridge(theXercesNode,
								theNavigator);

	This->m_nodes.push_back(theBridge);
#endif

	if (m_doctype != 0 || mapNode == true)
	{
		// Add it to the node map, since we my need it for getting
		// elements by ID, or we're in mapping mode.
		This->m_nodeMap.addAssociation(theXercesNode, theBridge);
	}

#else	// XALAN_NO_MUTABLE

	XercesElementBridge* const	theBridge =
#if defined(XALAN_USE_BLOCK_ALLOCATORS)
		m_elementAllocator.create(theXercesNode,
								theNavigator);
#else
		new XercesElementBridge(theXercesNode,
								theNavigator);

	m_nodes.push_back(theBridge);
#endif

	if (m_doctype != 0 || mapNode == true)
	{
		// Add it to the node map, since we my need it for getting
		// elements by ID, or we're in mapping mode.
		m_nodeMap.addAssociation(theXercesNode, theBridge);
	}
#endif

	return theBridge;
}



XercesDocumentFragmentBridge*
XercesDocumentBridge::createBridgeNode(
			const DOM_DocumentFragment&		theXercesNode,
			unsigned long					theIndex,
			bool							mapNode) const
{
	// Create a navigator...
	XercesBridgeNavigator&	theNavigator = pushNavigator(mapNode);

	theNavigator.setIndex(theIndex);

	XercesDocumentFragmentBridge* const		theBridge =
		new XercesDocumentFragmentBridge(theXercesNode,
										 theNavigator);

#if defined(XALAN_NO_MUTABLE)
	XercesDocumentBridge* const		This =
		(XercesDocumentBridge*)this;

	This->m_nodes.push_back(theBridge);

	if (mapNode == true)
	{
		// Add it to the node map...
		This->m_nodeMap.addAssociation(theXercesNode, theBridge);
	}
#else
	m_nodes.push_back(theBridge);

	if (mapNode == true)
	{
		// Add it to the node map...
		m_nodeMap.addAssociation(theXercesNode, theBridge);
	}
#endif

	return theBridge;
}



XercesTextBridge*
XercesDocumentBridge::createBridgeNode(
			const DOM_Text&		theXercesNode,
			unsigned long		theIndex,
			bool				mapNode) const
{
	// Create a navigator...
	XercesBridgeNavigator&	theNavigator = pushNavigator(mapNode);

	theNavigator.setIndex(theIndex);

#if defined(XALAN_NO_MUTABLE)
	XercesDocumentBridge* const		This =
		(XercesDocumentBridge*)this;

	XercesTextBridge* const		theBridge =
#if defined(XALAN_USE_BLOCK_ALLOCATORS)
		This->m_textAllocator.create(theXercesNode,
									 theNavigator);
#else
		new XercesTextBridge(theXercesNode,
							 theNavigator);

	This->m_nodes.push_back(theBridge);
#endif

	if (mapNode == true)
	{
		// Add it to the node map...
		This->m_nodeMap.addAssociation(theXercesNode, theBridge);
	}

#else	// XALAN_NO_MUTABLE

	XercesTextBridge* const		theBridge =
#if defined(XALAN_USE_BLOCK_ALLOCATORS)
		m_textAllocator.create(theXercesNode,
							   theNavigator);
#else
		new XercesTextBridge(theXercesNode,
							 theNavigator);

	m_nodes.push_back(theBridge);
#endif

	if (mapNode == true)
	{
		// Add it to the node map...
		m_nodeMap.addAssociation(theXercesNode, theBridge);
	}

#endif

	return theBridge;
}



XercesCommentBridge*
XercesDocumentBridge::createBridgeNode(
			const DOM_Comment&	theXercesNode,
			unsigned long		theIndex,
			bool				mapNode) const
{
	// Create a navigator...
	XercesBridgeNavigator&	theNavigator = pushNavigator(mapNode);

	theNavigator.setIndex(theIndex);

	XercesCommentBridge* const	theBridge =
		new XercesCommentBridge(theXercesNode,
								theNavigator);

#if defined(XALAN_NO_MUTABLE)
	XercesDocumentBridge* const		This =
		(XercesDocumentBridge*)this;

	This->m_nodes.push_back(theBridge);

	if (mapNode == true)
	{
		// Add it to the node map...
		This->m_nodeMap.addAssociation(theXercesNode, theBridge);
	}

#else	// XALAN_NO_MUTABLE

	m_nodes.push_back(theBridge);

	if (mapNode == true)
	{
		// Add it to the node map...
		m_nodeMap.addAssociation(theXercesNode, theBridge);
	}

#endif

	return theBridge;
}



XercesCDATASectionBridge*
XercesDocumentBridge::createBridgeNode(
			const DOM_CDATASection&		theXercesNode,
			unsigned long				theIndex,
			bool						mapNode) const
{
	// Create a navigator...
	XercesBridgeNavigator&	theNavigator = pushNavigator(mapNode);

	theNavigator.setIndex(theIndex);

	XercesCDATASectionBridge* const		theBridge =
		new XercesCDATASectionBridge(theXercesNode,
									 theNavigator);

#if defined(XALAN_NO_MUTABLE)
	XercesDocumentBridge* const		This =
		(XercesDocumentBridge*)this;

	This->m_nodes.push_back(theBridge);

	if (mapNode == true)
	{
		// Add it to the node map...
		This->m_nodeMap.addAssociation(theXercesNode, theBridge);
	}

#else	// XALAN_NO_MUTABLE

	m_nodes.push_back(theBridge);

	if (mapNode == true)
	{
		// Add it to the node map...
		m_nodeMap.addAssociation(theXercesNode, theBridge);
	}

#endif

	return theBridge;
}



XercesProcessingInstructionBridge*
XercesDocumentBridge::createBridgeNode(
			const DOM_ProcessingInstruction&	theXercesNode,
			unsigned long						theIndex,
			bool								mapNode) const
{
	// Create a navigator...
	XercesBridgeNavigator&	theNavigator = pushNavigator(mapNode);

	theNavigator.setIndex(theIndex);

	XercesProcessingInstructionBridge* const	theBridge =
		new XercesProcessingInstructionBridge(theXercesNode,
											  theNavigator);

#if defined(XALAN_NO_MUTABLE)
	XercesDocumentBridge* const		This =
		(XercesDocumentBridge*)this;

	This->m_nodes.push_back(theBridge);

	if (mapNode == true)
	{
		// Add it to the node map...
		This->m_nodeMap.addAssociation(theXercesNode, theBridge);
	}

#else	// XALAN_NO_MUTABLE

	m_nodes.push_back(theBridge);

	if (mapNode == true)
	{
		// Add it to the node map...
		m_nodeMap.addAssociation(theXercesNode, theBridge);
	}

#endif

	return theBridge;
}



XercesAttrBridge*
XercesDocumentBridge::createBridgeNode(
			const DOM_Attr&		theXercesNode,
			unsigned long		theIndex,
			bool				mapNode) const
{
	// Create a navigator...
	XercesBridgeNavigator&	theNavigator = pushNavigator(mapNode);

	theNavigator.setIndex(theIndex);

#if defined(XALAN_NO_MUTABLE)
	XercesDocumentBridge* const		This =
		(XercesDocumentBridge*)this;

	XercesAttrBridge* const		theBridge =
#if defined(XALAN_USE_BLOCK_ALLOCATORS)
		This->m_attributeAllocator.create(theXercesNode,
										  theNavigator);
#else
		new XercesAttrBridge(theXercesNode,
							 theNavigator);

	This->m_nodes.push_back(theBridge);
#endif

	// Add it to the node map -- attributes ALWAYS go in the map
	// for now...
	This->m_nodeMap.addAssociation(theXercesNode, theBridge);

#else	// XALAN_NO_MUTABLE

	XercesAttrBridge* const		theBridge =
#if defined(XALAN_USE_BLOCK_ALLOCATORS)
		m_attributeAllocator.create(theXercesNode,
									theNavigator);
#else
		new XercesAttrBridge(theXercesNode,
							 theNavigator);

	m_nodes.push_back(theBridge);
#endif

	// Add it to the node map -- attributes ALWAYS go in the map
	// for now...
	m_nodeMap.addAssociation(theXercesNode, theBridge);

#endif

	return theBridge;
}



XercesEntityBridge*
XercesDocumentBridge::createBridgeNode(
			const DOM_Entity&	theXercesNode,
			unsigned long		theIndex,
			bool				mapNode) const
{
	// Create a navigator...
	XercesBridgeNavigator&	theNavigator = pushNavigator(mapNode);

	theNavigator.setIndex(theIndex);

	XercesEntityBridge* const	theBridge =
		new XercesEntityBridge(theXercesNode,
							   theNavigator);

#if defined(XALAN_NO_MUTABLE)
	XercesDocumentBridge* const		This =
		(XercesDocumentBridge*)this;

	This->m_nodes.push_back(theBridge);

	// Add it to the node map -- entities ALWAYS go in the map
	// for now...
	This->m_nodeMap.addAssociation(theXercesNode, theBridge);

#else	// XALAN_NO_MUTABLE

	m_nodes.push_back(theBridge);

	// Add it to the node map -- entities ALWAYS go in the map
	// for now...
	m_nodeMap.addAssociation(theXercesNode, theBridge);

#endif

	return theBridge;
}



XercesEntityReferenceBridge*
XercesDocumentBridge::createBridgeNode(
			const DOM_EntityReference& 	theXercesNode,
			unsigned long				theIndex,
			bool						mapNode) const
{
	// Create a navigator...
	XercesBridgeNavigator&	theNavigator = pushNavigator(mapNode);

	theNavigator.setIndex(theIndex);

	XercesEntityReferenceBridge* const	theBridge =
		new XercesEntityReferenceBridge(theXercesNode,
										theNavigator);

#if defined(XALAN_NO_MUTABLE)
	XercesDocumentBridge* const		This =
		(XercesDocumentBridge*)this;

	This->m_nodes.push_back(theBridge);

	if (mapNode == true)
	{
		// Add it to the node map...
		This->m_nodeMap.addAssociation(theXercesNode, theBridge);
	}

#else	// XALAN_NO_MUTABLE

	m_nodes.push_back(theBridge);

	if (mapNode == true)
	{
		// Add it to the node map...
		m_nodeMap.addAssociation(theXercesNode, theBridge);
	}

#endif

	return theBridge;
}



XercesNotationBridge*
XercesDocumentBridge::createBridgeNode(
			const DOM_Notation&		theXercesNode,
			unsigned long			theIndex,
			bool					mapNode) const
{
	// Create a navigator...
	XercesBridgeNavigator&	theNavigator = pushNavigator(mapNode);

	theNavigator.setIndex(theIndex);

	XercesNotationBridge* const		theBridge =
		new XercesNotationBridge(theXercesNode,
								 theNavigator);

#if defined(XALAN_NO_MUTABLE)
	XercesDocumentBridge* const		This =
		(XercesDocumentBridge*)this;

	This->m_nodes.push_back(theBridge);

	// Add it to the node map -- notations ALWAYS go in the map
	// for now...
	This->m_nodeMap.addAssociation(theXercesNode, theBridge);

#else	// XALAN_NO_MUTABLE

	m_nodes.push_back(theBridge);

	// Add it to the node map -- notations ALWAYS go in the map
	// for now...
	m_nodeMap.addAssociation(theXercesNode, theBridge);

#endif

	return theBridge;
}



XalanNode*
XercesDocumentBridge::createBridgeNode(
			const DOM_Node&		theXercesNode,
			unsigned long		theIndex,
			bool				mapNode) const
{
	XalanNode*				theNewNode = 0;

	switch(theXercesNode.getNodeType())
	{
	case DOM_Node::ATTRIBUTE_NODE:
		{
			const DOM_Attr&		theAttrNode =
#if defined(XALAN_OLD_STYLE_CASTS)
						(const DOM_Attr&)theXercesNode;
#else
						static_cast<const DOM_Attr&>(theXercesNode);
#endif

			theNewNode = createBridgeNode(theAttrNode, theIndex, mapNode);
			assert(theNewNode != 0);
		}
		break;

	case DOM_Node::CDATA_SECTION_NODE:
		{
			const DOM_CDATASection&		theCDATASectionNode =
#if defined(XALAN_OLD_STYLE_CASTS)
						(const DOM_CDATASection&)theXercesNode;
#else
						static_cast<const DOM_CDATASection&>(theXercesNode);
#endif

			theNewNode = createBridgeNode(theCDATASectionNode, theIndex, mapNode);
			assert(theNewNode != 0);

		}
		break;

	case DOM_Node::COMMENT_NODE:
		{
			const DOM_Comment&	theCommentNode =
#if defined(XALAN_OLD_STYLE_CASTS)
						(const DOM_Comment&)theXercesNode;
#else
						static_cast<const DOM_Comment&>(theXercesNode);
#endif

			theNewNode = createBridgeNode(theCommentNode, theIndex, mapNode);
			assert(theNewNode != 0);
		}
		break;

	case DOM_Node::DOCUMENT_FRAGMENT_NODE:
		{
			const DOM_DocumentFragment&		theDocumentFragmentNode =
#if defined(XALAN_OLD_STYLE_CASTS)
						(const DOM_DocumentFragment&)theXercesNode;
#else
						static_cast<const DOM_DocumentFragment&>(theXercesNode);
#endif

			theNewNode = createBridgeNode(theDocumentFragmentNode, theIndex, mapNode);
			assert(theNewNode != 0);

		}
		break;

	case DOM_Node::ELEMENT_NODE:
		{
			const DOM_Element&	theElementNode =
#if defined(XALAN_OLD_STYLE_CASTS)
						(const DOM_Element&)theXercesNode;
#else
						static_cast<const DOM_Element&>(theXercesNode);
#endif

			theNewNode = createBridgeNode(theElementNode, theIndex, mapNode);
			assert(theNewNode != 0);
		}
		break;

	case DOM_Node::ENTITY_NODE:
		{
			const DOM_Entity&	theEntityNode =
#if defined(XALAN_OLD_STYLE_CASTS)
						(const DOM_Entity&)theXercesNode;
#else
						static_cast<const DOM_Entity&>(theXercesNode);
#endif

			theNewNode = createBridgeNode(theEntityNode, theIndex, mapNode);
			assert(theNewNode != 0);
		}
		break;

	case DOM_Node::ENTITY_REFERENCE_NODE:
		{
			const DOM_EntityReference&	theEntityReferenceNode =
#if defined(XALAN_OLD_STYLE_CASTS)
						(const DOM_EntityReference&)theXercesNode;
#else
						static_cast<const DOM_EntityReference&>(theXercesNode);
#endif

			theNewNode = createBridgeNode(theEntityReferenceNode, theIndex, mapNode);
			assert(theNewNode != 0);
		}
		break;

	case DOM_Node::NOTATION_NODE:
		{
			const DOM_Notation&		theNotationNode =
#if defined(XALAN_OLD_STYLE_CASTS)
						(const DOM_Notation&)theXercesNode;
#else
						static_cast<const DOM_Notation&>(theXercesNode);
#endif

			theNewNode = createBridgeNode(theNotationNode, theIndex, mapNode);
			assert(theNewNode != 0);
		}
		break;

	case DOM_Node::PROCESSING_INSTRUCTION_NODE:
		{
			const DOM_ProcessingInstruction&	thePINode =
#if defined(XALAN_OLD_STYLE_CASTS)
						(const DOM_ProcessingInstruction&)theXercesNode;
#else
						static_cast<const DOM_ProcessingInstruction&>(theXercesNode);
#endif

			theNewNode = createBridgeNode(thePINode, theIndex, mapNode);
			assert(theNewNode != 0);
		}
		break;

	case DOM_Node::TEXT_NODE:
		{
			const DOM_Text&		theTextNode =
#if defined(XALAN_OLD_STYLE_CASTS)
						(const DOM_Text&)theXercesNode;
#else
						static_cast<const DOM_Text&>(theXercesNode);
#endif

			theNewNode = createBridgeNode(theTextNode, theIndex, mapNode);
			assert(theNewNode != 0);
		}
		break;

	case DOM_Node::DOCUMENT_TYPE_NODE:
		{
			const DOM_DocumentType&		theDoctypeNode =
#if defined(XALAN_OLD_STYLE_CASTS)
						(const DOM_DocumentType&)theXercesNode;
#else
						static_cast<const DOM_DocumentType&>(theXercesNode);
#endif

			theNewNode = createBridgeNode(theDoctypeNode, theIndex, mapNode);

			assert(theNewNode != 0);
		}
		break;

	default:
		assert(false);
		break;
	}

	return theNewNode;
}



void
XercesDocumentBridge::destroyNode(XalanNode*	theNode)
{
#if !defined(XALAN_NO_NAMESPACES)
	using std::find;
#endif

	const NodeVectorType::iterator 	i =
		find(m_nodes.begin(), m_nodes.end(), theNode);

	if (i == m_nodes.end())
	{
		// Doesn't belong to this doc, so throw...
		throw XercesDOMException(XercesDOMException::WRONG_DOCUMENT_ERR);
	}
	else
	{
		// Delete the node...
		delete *i;

		// Erase it from the map...
		m_nodes.erase(i);
	}
}



XalanNode*
XercesDocumentBridge::internalCloneNode(
			const XalanNode*	theXalanNode,
			const DOM_Node&		theXercesNode,
			bool				deep)
{
	XalanNode*	theNewNode = 0;

	if (theXalanNode->getOwnerDocument() != this)
	{
		throw XercesDOMException(XercesDOMException::WRONG_DOCUMENT_ERR);
	}

	try
	{
		const DOM_Node	theNewXercesNode = 
			theXercesNode.cloneNode(deep);

		theNewNode = createBridgeNode(theNewXercesNode, 0, true);
	}
	catch(const DOM_DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}

	return theNewNode;
}



// The rest of these are the standard DOM interfaces...

XalanDOMString
XercesDocumentBridge::getNodeName() const
{
	return m_xercesDocument.getNodeName();
}



XalanDOMString
XercesDocumentBridge::getNodeValue() const
{
	return m_xercesDocument.getNodeValue();
}



XercesDocumentBridge::NodeType
XercesDocumentBridge::getNodeType() const
{
	return DOCUMENT_NODE;
}



XalanNode*
XercesDocumentBridge::getParentNode() const
{
	return 0;
}



const XalanNodeList*
XercesDocumentBridge::getChildNodes() const
{
	return &m_children;
}



XalanNode*
XercesDocumentBridge::getFirstChild() const
{
	return m_navigator.getFirstChild(m_xercesDocument);
}



XalanNode*
XercesDocumentBridge::getLastChild() const
{
	return m_navigator.getLastChild(m_xercesDocument);
}



XalanNode*
XercesDocumentBridge::getPreviousSibling() const
{
	return 0;
}



XalanNode*
XercesDocumentBridge::getNextSibling() const
{
	return 0;
}



const XalanNamedNodeMap*
XercesDocumentBridge::getAttributes() const
{
	return 0;
}



XalanDocument*
XercesDocumentBridge::getOwnerDocument() const
{
	return 0;
}



#if defined(XALAN_NO_COVARIANT_RETURN_TYPE)
XalanNode*
#else
XercesDocumentBridge*
#endif
XercesDocumentBridge::cloneNode(bool	deep) const
{
	XercesDocumentBridge*	theBridge = 0;

	try
	{
		const DOM_Node	theNewDocument = m_xercesDocument.cloneNode(deep);

		theBridge =
#if defined(XALAN_OLD_STYLE_CASTS)
			new XercesDocumentBridge((const DOM_Document&)theNewDocument);
#else
			new XercesDocumentBridge(static_cast<const DOM_Document&>(theNewDocument));
#endif
	}
	catch(const DOM_DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}

	return theBridge;
}



XalanNode*
XercesDocumentBridge::insertBefore(
			XalanNode*	newChild,
			XalanNode*	refChild)
{
	return m_navigator.insertBefore(m_xercesDocument, newChild, refChild);
}



XalanNode*
XercesDocumentBridge::replaceChild(
			XalanNode*	newChild,
			XalanNode*	oldChild)
{
	return m_navigator.replaceChild(m_xercesDocument, newChild, oldChild);
}



XalanNode*
XercesDocumentBridge::removeChild(XalanNode*	 oldChild)
{
	return m_navigator.removeChild(m_xercesDocument, oldChild);
}



XalanNode*
XercesDocumentBridge::appendChild(XalanNode*	newChild)
{
	return m_navigator.appendChild(m_xercesDocument, newChild);
}



bool
XercesDocumentBridge::hasChildNodes() const
{
	return m_xercesDocument.hasChildNodes();
}



void
XercesDocumentBridge::setNodeValue(const XalanDOMString&	nodeValue)
{
	try
	{
		m_xercesDocument.setNodeValue(nodeValue);
	}
	catch(const DOM_DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}
}



void
XercesDocumentBridge::normalize()
{
	try
	{
		m_xercesDocument.normalize();
	}
	catch(const DOM_DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}
}


bool
XercesDocumentBridge::supports(
			const XalanDOMString&	feature,
			const XalanDOMString&	version) const
{
	return m_xercesDocument.supports(feature, version);
}



XalanDOMString
XercesDocumentBridge::getNamespaceURI() const
{
	return m_xercesDocument.getNamespaceURI();
}



XalanDOMString
XercesDocumentBridge::getPrefix() const
{
	return m_xercesDocument.getPrefix();
}



XalanDOMString
XercesDocumentBridge::getLocalName() const
{
	return m_xercesDocument.getLocalName();
}



void
XercesDocumentBridge::setPrefix(const XalanDOMString&	prefix)
{
	try
	{
		m_xercesDocument.setPrefix(prefix);
	}
	catch(const DOM_DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}
}



bool
XercesDocumentBridge::isIndexed() const
{
	return m_indexValid;
}



unsigned long
XercesDocumentBridge::getIndex() const
{
	assert(m_navigator.getIndex() == 1);

	return m_navigator.getIndex();
}



XalanDOMString
XercesDocumentBridge::getXSLTData() const
{
	return DOMServices::getNodeData(*this);
}



XalanElement*
XercesDocumentBridge::createElement(const XalanDOMString&	tagName)
{
	XalanElement*	theBridgeNode = 0;

	try
	{
		const DOM_Element	theXercesNode =
			m_xercesDocument.createElement(tagName);
		assert(theXercesNode.isNull() == false);

		theBridgeNode = createBridgeNode(theXercesNode, 0, true);
		assert(mapNode(theXercesNode) == theBridgeNode);
	}
	catch(const DOM_DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}

	return theBridgeNode;
}



XalanDocumentFragment*
XercesDocumentBridge::createDocumentFragment()
{
	XalanDocumentFragment*	theBridgeNode = 0;

	try
	{
		const DOM_DocumentFragment	theXercesNode =
			m_xercesDocument.createDocumentFragment();
		assert(theXercesNode.isNull() == false);

		theBridgeNode = createBridgeNode(theXercesNode, 0, true);
		assert(mapNode(theXercesNode) == theBridgeNode);
	}
	catch(const DOM_DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}

	return theBridgeNode;
}



XalanText*
XercesDocumentBridge::createTextNode(const XalanDOMString&	data)
{
	XalanText*	theBridgeNode = 0;

	try
	{
		const DOM_Text	theXercesNode =
			m_xercesDocument.createTextNode(data);
		assert(theXercesNode.isNull() == false);

		theBridgeNode = createBridgeNode(theXercesNode, 0, true);
		assert(mapNode(theXercesNode) == theBridgeNode);
	}
	catch(const DOM_DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}

	return theBridgeNode;
}



XalanComment*
XercesDocumentBridge::createComment(const XalanDOMString&	data)
{
	XalanComment*	theBridgeNode = 0;

	try
	{
		const DOM_Comment	theXercesNode =
			m_xercesDocument.createComment(data);
		assert(theXercesNode.isNull() == false);

		theBridgeNode = createBridgeNode(theXercesNode, 0, true);
		assert(mapNode(theXercesNode) == theBridgeNode);
	}
	catch(const DOM_DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}

	return theBridgeNode;
}



XalanCDATASection*
XercesDocumentBridge::createCDATASection(const XalanDOMString&	data)
{
	XalanCDATASection*	theBridgeNode = 0;

	try
	{
		const DOM_CDATASection	theXercesNode =
			m_xercesDocument.createCDATASection(data);
		assert(theXercesNode.isNull() == false);

		theBridgeNode = createBridgeNode(theXercesNode, 0, true);
		assert(mapNode(theXercesNode) == theBridgeNode);
	}
	catch(const DOM_DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}

	return theBridgeNode;
}



XalanProcessingInstruction*
XercesDocumentBridge::createProcessingInstruction(
			const XalanDOMString&	target,
			const XalanDOMString&	data)
{
	XalanProcessingInstruction*	theBridgeNode = 0;

	try
	{
		const DOM_ProcessingInstruction	theXercesNode =
			m_xercesDocument.createProcessingInstruction(target, data);
		assert(theXercesNode.isNull() == false);

		theBridgeNode = createBridgeNode(theXercesNode, 0, true);
		assert(mapNode(theXercesNode) == theBridgeNode);
	}
	catch(const DOM_DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}

	return theBridgeNode;
}



XalanAttr*
XercesDocumentBridge::createAttribute(const XalanDOMString&		name)
{
	XalanAttr*	theBridgeNode = 0;

	try
	{
		const DOM_Attr	theXercesNode =
			m_xercesDocument.createAttribute(name);
		assert(theXercesNode.isNull() == false);

		theBridgeNode = createBridgeNode(theXercesNode, 0, true);
		assert(mapNode(theXercesNode) == theBridgeNode);
	}
	catch(const DOM_DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}

	return theBridgeNode;
}



XalanEntityReference*
XercesDocumentBridge::createEntityReference(const XalanDOMString&	name)
{
	XalanEntityReference*	theBridgeNode = 0;

	try
	{
		const DOM_EntityReference	theXercesNode =
			m_xercesDocument.createEntityReference(name);
		assert(theXercesNode.isNull() == false);

		theBridgeNode = createBridgeNode(theXercesNode, 0, true);
		assert(mapNode(theXercesNode) == theBridgeNode);
	}
	catch(const DOM_DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}

	return theBridgeNode;
}



XalanDocumentType*
XercesDocumentBridge::getDoctype() const
{
	return m_doctype;
}




XalanDOMImplementation*
XercesDocumentBridge::getImplementation() const
{
	return m_domImplementation.get();
}



XalanElement*
XercesDocumentBridge::getDocumentElement() const
{
	// If we're working in mapping mode, m_documentElement will
	// be null, so we'll have to map the node...
	return m_documentElement != 0 ? m_documentElement : mapNode(m_xercesDocument.getDocumentElement());
}



XalanNodeList*
XercesDocumentBridge::getElementsByTagName(const XalanDOMString&	tagname) const
{
	return m_cachedNodeLists.getElementsByTagName(tagname);
}



XalanNode*
XercesDocumentBridge::importNode(
			XalanNode*	importedNode,
			bool		deep)
{
	// $$$ToDo: Fix this....
	// The problem is that we must get the Xerces node that corresponds to the
	// importedNode parameter.  We could assume that it is indeed a node from
	// another XercesDocumentBridge, but I'm not sure that we should do that.
	throw XercesDOMException(XercesDOMException::NO_MODIFICATION_ALLOWED_ERR);

	return 0;
}



XalanElement*
XercesDocumentBridge::createElementNS(
			const XalanDOMString&	namespaceURI,
			const XalanDOMString&	qualifiedName)
{
	XalanElement*	theBridgeNode = 0;

	try
	{
		const DOM_Element	theXercesNode =
			m_xercesDocument.createElementNS(namespaceURI, qualifiedName);
		assert(theXercesNode.isNull() == false);

		theBridgeNode = createBridgeNode(theXercesNode, 0, true);
		assert(mapNode(theXercesNode) == theBridgeNode);
	}
	catch(const DOM_DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}

	return theBridgeNode;
}



XalanAttr*
XercesDocumentBridge::createAttributeNS(
			const XalanDOMString&	namespaceURI,
			const XalanDOMString&	qualifiedName)
{
	XalanAttr*	theBridgeNode = 0;

	try
	{
		const DOM_Attr	theXercesNode =
			m_xercesDocument.createAttributeNS(namespaceURI, qualifiedName);
		assert(theXercesNode.isNull() == false);

		theBridgeNode = createBridgeNode(theXercesNode, 0, true);
		assert(mapNode(theXercesNode) == theBridgeNode);
	}
	catch(const DOM_DOMException&	theException)
	{
		throw XercesDOMException(theException);
	}

	return theBridgeNode;
}



XalanNodeList*
XercesDocumentBridge::getElementsByTagNameNS(
			const XalanDOMString&	namespaceURI,
			const XalanDOMString&	localName) const
{
	return m_cachedNodeLists.getElementsByTagNameNS(namespaceURI, localName);
}



XalanElement*
XercesDocumentBridge::getElementById(const XalanDOMString&	elementId) const
{
	// $$$ ToDo: This is because DOM_Document::getElementById() is not
	// const...
#if defined(XALAN_NO_MUTABLE)
	const DOM_Node	theXercesNode(((DOM_Document&)m_xercesDocument).getElementById(elementId));
#else
	const DOM_Node	theXercesNode(m_xercesDocument.getElementById(elementId));
#endif

	return theXercesNode.isNull() == true ? 0 :
#if defined(XALAN_OLD_STYLE_CASTS)
				(XalanElement*)mapNode(theXercesNode);
#else
				static_cast<XalanElement*>(mapNode(theXercesNode));
#endif
}



void
XercesDocumentBridge::buildBridgeNodes()
{
	const DOM_Node	theStartChild = m_xercesDocument.getFirstChild();

	if (theStartChild.isNull() == false)
	{
		assert(m_navigators.back().getIndex() == 1);
		assert(m_navigators.size() == 1);

		BuildBridgeTreeWalker	theTreeWalker(
				this,
				&m_navigators.back(),
				m_navigators,
				2);

		theTreeWalker.traverse(theStartChild, m_xercesDocument);
	}

	// OK, now set m_documentElement...
	XalanNode*	theChild = m_navigator.getFirstChild();

	while(theChild != 0 && theChild->getNodeType() != XalanNode::ELEMENT_NODE)
	{
		theChild = theChild->getNextSibling();
	}

#if defined(XALAN_OLD_STYLE_CASTS)
	m_documentElement = (XalanElement*)theChild;
#else
	m_documentElement = static_cast<XalanElement*>(theChild);
#endif

	m_indexValid = true;

	m_mappingMode = false;
}



XercesDocumentBridge::BuildBridgeTreeWalker::BuildBridgeTreeWalker(
			XercesDocumentBridge*		theDocument,
			XercesBridgeNavigator*		theDocumentNavigator,
			NavigatorBridgeVectorType&	theNavigators,
			unsigned long				theStartIndex) :
	m_document(theDocument),
	m_navigators(theNavigators),
	m_currentIndex(theStartIndex),
	m_parentNavigatorStack(),
	m_siblingNavigatorStack()
{
	assert(theDocument != 0 && theDocumentNavigator != 0);

	// Reserve some space...
	m_parentNavigatorStack.reserve(100);
	m_parentNavigatorStack.reserve(100);

	// The document navigator is the last navigator on the stack...
	m_parentNavigatorStack.push_back(NavigatorStackEntryType(theDocumentNavigator, theDocument));

	// There is no previous sibling...
	m_siblingNavigatorStack.push_back(NavigatorStackEntryType(0, 0));
}



XercesDocumentBridge::BuildBridgeTreeWalker::~BuildBridgeTreeWalker()
{
}



void
XercesDocumentBridge::BuildBridgeTreeWalker::startNode(const DOM_Node&	node)
{
	XalanNode* const	theBridgeNode = m_document->createBridgeNode(node, m_currentIndex, false);

	XercesBridgeNavigator&	theCurrentNodeNavigator = m_navigators.back();

	assert(m_parentNavigatorStack.empty() == false);
	assert(m_siblingNavigatorStack.empty() == false);

	// Get the two navigators...
	NavigatorStackEntryType&	theParentEntry = m_parentNavigatorStack.back();
	NavigatorStackEntryType&	theSiblingEntry = m_siblingNavigatorStack.back();

	theCurrentNodeNavigator.setParentNode(theParentEntry.m_node);

	// If the first child has not been set, then set it
	// now...
	if (theParentEntry.m_navigator->getFirstChild() == 0)
	{
		assert(theSiblingEntry.m_node == 0);

		theParentEntry.m_navigator->setFirstChild(theBridgeNode);
	}

	// Always set the last child...
	theParentEntry.m_navigator->setLastChild(theBridgeNode);

	theCurrentNodeNavigator.setPreviousSibling(theSiblingEntry.m_node);

	if (theSiblingEntry.m_navigator != 0)
	{
		theSiblingEntry.m_navigator->setNextSibling(theBridgeNode);
	}

	// Build an entry for the stacks...
	const NavigatorStackEntryType	theCurrentEntry(&theCurrentNodeNavigator, theBridgeNode);

	// My child nodes will now be visited, so push the current
	// context on the parent stack...
	m_parentNavigatorStack.push_back(theCurrentEntry);

	// My siblings will also need to know about me as well...
	m_siblingNavigatorStack.push_back(theCurrentEntry);

	// This will serve to mark the sibling context for my first child,
	// since it has no previous sibling.  This will be popped off
	// when endNode() is called.
	m_siblingNavigatorStack.push_back(NavigatorStackEntryType(0, 0));

	// Finally, increment the index counter...
	++m_currentIndex;

	const short		theType = node.getNodeType();

	if (theType == DOM_Node::DOCUMENT_TYPE_NODE)
	{
		// Special case for doctype -- we have to build its entities...
		const DOM_DocumentType&		theDoctype =
#if defined(XALAN_OLD_STYLE_CASTS)
			(const DOM_DocumentType&)node;
#else
			static_cast<const DOM_DocumentType&>(node);
#endif

		const DOM_NamedNodeMap	theEntities =
			theDoctype.getEntities();

		const unsigned int	theLength =
			theEntities.getLength();

		for (unsigned int i = 0; i < theLength; ++i)
		{
			// Build it, but don't index it...
			m_document->createBridgeNode(theEntities.item(i), m_currentIndex++, true);
		}
	}
	else if (theType == DOM_Node::ELEMENT_NODE)
	{
	// Special case for element nodes -- we have to build the attributes...
		const DOM_Element&	theElement =
#if defined(XALAN_OLD_STYLE_CASTS)
			(const DOM_Element&)node;
#else
			static_cast<const DOM_Element&>(node);
#endif

		const DOM_NamedNodeMap	theAttributes =
			theElement.getAttributes();

		const unsigned int	theLength =
			theAttributes.getLength();

		XercesBridgeNavigator*	thePreviousAttrNavigator = 0;
		XalanNode*				thePreviousAttr = 0;

		for (unsigned int i = 0; i < theLength; ++i)
		{
			// Get the attribute from the node map...
			const DOM_Node	theAttr = theAttributes.item(i);
			assert(theAttr.isNull() == false);

			// Create a bridge node.
			XalanNode* const	theCurrentAttr =
				m_document->createBridgeNode(theAttr, m_currentIndex, false);
			assert(theCurrentAttr != 0);

			// Get the attribute node's navigator...
			XercesBridgeNavigator&	theCurrentAttrNavigator =
				m_navigators.back();

			// Set the parent node...
			theCurrentAttrNavigator.setParentNode(theBridgeNode);

			if (thePreviousAttr != 0)
			{
				assert(thePreviousAttrNavigator != 0);

				// Link in the previous attribute...
				theCurrentAttrNavigator.setPreviousSibling(thePreviousAttr);

				thePreviousAttrNavigator->setNextSibling(theCurrentAttr);
			}

			// Update the pointers so they point to this attribute...
			thePreviousAttr = theCurrentAttr;
			thePreviousAttrNavigator = &theCurrentAttrNavigator;

			// Finally, increment the index...
			++m_currentIndex;
		}
	}
}



void
XercesDocumentBridge::BuildBridgeTreeWalker::endNode(const DOM_Node&	/* node */)
{
	assert(m_parentNavigatorStack.empty() == false);
	assert(m_siblingNavigatorStack.empty() == false);

	// I have to pop my entry, since my children are finished...
	m_parentNavigatorStack.pop_back();

	// Pop any sibling navigators my child pushed...
	while(m_siblingNavigatorStack.back().m_navigator != 0)
	{
		assert(m_siblingNavigatorStack.back().m_node != 0);

		m_siblingNavigatorStack.pop_back();
	}

	// There must be a context marker...
	assert(m_siblingNavigatorStack.back().m_navigator == 0 &&
		   m_siblingNavigatorStack.back().m_node == 0);

	// Pop the context marker...
	m_siblingNavigatorStack.pop_back();
}
