/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



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

#include <editeng/svxenum.hxx>
#include <numrule.hxx>
#include <SwNodeNum.hxx>
#include <ndtxt.hxx>
#include <pam.hxx>
#include <stdio.h>
// --> OD 2007-10-31 #i83479#
#include <IDocumentListItems.hxx>
// <--
// --> OD 2010-01-13 #b6912256#
//#include <svtools/svstdarr.hxx>
#include <doc.hxx>
// <--

// --> OD 2008-02-19 #refactorlists#
SwNodeNum::SwNodeNum( SwTxtNode* pTxtNode )
    : SwNumberTreeNode(),
      mpTxtNode( pTxtNode ),
      mpNumRule( 0 )
{
}

SwNodeNum::SwNodeNum( SwNumRule* pNumRule )
    : SwNumberTreeNode(),
      mpTxtNode( 0 ),
      mpNumRule( pNumRule )
{
}
// <--

SwNodeNum::~SwNodeNum()
{
}

SwTxtNode * SwNodeNum::GetTxtNode() const
{
    return mpTxtNode;
}

SwNumRule * SwNodeNum::GetNumRule() const
{
    return mpNumRule;
}

void SwNodeNum::ChangeNumRule( SwNumRule& rNumRule )
{
    ASSERT( GetNumRule() && GetTxtNode(),
            "<SwNodeNum::ChangeNumRule(..)> - missing list style and/or text node. Serious defect -> please informm OD." );
    if ( GetNumRule() && GetTxtNode() )
    {
        GetNumRule()->RemoveTxtNode( *(GetTxtNode()) );
    }

    mpNumRule = &rNumRule;

    if ( GetNumRule() && GetTxtNode() )
    {
        GetNumRule()->AddTxtNode( *(GetTxtNode()) );
    }
}

SwPosition SwNodeNum::GetPosition() const
{
    ASSERT( GetTxtNode(),
            "<SwNodeNum::GetPosition()> - no text node set at <SwNodeNum> instance" );
    return SwPosition(*mpTxtNode);
}

SwNumberTreeNode * SwNodeNum::Create() const
{
    // --> OD 2008-02-19 #refactorlists#
//    SwNodeNum * pResult = new SwNodeNum();
//    pResult->SetNumRule(mpNumRule);
    SwNodeNum * pResult = new SwNodeNum( GetNumRule() );
    // <--

    return pResult;
}

// --> OD 2008-02-19 #refactorlists#
void SwNodeNum::PreAdd()
{
    ASSERT( GetTxtNode(),
            "<SwNodeNum::PreAdd()> - no text node set at <SwNodeNum> instance" );
    if ( !GetNumRule() && GetTxtNode() )
    {
        mpNumRule = GetTxtNode()->GetNumRule();
    }
    ASSERT( GetNumRule(),
            "<SwNodeNum::PreAdd()> - no list style set at <SwNodeNum> instance" );
    if ( GetNumRule() && GetTxtNode() )
    {
        GetNumRule()->AddTxtNode( *(GetTxtNode()) );
    }


    {
        if ( GetTxtNode() &&
             GetTxtNode()->GetNodes().IsDocNodes() )
        {
            GetTxtNode()->getIDocumentListItems().addListItem( *this );
        }
    }
}

void SwNodeNum::PostRemove()
{
    ASSERT( GetTxtNode(),
            "<SwNodeNum::PostRemove()> - no text node set at <SwNodeNum> instance" );
    ASSERT( GetNumRule(),
            "<SwNodeNum::PostRemove()> - no list style set at <SwNodeNum> instance" );

    if ( GetTxtNode() )
    {
        GetTxtNode()->getIDocumentListItems().removeListItem( *this );
    }

    if ( GetNumRule() )
    {
        if ( GetTxtNode() )
        {
            GetNumRule()->RemoveTxtNode( *(GetTxtNode()) );
        }
        mpNumRule = 0;
    }
}
// <--

bool SwNodeNum::IsNotifiable() const
{
    bool aResult = true;

    if ( GetTxtNode() )
        aResult = GetTxtNode()->IsNotifiable();

    return aResult;
}

