/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_xmlsecurity.hxx"

#include "elementmark.hxx"
#include "elementcollector.hxx"
#include "buffernode.hxx"
#include <com/sun/star/xml/crypto/sax/ConstOfSecurityId.hpp>

namespace cssu = com::sun::star::uno;
namespace cssxw = com::sun::star::xml::wrapper;
namespace cssxc = com::sun::star::xml::crypto;

BufferNode::BufferNode( const cssu::Reference< cssxw::XXMLElementWrapper >& xXMLElement )
	:m_pParent(NULL),
	 m_pBlocker(NULL),
	 m_bAllReceived(false),
     m_xXMLElement(xXMLElement)
{
}

bool BufferNode::isECOfBeforeModifyIncluded(sal_Int32 nIgnoredSecurityId) const
/****** BufferNode/isECOfBeforeModifyIncluded ********************************
 *
 *   NAME
 *	isECOfBeforeModifyIncluded -- checks whether there is some 
 *	ElementCollector on this BufferNode, that has BEFORE-MODIFY priority.
 *
 *   SYNOPSIS
 *	bExist = isECOfBeforeModifyIncluded(nIgnoredSecurityId);
 *
 *   FUNCTION
 *	checks each ElementCollector on this BufferNode, if all following
 *	conditions are satisfied, then returns true:
 *	1. the ElementCollector's priority is BEFOREMODIFY;
 *	2. the ElementCollector's securityId can't be ignored.
 *	otherwise, returns false.
 *
 *   INPUTS
 *	nIgnoredSecurityId -	the security Id to be ignored. If it equals
 *	                        to UNDEFINEDSECURITYID, then no security Id
 *	                    	will be ignored.
 *
 *   RESULT
 *	bExist - true if a match found, false otherwise
 *
 *   HISTORY
 *	05.01.2004 -	implemented
 *
 *   AUTHOR
 *	Michael Mi
 *	Email: michael.mi@sun.com
 ******************************************************************************/
{
	bool rc = false;
	std::vector< const ElementCollector* >::const_iterator ii = m_vElementCollectors.begin();

	for( ; ii != m_vElementCollectors.end() ; ++ii ) 
	{
		ElementCollector* pElementCollector = (ElementCollector*)*ii;
		
		if ((nIgnoredSecurityId == cssxc::sax::ConstOfSecurityId::UNDEFINEDSECURITYID ||
		 	pElementCollector->getSecurityId() != nIgnoredSecurityId) &&
		    (pElementCollector->getPriority() == cssxc::sax::ElementMarkPriority_BEFOREMODIFY))
		{
			rc = true;
			break;
		}
	}
	
	return rc;
}

void BufferNode::setReceivedAll()
/****** BufferNode/setReceiveAll *********************************************
 *
 *   NAME
 *	setReceivedAll -- indicates that the element in this BufferNode has
 *	been compeletely bufferred.
 *
 *   SYNOPSIS
 *	setReceivedAll();
 *
 *   FUNCTION
 *	sets the all-received flag and launches ElementCollector's notify
 *	process.
 *
 *   INPUTS
 *	empty
 *
 *   RESULT
 *	empty
 *
 *   HISTORY
 *	05.01.2004 -	implemented
 *
 *   AUTHOR
 *	Michael Mi
 *	Email: michael.mi@sun.com
 ******************************************************************************/
{
	m_bAllReceived = true;
	elementCollectorNotify();
}

bool BufferNode::isAllReceived() const
{
	return m_bAllReceived;
}

void BufferNode::addElementCollector(const ElementCollector* pElementCollector)
/****** BufferNode/addElementCollector ***************************************
 *
 *   NAME
 *	addElementCollector -- adds a new ElementCollector to this BufferNode.
 *
 *   SYNOPSIS
 *	addElementCollector(pElementCollector);
 *
 *   FUNCTION
 *	see NAME
 *
 *   INPUTS
 *	pElementCollector - the ElementCollector to be added
 *
 *   RESULT
 *	empty
 *
 *   HISTORY
 *	05.01.2004 -	implemented
 *
 *   AUTHOR
 *	Michael Mi
 *	Email: michael.mi@sun.com
 ******************************************************************************/
{
	m_vElementCollectors.push_back( pElementCollector );
	((ElementCollector*)pElementCollector)->setBufferNode(this);
}

