/*************************************************************************
 *
 * 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();
}