bool SwNodeNum::IsNotificationEnabled() const
{
    bool aResult = true;

    if ( GetTxtNode() )
        aResult = GetTxtNode()->IsNotificationEnabled();

    return aResult;
}

bool SwNodeNum::IsContinuous() const
{
    bool aResult = false;

    // --> OD 2006-04-21 #i64311#
    if ( GetNumRule() )
    {
        aResult = mpNumRule->IsContinusNum();
    }
    else if ( GetParent() )
    {
        aResult = GetParent()->IsContinuous();
    }
    else
    {
        ASSERT( false, "<SwNodeNum::IsContinuous()> - OD debug" );
    }
    // <--

    return aResult;
}

bool SwNodeNum::IsCounted() const
{
    bool aResult = false;

    if ( GetTxtNode() )
    {
        // --> OD 2006-01-25 #i59559#
        // <SwTxtNode::IsCounted()> determines, if a text node is counted for numbering
//        const SwNumFmt * pNumFmt = GetNumFmt();
//        if (pNumFmt)
//        {
//            sal_Int16 nType = pNumFmt->GetNumberingType();
//            if ( nType != SVX_NUM_NUMBER_NONE)
//                aResult = mpTxtNode->IsCounted();
//        }
        aResult = GetTxtNode()->IsCountedInList();
        // <--
    }
    else
        aResult = SwNumberTreeNode::IsCounted();

    return aResult;
}

// --> OD 2006-04-26 #i64010#
bool SwNodeNum::HasCountedChildren() const
{
    bool bResult = false;

    tSwNumberTreeChildren::iterator aIt;

    for (aIt = mChildren.begin(); aIt != mChildren.end(); aIt++)
    {
        SwNodeNum* pChild( dynamic_cast<SwNodeNum*>(*aIt) );
        ASSERT( pChild,
                "<SwNodeNum::HasCountedChildren()> - unexcepted type of child -> please inform OD" );
        if ( pChild &&
             ( pChild->IsCountedForNumbering() ||
               pChild->HasCountedChildren() ) )
        {
            bResult = true;

            break;
        }
    }

    return bResult;
}
// <--
// --> OD 2006-04-26 #i64010#
bool SwNodeNum::IsCountedForNumbering() const
{
    return IsCounted() &&
           ( IsPhantom() ||                 // phantoms
             !GetTxtNode() ||               // root node
             GetTxtNode()->HasNumber() ||   // text node
             GetTxtNode()->HasBullet() );   // text node
}
// <--


void SwNodeNum::NotifyNode()
{
    ValidateMe();

    if (mpTxtNode)
    {
        mpTxtNode->NumRuleChgd();
    }
}

bool SwNodeNum::LessThan(const SwNumberTreeNode & rNode) const
{
    bool bResult = false;
    const SwNodeNum & rTmpNode = static_cast<const SwNodeNum &>(rNode);

    if (mpTxtNode == NULL && rTmpNode.mpTxtNode != NULL)
        bResult = true;
    else if (mpTxtNode != NULL && rTmpNode.mpTxtNode != NULL)
    {
        // --> OD 2007-10-31 #i83479# - refactoring
        // simplify comparison by comparing the indexes of the text nodes
//        SwPosition aMyPos(*mpTxtNode);
//        SwPosition aHisPos(*rTmpNode.mpTxtNode);
//        bResult = (aMyPos < aHisPos) ? true : false;
        bResult = ( mpTxtNode->GetIndex() < rTmpNode.mpTxtNode->GetIndex() ) ? true : false;
        // <--
    }

    return bResult;
}

//void SwNodeNum::SetRestart(bool bRestart)
//{
//    // --> OD 2005-10-19 #126009#
//    // - improvement: invalidation only, if <IsRestart()> state changes.
//    const bool bInvalidate( mbRestart != bRestart );
//    // <--
//    mbRestart = bRestart;

//    // --> OD 2005-10-19 #126009#
//    if ( bInvalidate )
//    {
//        InvalidateMe();
//        NotifyInvalidSiblings();
//    }
//    // <--
//}