void BufferNode::removeElementCollector(const ElementCollector* pElementCollector)
/****** BufferNode/removeElementCollector ************************************
 *
 *   NAME
 *	removeElementCollector -- removes an ElementCollector from this
 *	BufferNode.
 *
 *   SYNOPSIS
 *	removeElementCollector(pElementCollector);
 *
 *   FUNCTION
 *	see NAME
 *
 *   INPUTS
 *	pElementCollector - the ElementCollector to be removed
 *
 *   RESULT
 *	empty
 *
 *   HISTORY
 *	05.01.2004 -	implemented
 *
 *   AUTHOR
 *	Michael Mi
 *	Email: michael.mi@sun.com
 ******************************************************************************/
{
	std::vector< const ElementCollector* >::iterator ii = m_vElementCollectors.begin();

	for( ; ii != m_vElementCollectors.end() ; ++ii ) 
	{
		if( *ii == pElementCollector ) 
		{
			m_vElementCollectors.erase( ii );
			((ElementCollector*)pElementCollector)->setBufferNode(NULL);
			break;
		}
	}
}

ElementMark* BufferNode::getBlocker() const
{
	return m_pBlocker;
}

void BufferNode::setBlocker(const ElementMark* pBlocker)
/****** BufferNode/setBlocker ************************************************
 *
 *   NAME
 *	setBlocker -- adds a blocker to this BufferNode.
 *
 *   SYNOPSIS
 *	setBlocker(pBlocker);
 *
 *   FUNCTION
 *	see NAME
 *
 *   INPUTS
 *	pBlocker - the new blocker to be attached
 *
 *   RESULT
 *	empty
 *
 *   NOTES
 *	Because there is only one blocker permited for a BufferNode, so the
 *	old blocker on this BufferNode, if there is one, will be overcasted.
 *
 *   HISTORY
 *	05.01.2004 -	implemented
 *
 *   AUTHOR
 *	Michael Mi
 *	Email: michael.mi@sun.com
 ******************************************************************************/
{
	OSL_ASSERT(!(m_pBlocker != NULL && pBlocker != NULL));
	
	m_pBlocker = (ElementMark*)pBlocker;
	if (m_pBlocker != NULL)
	{
		m_pBlocker->setBufferNode(this);
	}
}

rtl::OUString BufferNode::printChildren() const
/****** BufferNode/printChildren *********************************************
 *
 *   NAME
 *	printChildren -- prints children information into a string.
 *
 *   SYNOPSIS
 *	result = printChildren();
 *
 *   FUNCTION
 *	see NAME
 *
 *   INPUTS
 *	empty
 *
 *   RESULT
 *	result - the information string
 *
 *   HISTORY
 *	05.01.2004 -	implemented
 *
 *   AUTHOR
 *	Michael Mi
 *	Email: michael.mi@sun.com
 ******************************************************************************/
{ 
	rtl::OUString rc;
	std::vector< const ElementCollector* >::const_iterator ii = m_vElementCollectors.begin();
			
	for( ; ii != m_vElementCollectors.end() ; ++ii ) 
	{
		rc += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "BufID=" ));
		rc += rtl::OUString::valueOf((*ii)->getBufferId());

		if (((ElementCollector*)(*ii))->getModify())
		{
			rc += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "[M]" ));
		}
		
		rc += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ",Pri=" ));
		
		switch (((ElementCollector*)(*ii))->getPriority())
		{
			case cssxc::sax::ElementMarkPriority_BEFOREMODIFY:
				rc += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "BEFOREMODIFY" ));
				break;
			case cssxc::sax::ElementMarkPriority_AFTERMODIFY:
				rc += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AFTERMODIFY" ));
				break;
			default:
				rc += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UNKNOWN" ));
				break;
		}
		
		rc += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "(" ));
		/*
		if (((ElementCollector*)(*ii))->isInternalNotificationSuppressed())
		{
			rc += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "*IN-Suppressed* " ));
		}
		*/
		rc += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "SecID=" ));
		rc += rtl::OUString::valueOf(((ElementCollector*)(*ii))->getSecurityId());
		rc += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ")" ));
		rc += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( " " ));
	}
	
	return rc;
}