// --> OD 2008-02-25 #refactorlists#
bool SwNodeNum::IsRestart() const
{
    bool bIsRestart = false;

    if ( GetTxtNode() )
    {
        bIsRestart = GetTxtNode()->IsListRestart();
    }

    return bIsRestart;
}
// <--

//void SwNodeNum::SetStart(SwNumberTree::tSwNumTreeNumber nStart)
//{
//    // --> OD 2005-10-19 #126009#
//    // - improvement: invalidation only, if <IsRestart()> state changes.
//    const bool bInvalidate( mnStart != nStart );
//    // <--
//    mnStart = nStart;

//    // --> OD 2005-10-19 #126009#
//    if ( bInvalidate )
//    {
//        InvalidateMe();
//        NotifyInvalidSiblings();
//    }
//}

bool SwNodeNum::IsCountPhantoms() const
{
    bool bResult = true;

    // --> OD 2006-04-21 #i64311#
    // phantoms aren't counted in consecutive numbering rules
    if ( mpNumRule )
        bResult = !mpNumRule->IsContinusNum() &&
                  mpNumRule->IsCountPhantoms();
    else
    {
        ASSERT( false,
                "<SwNodeNum::IsCountPhantoms(): missing numbering rule - please inform OD" );
    }
    // <--

    return bResult;
}

// --> OD 2008-02-25 #refactorlists#
SwNumberTree::tSwNumTreeNumber SwNodeNum::GetStartValue() const
//SwNumberTree::tSwNumTreeNumber SwNodeNum::GetStart() const
{
    SwNumberTree::tSwNumTreeNumber aResult = 1;

    if ( IsRestart() && GetTxtNode() )
    {
        aResult = GetTxtNode()->GetActualListStartValue();
    }
    else
    {
        SwNumRule * pRule = GetNumRule();

        if (pRule)
        {
            int nLevel = GetParent() ? GetLevelInListTree() : 0;

            if (nLevel >= 0 && nLevel < MAXLEVEL)
            {
                const SwNumFmt * pFmt = pRule->GetNumFmt( static_cast<sal_uInt16>(nLevel));

                if (pFmt)
                    aResult = pFmt->GetStart();
            }
        }
    }

    return aResult;
}

//String SwNodeNum::ToString() const
//{
//    String aResult("[ ", RTL_TEXTENCODING_ASCII_US);

//    if (GetTxtNode())
//    {
//        char aBuffer[256];

//        sprintf(aBuffer, "%p ", GetTxtNode());

//        aResult += String(aBuffer, RTL_TEXTENCODING_ASCII_US);
//        aResult += String::CreateFromInt32(GetPosition().nNode.GetIndex());
//    }
//    else
//        aResult += String("*", RTL_TEXTENCODING_ASCII_US);

//    aResult += String(" ", RTL_TEXTENCODING_ASCII_US);

//    unsigned int nLvl = GetLevel();
//    aResult += String::CreateFromInt32(nLvl);

//    aResult += String(": ", RTL_TEXTENCODING_ASCII_US);

//    tNumberVector aNumVector;

//    _GetNumberVector(aNumVector, false);

//    for (unsigned int n = 0; n < aNumVector.size(); n++)
//    {
//        if (n > 0)
//            aResult += String(", ", RTL_TEXTENCODING_ASCII_US);

//        aResult += String::CreateFromInt32(aNumVector[n]);
//    }

//    if (IsCounted())
////        aResult += String(" counted", RTL_TEXTENCODING_ASCII_US);
//        aResult += String(" C", RTL_TEXTENCODING_ASCII_US);

//    if (IsRestart())
//    {
////        aResult += String(" restart(", RTL_TEXTENCODING_ASCII_US);
//        aResult += String(" R(", RTL_TEXTENCODING_ASCII_US);
//        aResult += String::CreateFromInt32(GetStart());
//        aResult += String(")", RTL_TEXTENCODING_ASCII_US);
//    }