bool BufferNode::hasAnything() const
/****** BufferNode/hasAnything ***********************************************
 *
 *   NAME
 *	hasAnything -- checks whether there is any ElementCollector or blocker
 *	on this BufferNode.
 *
 *   SYNOPSIS
 *	bExist = hasAnything();
 *
 *   FUNCTION
 *	see NAME
 *
 *   INPUTS
 *	empty
 *
 *   RESULT
 *	bExist - true if there is, false otherwise.
 *
 *   HISTORY
 *	05.01.2004 -	implemented
 *
 *   AUTHOR
 *	Michael Mi
 *	Email: michael.mi@sun.com
 ******************************************************************************/
{
	return (m_pBlocker != NULL || m_vElementCollectors.size() > 0);
}

bool BufferNode::hasChildren() const
/****** BufferNode/hasChildren ***********************************************
 *
 *   NAME
 *	hasChildren -- checks whether this BufferNode has any child
 *	BufferNode.
 *
 *   SYNOPSIS
 *	bExist = hasChildren();
 *
 *   FUNCTION
 *	see NAME
 *
 *   INPUTS
 *	empty
 *
 *   RESULT
 *	bExist - true if there is, false otherwise.
 *
 *   HISTORY
 *	05.01.2004 -	implemented
 *
 *   AUTHOR
 *	Michael Mi
 *	Email: michael.mi@sun.com
 ******************************************************************************/
{
	return (m_vChildren.size() > 0);
}

std::vector< const BufferNode* >* BufferNode::getChildren() const
{
	return new std::vector< const BufferNode* >( m_vChildren );
}

const BufferNode* BufferNode::getFirstChild() const
/****** BufferNode/getFirstChild *********************************************
 *
 *   NAME
 *	getFirstChild -- retrieves the first child BufferNode.
 *
 *   SYNOPSIS
 *	child = getFirstChild();
 *
 *   FUNCTION
 *	see NAME
 *
 *   INPUTS
 *	empty
 *
 *   RESULT
 *	child -	the first child BufferNode, or NULL if there is no child
 *	       	BufferNode.
 *
 *   HISTORY
 *	05.01.2004 -	implemented
 *
 *   AUTHOR
 *	Michael Mi
 *	Email: michael.mi@sun.com
 ******************************************************************************/
{
	BufferNode* rc = NULL;
	
	if (m_vChildren.size() > 0)
	{
		rc = (BufferNode*)m_vChildren.front();
	}
	
	return (const BufferNode*)rc;
}

void BufferNode::addChild(const BufferNode* pChild, sal_Int32 nPosition)
/****** BufferNode/addChild(pChild,nPosition) ********************************
 *
 *   NAME
 *	addChild -- inserts a child BufferNode at specific position.
 *
 *   SYNOPSIS
 *	addChild(pChild, nPosition);
 *
 *   FUNCTION
 *	see NAME
 *
 *   INPUTS
 *	pChild - 	the child BufferNode to be added.
 *	nPosition -	the position where the new child locates.
 *
 *   RESULT
 *	empty
 *
 *   NOTES
 *	If the nPosition is -1, then the new child BufferNode is appended
 *	at the end.
 *
 *   HISTORY
 *	05.01.2004 -	implemented
 *
 *   AUTHOR
 *	Michael Mi
 *	Email: michael.mi@sun.com
 ******************************************************************************/
{
	if (nPosition == -1)
	{
		m_vChildren.push_back( pChild );
	}
	else
	{
		std::vector< const BufferNode* >::iterator ii = m_vChildren.begin();
		ii += nPosition;
		m_vChildren.insert(ii, pChild);
	}
}

void BufferNode::addChild(const BufferNode* pChild)
/****** BufferNode/addChild() ************************************************
 *
 *   NAME
 *	addChild -- add a new child BufferNode.
 *
 *   SYNOPSIS
 *	addChild(pChild);
 *
 *   FUNCTION
 *	see NAME
 *
 *   INPUTS
 *	pChild - 	the child BufferNode to be added.
 *
 *   RESULT
 *	empty
 *
 *   NOTES
 *	The new child BufferNode is appended at the end.
 *
 *   HISTORY
 *	05.01.2004 -	implemented
 *
 *   AUTHOR
 *	Michael Mi
 *	Email: michael.mi@sun.com
 ******************************************************************************/
{
	addChild(pChild, -1);
}

void BufferNode::removeChild(const BufferNode* pChild)
/****** BufferNode/removeChild ***********************************************
 *
 *   NAME
 *	removeChild -- removes a child BufferNode from the children list.
 *
 *   SYNOPSIS
 *	removeChild(pChild);
 *
 *   FUNCTION
 *	see NAME
 *
 *   INPUTS
 *	pChild - the child BufferNode to be removed
 *
 *   RESULT
 *	empty
 *
 *   HISTORY
 *	05.01.2004 -	implemented
 *
 *   AUTHOR
 *	Michael Mi
 *	Email: michael.mi@sun.com
 ******************************************************************************/
{
	std::vector< const BufferNode* >::iterator ii = m_vChildren.begin();

	for( ; ii != m_vChildren.end() ; ++ii ) 
	{
		if( *ii == pChild ) 
		{
			m_vChildren.erase( ii );
			break;
		}
	}
}

sal_Int32 BufferNode::indexOfChild(const BufferNode* pChild) const
/****** BufferNode/indexOfChild **********************************************
 *
 *   NAME
 *	indexOfChild -- gets the index of a child BufferNode.
 *
 *   SYNOPSIS
 *	index = indexOfChild(pChild);
 *
 *   FUNCTION
 *	see NAME
 *
 *   INPUTS
 *	pChild - the child BufferNode whose index to be gotten
 *
 *   RESULT
 *	index -	the index of that child BufferNode. If that child BufferNode
 *	       	is not found, -1 is returned.
 *
 *   HISTORY
 *	05.01.2004 -	implemented
 *
 *   AUTHOR
 *	Michael Mi
 *	Email: michael.mi@sun.com
 ******************************************************************************/
{
	sal_Int32 nIndex = 0;
	bool bFound = false;
	
	std::vector< const BufferNode * >::const_iterator ii = m_vChildren.begin();

	for( ; ii != m_vChildren.end() ; ++ii ) 
	{
		if( *ii == pChild ) 
		{
			bFound = true;
			break;
		}
		nIndex++;
	}
	
	if (!bFound )
	{
		nIndex = -1;
	}
	
	return nIndex;
}

const BufferNode* BufferNode::childAt(sal_Int32 nIndex) const
/****** BufferNode/childAt ***************************************************
 *
 *   NAME
 *	childAt -- retrieves the child BufferNode at specific possition.
 *
 *   SYNOPSIS
 *	child = childAt(nIndex);
 *
 *   FUNCTION
 *	see NAME
 *
 *   INPUTS
 *	nIndex - the index of the child BufferNode to be retrieved
 *
 *   RESULT
 *	child -	the child BufferNode at index position, or NULL if the index
 *	       	is out of the range of children.
 *
 *   HISTORY
 *	05.01.2004 -	implemented
 *
 *   AUTHOR
 *	Michael Mi
 *	Email: michael.mi@sun.com
 ******************************************************************************/
{
	BufferNode* rc = NULL;
	
	if (nIndex < ((sal_Int32)m_vChildren.size()) && nIndex >= 0)
	{
		rc = (BufferNode*)m_vChildren[nIndex];
	}
	
	return (const BufferNode*)rc;
}

const BufferNode* BufferNode::getParent() const
{
	return m_pParent;
}

void BufferNode::setParent(const BufferNode* pParent)
{
	m_pParent = (BufferNode*)pParent;
}

const BufferNode* BufferNode::getNextSibling() const
/****** BufferNode/getNextSibling ********************************************
 *
 *   NAME
 *	getNextSibling -- retrieves the next sibling BufferNode.
 *
 *   SYNOPSIS
 *	sibling = getNextSibling();
 *
 *   FUNCTION
 *	see NAME
 *
 *   INPUTS
 *	empty
 *
 *   RESULT
 *	sibling - the next sibling BufferNode, or NULL if there is none.
 *
 *   HISTORY
 *	05.01.2004 -	implemented
 *
 *   AUTHOR
 *	Michael Mi
 *	Email: michael.mi@sun.com
 ******************************************************************************/
{
	BufferNode* rc = NULL;
	
	if (m_pParent != NULL)
	{
		rc = (BufferNode*)m_pParent->getNextChild(this);
	}
	
	return (const BufferNode*)rc;
}