//    if (! IsValid())
////        aResult += String(" invalid", RTL_TEXTENCODING_ASCII_US);
//        aResult += String(" I", RTL_TEXTENCODING_ASCII_US);

//    aResult += String(" ]", RTL_TEXTENCODING_ASCII_US);

//    return aResult;
//}

// --> OD 2006-03-07 #131436#
void SwNodeNum::HandleNumberTreeRootNodeDelete( SwNodeNum& rNodeNum )
{
    SwNodeNum* pRootNode = rNodeNum.GetParent()
                           ? dynamic_cast<SwNodeNum*>(rNodeNum.GetRoot())
                           : &rNodeNum;
    if ( !pRootNode )
    {
        // no root node -> nothing do.
        return;
    }

    // unregister all number tree node entries, which correspond to a text node,
    // about the deletion of the number tree root node.
    _UnregisterMeAndChildrenDueToRootDelete( *pRootNode );
}

void SwNodeNum::_UnregisterMeAndChildrenDueToRootDelete( SwNodeNum& rNodeNum )
{
    const bool bIsPhantom( rNodeNum.IsPhantom() );
    tSwNumberTreeChildren::size_type nAllowedChildCount( 0 );
    bool bDone( false );
    while ( !bDone &&
            rNodeNum.GetChildCount() > nAllowedChildCount )
    {
        SwNodeNum* pChildNode( dynamic_cast<SwNodeNum*>((*rNodeNum.mChildren.begin())) );
        if ( !pChildNode )
        {
            ASSERT( false,
                    "<SwNodeNum::_UnregisterMeAndChildrenDueToRootDelete(..)> - unknown number tree node child" );
            ++nAllowedChildCount;
            continue;
        }

        // Unregistering the last child of a phantom will destroy the phantom.
        // Thus <rNodeNum> will be destroyed and access on <rNodeNum> has to
        // be suppressed.
        if ( bIsPhantom && rNodeNum.GetChildCount() == 1 )
        {
            bDone = true;
        }

        _UnregisterMeAndChildrenDueToRootDelete( *pChildNode );
    }

    if ( !bIsPhantom )
    {
        SwTxtNode* pTxtNode( rNodeNum.GetTxtNode() );
        if ( pTxtNode )
        {
            pTxtNode->RemoveFromList();
            // --> OD 2010-01-13 #b6912256#
            // clear all list attributes and the list style
            SvUShortsSort aResetAttrsArray;
            aResetAttrsArray.Insert( RES_PARATR_LIST_ID );
            aResetAttrsArray.Insert( RES_PARATR_LIST_LEVEL );
            aResetAttrsArray.Insert( RES_PARATR_LIST_ISRESTART );
            aResetAttrsArray.Insert( RES_PARATR_LIST_RESTARTVALUE );
            aResetAttrsArray.Insert( RES_PARATR_LIST_ISCOUNTED );
            aResetAttrsArray.Insert( RES_PARATR_NUMRULE );
            SwPaM aPam( *pTxtNode );
            pTxtNode->GetDoc()->ResetAttrs( aPam, sal_False,
                                            &aResetAttrsArray,
                                            false );
            // <--
        }
    }
}
// <--

// --> OD 2007-09-06 #i81002#
const SwNodeNum* SwNodeNum::GetPrecedingNodeNumOf( const SwTxtNode& rTxtNode ) const
{
    const SwNodeNum* pPrecedingNodeNum( 0 );

    // --> OD 2007-10-31 #i83479#
//    SwNodeNum aNodeNumForTxtNode;
//    aNodeNumForTxtNode.SetTxtNode( const_cast<SwTxtNode*>(&rTxtNode) );
    SwNodeNum aNodeNumForTxtNode( const_cast<SwTxtNode*>(&rTxtNode) );
    // <--

    pPrecedingNodeNum = dynamic_cast<const SwNodeNum*>(
                            GetRoot()
                            ? GetRoot()->GetPrecedingNodeOf( aNodeNumForTxtNode )
                            : GetPrecedingNodeOf( aNodeNumForTxtNode ) );

    return pPrecedingNodeNum;
}
// <--