const BufferNode* BufferNode::isAncestor(const BufferNode* pDescendant) const
/****** BufferNode/isAncestor ************************************************
 *
 *   NAME
 *	isAncestor -- checks whether this BufferNode is an ancestor of another
 *	BufferNode.
 *
 *   SYNOPSIS
 *	bIs = isAncestor(pDescendant);
 *
 *   FUNCTION
 *	see NAME
 *
 *   INPUTS
 *	pDescendant -	the BufferNode to be checked as a descendant
 *
 *   RESULT
 *	bIs -	true if this BufferNode is an ancestor of the pDescendant, 
 *	     	false otherwise.
 *
 *   HISTORY
 *	05.01.2004 -	implemented
 *
 *   AUTHOR
 *	Michael Mi
 *	Email: michael.mi@sun.com
 ******************************************************************************/
{
	BufferNode* rc = NULL;
	
	if (pDescendant != NULL)
	{
		std::vector< const BufferNode* >::const_iterator ii = m_vChildren.begin();
	
		for( ; ii != m_vChildren.end() ; ++ii ) 
		{
			BufferNode* pChild = (BufferNode*)*ii;
			
			if (pChild == pDescendant)
			{
				rc = pChild;
				break;
			}
			
			if (pChild->isAncestor(pDescendant) != NULL)
			{
				rc = pChild;
				break;
			}
		}
	}

	return (const BufferNode*)rc;
}	

bool BufferNode::isPrevious(const BufferNode* pFollowing) const
/****** BufferNode/isPrevious ************************************************
 *
 *   NAME
 *	isPrevious -- checks whether this BufferNode is ahead of another
 *	BufferNode in the tree order.
 *
 *   SYNOPSIS
 *	bIs = isPrevious(pFollowing);
 *
 *   FUNCTION
 *	see NAME
 *
 *   INPUTS
 *	pFollowing -	the BufferNode to be checked as a following
 *
 *   RESULT
 *	bIs -	true if this BufferNode is ahead in the tree order, false
 *	     	otherwise.
 *
 *   HISTORY
 *	05.01.2004 -	implemented
 *
 *   AUTHOR
 *	Michael Mi
 *	Email: michael.mi@sun.com
 ******************************************************************************/
{
	bool rc = false;
	
	BufferNode* pNextBufferNode = (BufferNode*)getNextNodeByTreeOrder();
	while (pNextBufferNode != NULL)
	{
		if (pNextBufferNode == pFollowing)
		{
			rc = true;
			break;
		}
		
		pNextBufferNode = (BufferNode*)(pNextBufferNode->getNextNodeByTreeOrder());
	}
	
	return rc;
}	

const BufferNode* BufferNode::getNextNodeByTreeOrder() const
/****** BufferNode/getNextNodeByTreeOrder ************************************
 *
 *   NAME
 *	getNextNodeByTreeOrder -- retrieves the next BufferNode in the tree
 *	order.
 *
 *   SYNOPSIS
 *	next = getNextNodeByTreeOrder();
 *
 *   FUNCTION
 *	see NAME
 *
 *   INPUTS
 *	empty
 *
 *   RESULT
 *	next -	the BufferNode following this BufferNode in the tree order, 
 *	      	or NULL if there is none.
 *
 *   NOTES
 *	The "next" node in tree order is defined as:
 *	1. If a node has children, then the first child is;
 *	2. otherwise, if it has a following sibling, then this sibling node is;
 *	3. otherwise, if it has a parent node, the the parent's next sibling
 *	   node is;
 *	4. otherwise, no "next" node exists.
 *
 *   HISTORY
 *	05.01.2004 -	implemented
 *
 *   AUTHOR
 *	Michael Mi
 *	Email: michael.mi@sun.com
 ******************************************************************************/
{
        /*
         * If this buffer node has m_vChildren, then return the first
         * child.
         */
	if (hasChildren())
	{
		return getFirstChild();
	}

        /*
         * Otherwise, it this buffer node has a following sibling, 
         * then return that sibling.
         */
	BufferNode* pNextSibling = (BufferNode*)getNextSibling();
	if (pNextSibling != NULL)
	{
		return pNextSibling;
	}
	
        /*
         * Otherwise, it this buffer node has parent, then return
         * its parent's following sibling.
         */
        BufferNode* pNode = (BufferNode*)this;
	BufferNode* pParent;
	BufferNode* pNextSiblingParent = NULL;
	
	do
	{
		if (pNode == NULL)
		{
			break;
		}
		
		pParent = (BufferNode*)pNode->getParent();
		if (pParent != NULL)
		{
			pNextSiblingParent = (BufferNode*)pParent->getNextSibling();
		}
		pNode = pParent;
		
	}while (pNextSiblingParent == NULL);
	
	return pNextSiblingParent;
}

cssu::Reference< cssxw::XXMLElementWrapper > BufferNode::getXMLElement() const
{
	return m_xXMLElement;
}

void BufferNode::setXMLElement( const cssu::Reference< cssxw::XXMLElementWrapper >& xXMLElement )
{
	m_xXMLElement = xXMLElement;
}	

void BufferNode::notifyBranch()
/****** BufferNode/notifyBranch **********************************************
 *
 *   NAME
 *	notifyBranch -- notifies each BufferNode in the branch of this
 *	BufferNode in the tree order.
 *
 *   SYNOPSIS
 *	notifyBranch();
 *
 *   FUNCTION
 *	see NAME
 *
 *   INPUTS
 *	empty
 *
 *   RESULT
 *	empty
 *
 *   HISTORY
 *	05.01.2004 -	implemented
 *
 *   AUTHOR
 *	Michael Mi
 *	Email: michael.mi@sun.com
 ******************************************************************************/
{
	std::vector< const BufferNode* >::const_iterator ii = m_vChildren.begin();

	for( ; ii != m_vChildren.end() ; ++ii ) 
	{
		BufferNode* pBufferNode = (BufferNode*)*ii;
		pBufferNode->elementCollectorNotify();
		pBufferNode->notifyBranch();
	}
}

void BufferNode::notifyAncestor()
/****** BufferNode/notifyAncestor ********************************************
 *
 *   NAME
 *	notifyAncestor -- notifies each ancestor BufferNode through the parent
 *	link.
 *
 *   SYNOPSIS
 *	notifyAncestor();
 *
 *   FUNCTION
 *	see NAME
 *
 *   INPUTS
 *	empty
 *
 *   RESULT
 *	empty
 *
 *   HISTORY
 *	05.01.2004 -	implemented
 *
 *   AUTHOR
 *	Michael Mi
 *	Email: michael.mi@sun.com
 ******************************************************************************/
{
	BufferNode* pParent = m_pParent;
	while (pParent != NULL)
	{
		pParent->notifyAncestor();
		pParent = (BufferNode*)pParent->getParent();
	}
}

void BufferNode::elementCollectorNotify()
/****** BufferNode/elementCollectorNotify ************************************
 *
 *   NAME
 *	elementCollectorNotify -- notifies this BufferNode.
 *
 *   SYNOPSIS
 *	elementCollectorNotify();
 *
 *   FUNCTION
 *	Notifies this BufferNode if the notification is not suppressed.
 *
 *   INPUTS
 *	empty
 *
 *   RESULT
 *	child -	the first child BufferNode, or NULL if there is no child
 *	       	BufferNode.
 *
 *   HISTORY
 *	05.01.2004 -	implemented
 *
 *   AUTHOR
 *	Michael Mi
 *	Email: michael.mi@sun.com
 ******************************************************************************/
{
	if (m_vElementCollectors.size()>0)
	{
		cssxc::sax::ElementMarkPriority nMaxPriority = cssxc::sax::ElementMarkPriority_MINIMUM;
		cssxc::sax::ElementMarkPriority nPriority;
		
		/*
		 * get the max priority among ElementCollectors on this BufferNode
		 */
		std::vector< const ElementCollector* >::const_iterator ii = m_vElementCollectors.begin();
		for( ; ii != m_vElementCollectors.end() ; ++ii ) 
		{
			ElementCollector* pElementCollector = (ElementCollector*)*ii;
			nPriority = pElementCollector->getPriority();
			if (nPriority > nMaxPriority)
			{
				nMaxPriority = nPriority;
			}
		}
		
		std::vector< const ElementCollector* > vElementCollectors( m_vElementCollectors );
		ii = vElementCollectors.begin();
		
		for( ; ii != vElementCollectors.end() ; ++ii ) 
		{
			ElementCollector* pElementCollector = (ElementCollector*)*ii;
			nPriority = pElementCollector->getPriority();
			bool bToModify = pElementCollector->getModify();
			
			/*
			 * Only ElementCollector with the max priority can
			 * perform notify operation.
			 * Moreover, if any blocker exists in the subtree of
			 * this BufferNode, this ElementCollector can't do notify
			 * unless its priority is BEFOREMODIFY.
			 */
			if (nPriority == nMaxPriority &&
				(nPriority == cssxc::sax::ElementMarkPriority_BEFOREMODIFY ||
				 !isBlockerInSubTreeIncluded(pElementCollector->getSecurityId())))
			{
				/*
				 * If this ElementCollector will modify the bufferred element, then
				 * special attention must be paid.
				 *
				 * If there is any ElementCollector in the subtree or any ancestor
				 * ElementCollector with PRI_BEFPREMODIFY priority, this
				 * ElementCollector can't perform notify operation, otherwise, it
				 * will destroy the bufferred element, in turn, ElementCollectors
				 * mentioned above can't perform their mission.
				 */
				//if (!(nMaxPriority == cssxc::sax::ElementMarkPriority_PRI_MODIFY && 
				if (!(bToModify &&
				     (isECInSubTreeIncluded(pElementCollector->getSecurityId()) ||
				      isECOfBeforeModifyInAncestorIncluded(pElementCollector->getSecurityId()))
				   ))
				{
					pElementCollector->notifyListener();
				}
			}
		}
	}
}

bool BufferNode::isECInSubTreeIncluded(sal_Int32 nIgnoredSecurityId) const
/****** BufferNode/isECInSubTreeIncluded *************************************
 *
 *   NAME
 *	isECInSubTreeIncluded -- checks whether there is any ElementCollector
 *	in the branch of this BufferNode.
 *
 *   SYNOPSIS
 *	bExist = isECInSubTreeIncluded(nIgnoredSecurityId);
 *
 *   FUNCTION
 *	checks each BufferNode in the branch of this BufferNode, if there is
 *	an ElementCollector whose signatureId is not ignored, then return
 *	true, otherwise, false returned.
 *
 *   INPUTS
 *	nIgnoredSecurityId -	the security Id to be ignored. If it equals
 *	                        to UNDEFINEDSECURITYID, then no security Id
 *	                    	will be ignored.
 *
 *   RESULT
 *	bExist - true if a match found, false otherwise.
 *
 *   HISTORY
 *	05.01.2004 -	implemented
 *
 *   AUTHOR
 *	Michael Mi
 *	Email: michael.mi@sun.com
 ******************************************************************************/
{
	bool rc = false;
	
	std::vector< const ElementCollector* >::const_iterator jj = m_vElementCollectors.begin();
	
	for( ; jj != m_vElementCollectors.end() ; ++jj ) 
	{
		ElementCollector* pElementCollector = (ElementCollector*)*jj;
		if (nIgnoredSecurityId == cssxc::sax::ConstOfSecurityId::UNDEFINEDSECURITYID ||
		 	pElementCollector->getSecurityId() != nIgnoredSecurityId)
		{
			rc = true;
			break;
		}
	}
	
	if ( !rc )
	{
		std::vector< const BufferNode* >::const_iterator ii = m_vChildren.begin();
	
		for( ; ii != m_vChildren.end() ; ++ii ) 
		{
			BufferNode* pBufferNode = (BufferNode*)*ii;
			
			if ( pBufferNode->isECInSubTreeIncluded(nIgnoredSecurityId))
			{
				rc = true;
				break;
			}
		}
	}
	
	return rc;
}

bool BufferNode::isECOfBeforeModifyInAncestorIncluded(sal_Int32 nIgnoredSecurityId) const
/****** BufferNode/isECOfBeforeModifyInAncestorIncluded **********************
 *
 *   NAME
 *	isECOfBeforeModifyInAncestorIncluded -- checks whether there is some
 *	ancestor BufferNode which has ElementCollector with PRI_BEFPREMODIFY
 *	priority.
 *
 *   SYNOPSIS
 *	bExist = isECOfBeforeModifyInAncestorIncluded(nIgnoredSecurityId);
 *
 *   FUNCTION
 *	checks each ancestor BufferNode through the parent link, if there is
 *	an ElementCollector with PRI_BEFPREMODIFY priority and its 
 *	signatureId is not ignored, then return true, otherwise, false
 *	returned.
 *
 *   INPUTS
 *	nIgnoredSecurityId -	the security Id to be ignored. If it equals
 *	                        to UNDEFINEDSECURITYID, then no security Id
 *	                    	will be ignored.
 *
 *   RESULT
 *	bExist - true if a match found, false otherwise.
 *
 *   HISTORY
 *	05.01.2004 -	implemented
 *
 *   AUTHOR
 *	Michael Mi
 *	Email: michael.mi@sun.com
 ******************************************************************************/
{
	bool rc = false;
	
	BufferNode* pParentNode = m_pParent;
	while (pParentNode != NULL)
	{
		if (pParentNode->isECOfBeforeModifyIncluded(nIgnoredSecurityId))
		{
			rc = true;
			break;
		}
		
		pParentNode = (BufferNode*)pParentNode->getParent();
	}
	
	return rc;
}

bool BufferNode::isBlockerInSubTreeIncluded(sal_Int32 nIgnoredSecurityId) const
/****** BufferNode/isBlockerInSubTreeIncluded ********************************
 *
 *   NAME
 *	isBlockerInSubTreeIncluded -- checks whether there is some BufferNode
 *	which has blocker on it
 *
 *   SYNOPSIS
 *	bExist = isBlockerInSubTreeIncluded(nIgnoredSecurityId);
 *
 *   FUNCTION
 *	checks each BufferNode in the branch of this BufferNode, if one has
 *	a blocker on it, and the blocker's securityId is not ignored, then
 *	returns true; otherwise, false returns.
 *
 *   INPUTS
 *	nIgnoredSecurityId -	the security Id to be ignored. If it equals
 *	                        to UNDEFINEDSECURITYID, then no security Id
 *	                    	will be ignored.
 *
 *   RESULT
 *	bExist - true if a match found, false otherwise.
 *
 *   HISTORY
 *	05.01.2004 -	implemented
 *
 *   AUTHOR
 *	Michael Mi
 *	Email: michael.mi@sun.com
 ******************************************************************************/
{
	bool rc = false;
	
	std::vector< const BufferNode* >::const_iterator ii = m_vChildren.begin();

	for( ; ii != m_vChildren.end() ; ++ii ) 
	{
		BufferNode* pBufferNode = (BufferNode*)*ii;
		ElementMark* pBlocker = pBufferNode->getBlocker();
		
		if (pBlocker != NULL &&
			(nIgnoredSecurityId == cssxc::sax::ConstOfSecurityId::UNDEFINEDSECURITYID ||
			pBlocker->getSecurityId() != nIgnoredSecurityId )) 
		{
			rc = true;
			break;
		}
		
		if (rc || pBufferNode->isBlockerInSubTreeIncluded(nIgnoredSecurityId))
		{
			rc = true;
			break;
		}
	}
	
	return rc;
}

const BufferNode* BufferNode::getNextChild(const BufferNode* pChild) const
/****** BufferNode/getNextChild **********************************************
 *
 *   NAME
 *	getNextChild -- get the next child BufferNode.
 *
 *   SYNOPSIS
 *	nextChild = getNextChild();
 *
 *   FUNCTION
 *	see NAME
 *
 *   INPUTS
 *	pChild - the child BufferNode whose next node is retrieved.
 *
 *   RESULT
 *	nextChild -	the next child BufferNode after the pChild, or NULL if 
 *	there is none.
 *
 *   HISTORY
 *	05.01.2004 -	implemented
 *
 *   AUTHOR
 *	Michael Mi
 *	Email: michael.mi@sun.com
 ******************************************************************************/
{
	BufferNode* rc = NULL;
	bool bChildFound = false;
	
	std::vector< const BufferNode* >::const_iterator ii = m_vChildren.begin();
	for( ; ii != m_vChildren.end() ; ++ii ) 
	{
		if (bChildFound)
		{
			rc = (BufferNode*)*ii;
			break;
		}
			
		if( *ii == pChild ) 
		{
			bChildFound = true;
		}
	}
	
	return (const BufferNode*)rc;
}


void BufferNode::freeAllChildren()
/****** BufferNode/freeAllChildren *******************************************
 *
 *   NAME
 *	freeAllChildren -- free all his child BufferNode.
 *
 *   SYNOPSIS
 *	freeAllChildren();
 *
 *   FUNCTION
 *	see NAME
 *
 *   INPUTS
 *	empty
 *
 *   RESULT
 *	empty
 *
 *   HISTORY
 *	30.03.2004 -	the correct the memory leak bug
 *
 *   AUTHOR
 *	Michael Mi
 *	Email: michael.mi@sun.com
 ******************************************************************************/
{
	std::vector< const BufferNode* >::const_iterator ii = m_vChildren.begin();
	for( ; ii != m_vChildren.end() ; ++ii ) 
	{
		BufferNode *pChild = (BufferNode *)(*ii);
		pChild->freeAllChildren();
		delete pChild;
	}
	
	m_vChildren.clear();
}