/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * 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.
 *
 ************************************************************************/

#include "XMLChangeTrackingImportHelper.hxx"
#include "XMLConverter.hxx"
#include "cell.hxx"

#include <bf_svtools/zforlist.hxx>

#include <bf_xmloff/xmluconv.hxx>
namespace binfilter {

#define SC_CHANGE_ID_PREFIX "ct"

ScMyCellInfo::ScMyCellInfo(ScBaseCell* pTempCell, const ::rtl::OUString& rFormulaAddress, const ::rtl::OUString& rFormula,
            const double& rValue, const sal_uInt16 nTempType, const sal_uInt8 nTempMatrixFlag, const sal_Int32 nTempMatrixCols,
            const sal_Int32 nTempMatrixRows)
    : pCell(pTempCell),
    sFormulaAddress(rFormulaAddress),
    sFormula(rFormula),
    fValue(rValue),
    nMatrixCols(nTempMatrixCols),
    nMatrixRows(nTempMatrixRows),
    nType(nTempType),
    nMatrixFlag(nTempMatrixFlag)
{
}

ScMyCellInfo::~ScMyCellInfo()
{
    if (pCell)
        pCell->Delete();
}

ScBaseCell* ScMyCellInfo::CreateCell(ScDocument* pDoc)
{
    if (pDoc)
    {
        if (!pCell && sFormula.getLength() && sFormulaAddress.getLength())
        {
            ScAddress aPos;
            sal_Int32 nOffset(0);
            ScXMLConverter::GetAddressFromString(aPos, sFormulaAddress, pDoc, nOffset);
            pCell = new ScFormulaCell(pDoc, aPos, sFormula, nMatrixFlag);
            static_cast<ScFormulaCell*>(pCell)->SetMatColsRows(static_cast<sal_uInt16>(nMatrixCols), static_cast<sal_uInt16>(nMatrixRows));
        }

        if (nType != NUMBERFORMAT_ALL)
        {
            if (nType == NUMBERFORMAT_DATE)
                pDoc->GetFormatTable()->GetInputLineString(fValue, NF_DATE_SYS_DDMMYYYY, sResult);
            else if (nType == NUMBERFORMAT_TIME)
                pDoc->GetFormatTable()->GetInputLineString(fValue, NF_TIME_HHMMSS, sResult);
        }
    }

    if (pCell)
        return pCell->Clone(pDoc);
    else
        return NULL;
}

ScMyDeleted::ScMyDeleted()
    : pCellInfo(NULL)
{
}

ScMyDeleted::~ScMyDeleted()
{
    if (pCellInfo)
        delete pCellInfo;
}

ScMyGenerated::ScMyGenerated(ScMyCellInfo* pTempCellInfo, const ScBigRange& aTempBigRange)
    : aBigRange(aTempBigRange),
    nID(0),
    pCellInfo(pTempCellInfo)
{
}

ScMyGenerated::~ScMyGenerated()
{
    if (pCellInfo)
        delete pCellInfo;
}

ScMyBaseAction::ScMyBaseAction(const ScChangeActionType nTempActionType)
    : aDependences(),
    aDeletedList(),
    nActionNumber(0),
    nRejectingNumber(0),
    nPreviousAction(0),
    nActionType(nTempActionType),
    nActionState(SC_CAS_VIRGIN)
{
}

ScMyBaseAction::~ScMyBaseAction()
{
}

ScMyInsAction::ScMyInsAction(const ScChangeActionType nInActionType)
    : ScMyBaseAction(nInActionType)
{
}

ScMyDelAction::ScMyDelAction(const ScChangeActionType nInActionType)
    : ScMyBaseAction(nInActionType)
    , aGeneratedList()
    , pInsCutOff(NULL)
    , aMoveCutOffs()
    , nD(0)
{
}

ScMyDelAction::~ScMyDelAction()
{
    if (pInsCutOff)
        delete pInsCutOff;
}

ScMyMoveAction::ScMyMoveAction()
    : ScMyBaseAction(SC_CAT_MOVE)
    , aGeneratedList()
    , pMoveRanges(NULL)
{
}

ScMyMoveAction::~ScMyMoveAction()
{
    if (pMoveRanges)
        delete pMoveRanges;
}


ScMyContentAction::ScMyContentAction()
    : ScMyBaseAction(SC_CAT_CONTENT),
    pCellInfo(NULL)
{
}

ScMyContentAction::~ScMyContentAction()
{
    if (pCellInfo)
        delete pCellInfo;
}

ScMyRejAction::ScMyRejAction()
    : ScMyBaseAction(SC_CAT_REJECT)
{
}

ScXMLChangeTrackingImportHelper::ScXMLChangeTrackingImportHelper() :
    aUsers(),
    aActions(),
    pDoc(NULL),
    pTrack(NULL),
    pCurrentAction(NULL),
    sIDPrefix(RTL_CONSTASCII_USTRINGPARAM(SC_CHANGE_ID_PREFIX)),
    nMultiSpanned(0),
    nMultiSpannedSlaveCount(0),
    bChangeTrack(sal_False)
{
    nPrefixLength = sIDPrefix.getLength();
}

ScXMLChangeTrackingImportHelper::~ScXMLChangeTrackingImportHelper()
{
}

void ScXMLChangeTrackingImportHelper::StartChangeAction(const ScChangeActionType nActionType)
{
    DBG_ASSERT(!pCurrentAction, "a not inserted action");
    switch (nActionType)
    {
        case SC_CAT_INSERT_COLS:
        case SC_CAT_INSERT_ROWS:
        case SC_CAT_INSERT_TABS:
        {
            pCurrentAction = new ScMyInsAction(nActionType);
        }
        break;
        case SC_CAT_DELETE_COLS:
        case SC_CAT_DELETE_ROWS:
        case SC_CAT_DELETE_TABS:
        {
            pCurrentAction = new ScMyDelAction(nActionType);
        }
        break;
        case SC_CAT_MOVE:
        {
            pCurrentAction = new ScMyMoveAction();
        }
        break;
        case SC_CAT_CONTENT:
        {
            pCurrentAction = new ScMyContentAction();
        }
        break;
        case SC_CAT_REJECT:
        {
            pCurrentAction = new ScMyRejAction();
        }
        break;
        default:
        break;
    }
}

sal_uInt32 ScXMLChangeTrackingImportHelper::GetIDFromString(const ::rtl::OUString& sID)
{
    sal_uInt32 nResult(0);
    sal_uInt32 nLength(sID.getLength());
    if (nLength)
    {
        if (sID.compareTo(sIDPrefix, nPrefixLength) == 0)
        {
            ::rtl::OUString sValue(sID.copy(nPrefixLength, nLength - nPrefixLength));
            sal_Int32 nValue;
            SvXMLUnitConverter::convertNumber(nValue, sValue);
            DBG_ASSERT(nValue > 0, "wrong change action ID");
            nResult = nValue;
        }
        else
            OSL_FAIL("wrong change action ID");
    }
    return nResult;
}

void ScXMLChangeTrackingImportHelper::SetActionInfo(const ScMyActionInfo& aInfo)
{
    pCurrentAction->aInfo = aInfo;
    String aUser(aInfo.sUser);
    StrData* pStrData = new StrData( aUser );
    if ( !aUsers.Insert( pStrData ) )
        delete pStrData;
}

void ScXMLChangeTrackingImportHelper::SetPreviousChange(const sal_uInt32 nPreviousAction,
                            ScMyCellInfo* pCellInfo)
{
    DBG_ASSERT(pCurrentAction->nActionType == SC_CAT_CONTENT, "wrong action type");
    ScMyContentAction* pAction = static_cast<ScMyContentAction*>(pCurrentAction);
    pAction->nPreviousAction = nPreviousAction;
    pAction->pCellInfo = pCellInfo;
}

void ScXMLChangeTrackingImportHelper::SetPosition(const sal_Int32 nPosition, const sal_Int32 nCount, const sal_Int32 nTable)
{
    DBG_ASSERT(((pCurrentAction->nActionType != SC_CAT_MOVE) &&
                (pCurrentAction->nActionType != SC_CAT_CONTENT) &&
                (pCurrentAction->nActionType != SC_CAT_REJECT)), "wrong action type");
    DBG_ASSERT(nCount > 0, "wrong count");
    switch(pCurrentAction->nActionType)
    {
        case SC_CAT_INSERT_COLS:
        case SC_CAT_DELETE_COLS:
        {
            pCurrentAction->aBigRange.Set(nPosition, nInt32Min, nTable,
                                        nPosition + nCount - 1, nInt32Max, nTable);
        }
        break;
        case SC_CAT_INSERT_ROWS:
        case SC_CAT_DELETE_ROWS:
        {
            pCurrentAction->aBigRange.Set(nInt32Min, nPosition, nTable,
                                        nInt32Max, nPosition + nCount - 1, nTable);
        }
        break;
        case SC_CAT_INSERT_TABS:
        case SC_CAT_DELETE_TABS:
        {
            pCurrentAction->aBigRange.Set(nInt32Min, nInt32Min, nPosition,
                                        nInt32Max, nInt32Max, nPosition + nCount - 1);
        }
        break;
        default:
        break;
    }
}

void ScXMLChangeTrackingImportHelper::AddDeleted(const sal_uInt32 nID)
{
    ScMyDeleted* pDeleted = new ScMyDeleted();
    pDeleted->nID = nID;
    pCurrentAction->aDeletedList.push_front(pDeleted);
}

void ScXMLChangeTrackingImportHelper::AddDeleted(const sal_uInt32 nID, ScMyCellInfo* pCellInfo)
{
    ScMyDeleted* pDeleted = new ScMyDeleted();
    pDeleted->nID = nID;
    pDeleted->pCellInfo = pCellInfo;
    pCurrentAction->aDeletedList.push_front(pDeleted);
}

void ScXMLChangeTrackingImportHelper::SetMultiSpanned(const sal_Int16 nTempMultiSpanned)
{
    if (nTempMultiSpanned)
    {
        DBG_ASSERT(((pCurrentAction->nActionType == SC_CAT_DELETE_COLS) ||
                    (pCurrentAction->nActionType == SC_CAT_DELETE_ROWS)), "wrong action type");
        nMultiSpanned = nTempMultiSpanned;
        nMultiSpannedSlaveCount = 0;
    }
}

void ScXMLChangeTrackingImportHelper::SetInsertionCutOff(const sal_uInt32 nID, const sal_Int32 nPosition)
{
    if ((pCurrentAction->nActionType == SC_CAT_DELETE_COLS) ||
        (pCurrentAction->nActionType == SC_CAT_DELETE_ROWS))
    {
        static_cast<ScMyDelAction*>(pCurrentAction)->pInsCutOff = new ScMyInsertionCutOff(nID, nPosition);
    }
    else
        OSL_FAIL("wrong action type");
}

void ScXMLChangeTrackingImportHelper::AddMoveCutOff(const sal_uInt32 nID, const sal_Int32 nStartPosition, const sal_Int32 nEndPosition)
{
    if ((pCurrentAction->nActionType == SC_CAT_DELETE_COLS) ||
        (pCurrentAction->nActionType == SC_CAT_DELETE_ROWS))
    {
        static_cast<ScMyDelAction*>(pCurrentAction)->aMoveCutOffs.push_front(ScMyMoveCutOff(nID, nStartPosition, nEndPosition));
    }
    else
        OSL_FAIL("wrong action type");
}

void ScXMLChangeTrackingImportHelper::SetMoveRanges(const ScBigRange& aSourceRange, const ScBigRange& aTargetRange)
{
    if (pCurrentAction->nActionType == SC_CAT_MOVE)
    {
         static_cast<ScMyMoveAction*>(pCurrentAction)->pMoveRanges = new ScMyMoveRanges(aSourceRange, aTargetRange);
    }
    else
        OSL_FAIL("wrong action type");
}

void ScXMLChangeTrackingImportHelper::GetMultiSpannedRange()
{
    if ((pCurrentAction->nActionType == SC_CAT_DELETE_COLS) ||
        (pCurrentAction->nActionType == SC_CAT_DELETE_ROWS))
    {
        if (nMultiSpannedSlaveCount)
        {
            static_cast<ScMyDelAction*>(pCurrentAction)->nD = nMultiSpannedSlaveCount;
        }
        nMultiSpannedSlaveCount++;
        if (nMultiSpannedSlaveCount >= nMultiSpanned)
        {
            nMultiSpanned = 0;
            nMultiSpannedSlaveCount = 0;
        }
    }
    else
        OSL_FAIL("wrong action type");
}

void ScXMLChangeTrackingImportHelper::AddGenerated(ScMyCellInfo* pCellInfo, const ScBigRange& aBigRange)
{
    ScMyGenerated* pGenerated = new ScMyGenerated(pCellInfo, aBigRange);
    if (pCurrentAction->nActionType == SC_CAT_MOVE)
    {
        static_cast<ScMyMoveAction*>(pCurrentAction)->aGeneratedList.push_back(pGenerated);
    }
    else if ((pCurrentAction->nActionType == SC_CAT_DELETE_COLS) ||
        (pCurrentAction->nActionType == SC_CAT_DELETE_ROWS))
    {
        static_cast<ScMyDelAction*>(pCurrentAction)->aGeneratedList.push_back(pGenerated);
    }
    else
        OSL_FAIL("try to insert a generated action to a wrong action");
}

void ScXMLChangeTrackingImportHelper::EndChangeAction()
{
    if ((pCurrentAction->nActionType == SC_CAT_DELETE_COLS) ||
        (pCurrentAction->nActionType == SC_CAT_DELETE_ROWS))
        GetMultiSpannedRange();
    if (pCurrentAction && pCurrentAction->nActionNumber > 0)
        aActions.push_back(pCurrentAction);
    else
        OSL_FAIL("no current action");
    pCurrentAction = NULL;
}

void ScXMLChangeTrackingImportHelper::ConvertInfo(const ScMyActionInfo& aInfo, String& rUser, DateTime& aDateTime)
{
    Date aDate(aInfo.aDateTime.Day, aInfo.aDateTime.Month, aInfo.aDateTime.Year);
    Time aTime(aInfo.aDateTime.Hours, aInfo.aDateTime.Minutes, aInfo.aDateTime.Seconds, aInfo.aDateTime.HundredthSeconds);
    aDateTime.SetDate( aDate.GetDate() );
    aDateTime.SetTime( aTime.GetTime() );

    // #97286# old files didn't store 100th seconds, enable again
    if ( aInfo.aDateTime.HundredthSeconds )
        pTrack->SetTime100thSeconds( TRUE );

    StrData aStrData( aInfo.sUser );
    USHORT nPos;
    if ( pTrack->GetUserCollection().Search( &aStrData, nPos ) )
    {
        const StrData* pUser = static_cast<const StrData*>( pTrack->GetUserCollection().At( nPos ) );
        if ( pUser )
            rUser = pUser->GetString();
        else
            rUser = aInfo.sUser;    // shouldn't happen
    }
    else
        rUser = aInfo.sUser;    // shouldn't happen
}

ScChangeAction* ScXMLChangeTrackingImportHelper::CreateInsertAction(ScMyInsAction* pAction)
{
    DateTime aDateTime( Date(0), Time(0) );
    String aUser;
    ConvertInfo(pAction->aInfo, aUser, aDateTime);

    String sComment (pAction->aInfo.sComment);

    ScChangeAction* pNewAction = new ScChangeActionIns(pAction->nActionNumber, pAction->nActionState, pAction->nRejectingNumber,
        pAction->aBigRange, aUser, aDateTime, sComment, pAction->nActionType);
    return pNewAction;
}

ScChangeAction* ScXMLChangeTrackingImportHelper::CreateDeleteAction(ScMyDelAction* pAction)
{
    DateTime aDateTime( Date(0), Time(0) );
    String aUser;
    ConvertInfo(pAction->aInfo, aUser, aDateTime);

    String sComment (pAction->aInfo.sComment);

    ScChangeAction* pNewAction = new ScChangeActionDel(pAction->nActionNumber, pAction->nActionState, pAction->nRejectingNumber,
        pAction->aBigRange, aUser, aDateTime, sComment, pAction->nActionType, pAction->nD, pTrack);
    return pNewAction;
}

ScChangeAction* ScXMLChangeTrackingImportHelper::CreateMoveAction(ScMyMoveAction* pAction)
{
    DBG_ASSERT(pAction->pMoveRanges, "no move ranges");
    if (pAction->pMoveRanges)
    {
        DateTime aDateTime( Date(0), Time(0) );
        String aUser;
        ConvertInfo(pAction->aInfo, aUser, aDateTime);

        String sComment (pAction->aInfo.sComment);

        ScChangeAction* pNewAction = new ScChangeActionMove(pAction->nActionNumber, pAction->nActionState, pAction->nRejectingNumber,
            pAction->pMoveRanges->aTargetRange, aUser, aDateTime, sComment, pAction->pMoveRanges->aSourceRange , pTrack);
        return pNewAction;
    }
    return NULL;
}

ScChangeAction* ScXMLChangeTrackingImportHelper::CreateRejectionAction(ScMyRejAction* pAction)
{
    DateTime aDateTime( Date(0), Time(0) );
    String aUser;
    ConvertInfo(pAction->aInfo, aUser, aDateTime);

    String sComment (pAction->aInfo.sComment);

    ScChangeAction* pNewAction = new ScChangeActionReject(pAction->nActionNumber, pAction->nActionState, pAction->nRejectingNumber,
        pAction->aBigRange, aUser, aDateTime, sComment);
    return pNewAction;
}

ScChangeAction* ScXMLChangeTrackingImportHelper::CreateContentAction(ScMyContentAction* pAction)
{
    ScBaseCell* pCell = NULL;
    if (pAction->pCellInfo)
         pCell = pAction->pCellInfo->CreateCell(pDoc);

    DateTime aDateTime( Date(0), Time(0) );
    String aUser;
    ConvertInfo(pAction->aInfo, aUser, aDateTime);

    String sComment (pAction->aInfo.sComment);

    ScChangeAction* pNewAction = new ScChangeActionContent(pAction->nActionNumber, pAction->nActionState, pAction->nRejectingNumber,
        pAction->aBigRange, aUser, aDateTime, sComment, pCell, pDoc, pAction->pCellInfo->sResult);
    return pNewAction;
}

void ScXMLChangeTrackingImportHelper::CreateGeneratedActions(ScMyGeneratedList& rList)
{
    if (!rList.empty())
    {
        ScMyGeneratedList::iterator aItr = rList.begin();
        while (aItr != rList.end())
        {
            if (((*aItr)->nID == 0))
            {
                ScBaseCell* pCell = NULL;
                if ((*aItr)->pCellInfo)
                    pCell = (*aItr)->pCellInfo->CreateCell(pDoc);

                if (pCell)
                {
                    (*aItr)->nID = pTrack->AddLoadedGenerated(pCell, (*aItr)->aBigRange );
                    DBG_ASSERT((*aItr)->nID, "could not insert generated action");
                }
            }
            ++aItr;
        }
    }
}

void ScXMLChangeTrackingImportHelper::SetDeletionDependences(ScMyDelAction* pAction, ScChangeActionDel* pDelAct)
{
    if (!pAction->aGeneratedList.empty())
    {
        DBG_ASSERT(((pAction->nActionType == SC_CAT_DELETE_COLS) ||
            (pAction->nActionType == SC_CAT_DELETE_ROWS) ||
            (pAction->nActionType == SC_CAT_DELETE_TABS)), "wrong action type");
        if (pDelAct)
        {
            ScMyGeneratedList::iterator aItr = pAction->aGeneratedList.begin();
            while (aItr != pAction->aGeneratedList.end())
            {
                DBG_ASSERT((*aItr)->nID, "a not inserted generated action");
                pDelAct->SetDeletedInThis((*aItr)->nID, pTrack);
                if (*aItr)
                    delete *aItr;
                aItr = pAction->aGeneratedList.erase(aItr);
            }
        }
    }
    if (pAction->pInsCutOff)
    {
        DBG_ASSERT(((pAction->nActionType == SC_CAT_DELETE_COLS) ||
            (pAction->nActionType == SC_CAT_DELETE_ROWS) ||
            (pAction->nActionType == SC_CAT_DELETE_TABS)), "wrong action type");
        ScChangeAction* pChangeAction = pTrack->GetAction(pAction->pInsCutOff->nID);
        if (pChangeAction && pChangeAction->IsInsertType())
        {
            ScChangeActionIns* pInsAction = static_cast<ScChangeActionIns*>(pChangeAction);
            if (pInsAction && pDelAct)
                pDelAct->SetCutOffInsert(pInsAction, static_cast<sal_Int16>(pAction->pInsCutOff->nPosition));
        }
        else
            OSL_FAIL("no cut off insert action");
    }
    if (!pAction->aMoveCutOffs.empty())
    {
        DBG_ASSERT(((pAction->nActionType == SC_CAT_DELETE_COLS) ||
            (pAction->nActionType == SC_CAT_DELETE_ROWS) ||
            (pAction->nActionType == SC_CAT_DELETE_TABS)), "wrong action type");
        ScMyMoveCutOffs::iterator aItr = pAction->aMoveCutOffs.begin();
        while(aItr != pAction->aMoveCutOffs.end())
        {
            ScChangeAction* pChangeAction = pTrack->GetAction(aItr->nID);
            if (pChangeAction && (pChangeAction->GetType() == SC_CAT_MOVE))
            {
                ScChangeActionMove* pMoveAction = static_cast<ScChangeActionMove*>(pChangeAction);
                if (pMoveAction && pDelAct)
                    pDelAct->AddCutOffMove(pMoveAction, static_cast<sal_Int16>(aItr->nStartPosition),
                                        static_cast<sal_Int16>(aItr->nEndPosition));
            }
            else
                OSL_FAIL("no cut off move action");
            aItr = pAction->aMoveCutOffs.erase(aItr);
        }
    }
}

void ScXMLChangeTrackingImportHelper::SetMovementDependences(ScMyMoveAction* pAction, ScChangeActionMove* pMoveAct)
{
    if (!pAction->aGeneratedList.empty())
    {
        if (pAction->nActionType == SC_CAT_MOVE)
        {
            if (pMoveAct)
            {
                ScMyGeneratedList::iterator aItr = pAction->aGeneratedList.begin();
                while (aItr != pAction->aGeneratedList.end())
                {
                    DBG_ASSERT((*aItr)->nID, "a not inserted generated action");
                    pMoveAct->SetDeletedInThis((*aItr)->nID, pTrack);
                    if (*aItr)
                        delete *aItr;
                    aItr = pAction->aGeneratedList.erase(aItr);
                }
            }
        }
    }
}

void ScXMLChangeTrackingImportHelper::SetContentDependences(ScMyContentAction* pAction, ScChangeActionContent* pActContent)
{
    if (pAction->nPreviousAction)
    {
        DBG_ASSERT(pAction->nActionType == SC_CAT_CONTENT, "wrong action type");
        ScChangeAction* pPrevAct = pTrack->GetAction(pAction->nPreviousAction);
        if (pPrevAct)
        {
            ScChangeActionContent* pPrevActContent = static_cast<ScChangeActionContent*>(pPrevAct);
            if (pPrevActContent && pActContent)
            {
                pActContent->SetPrevContent(pPrevActContent);
                pPrevActContent->SetNextContent(pActContent);
                const ScBaseCell* pOldCell = pActContent->GetOldCell();
                if (pOldCell)
                {
                    ScBaseCell* pNewCell = pOldCell->Clone(pDoc);
                    if (pNewCell)
                        pPrevActContent->SetNewCell(pNewCell, pDoc);
                }
            }
        }
    }
}

void ScXMLChangeTrackingImportHelper::SetDependences(ScMyBaseAction* pAction)
{
    ScChangeAction* pAct = pTrack->GetAction(pAction->nActionNumber);
    if (pAct)
    {
        if (!pAction->aDependences.empty())
        {
            ScMyDependences::iterator aItr = pAction->aDependences.begin();
            while(aItr != pAction->aDependences.end())
            {
                pAct->AddDependent(*aItr, pTrack);
                aItr = pAction->aDependences.erase(aItr);
            }
        }
        if (!pAction->aDeletedList.empty())
        {
            ScMyDeletedList::iterator aItr = pAction->aDeletedList.begin();
            while(aItr != pAction->aDeletedList.end())
            {
                pAct->SetDeletedInThis((*aItr)->nID, pTrack);
                ScChangeAction* pDeletedAct = pTrack->GetAction((*aItr)->nID);
                if ((pDeletedAct->GetType() == SC_CAT_CONTENT) && (*aItr)->pCellInfo)
                {
                    ScChangeActionContent* pContentAct = static_cast<ScChangeActionContent*>(pDeletedAct);
                    if (pContentAct && (*aItr)->pCellInfo)
                    {
                        ScBaseCell* pCell = (*aItr)->pCellInfo->CreateCell(pDoc);
                        if (!ScBaseCell::CellEqual(pCell, pContentAct->GetNewCell()))
                            pContentAct->SetNewCell(pCell, pDoc);
                    }
                }
                if (*aItr)
                    delete *aItr;
                aItr = pAction->aDeletedList.erase(aItr);
            }
        }
        if ((pAction->nActionType == SC_CAT_DELETE_COLS) ||
            (pAction->nActionType == SC_CAT_DELETE_ROWS))
            SetDeletionDependences(static_cast<ScMyDelAction*>(pAction), static_cast<ScChangeActionDel*>(pAct));
        else if (pAction->nActionType == SC_CAT_MOVE)
            SetMovementDependences(static_cast<ScMyMoveAction*>(pAction), static_cast<ScChangeActionMove*>(pAct));
        else if (pAction->nActionType == SC_CAT_CONTENT)
            SetContentDependences(static_cast<ScMyContentAction*>(pAction), static_cast<ScChangeActionContent*>(pAct));
    }
    else
        OSL_FAIL("could not find the action");
}

void ScXMLChangeTrackingImportHelper::SetNewCell(ScMyContentAction* pAction)
{
    ScChangeAction* pChangeAction = pTrack->GetAction(pAction->nActionNumber);
    if (pChangeAction)
    {
        ScChangeActionContent* pChangeActionContent = static_cast<ScChangeActionContent*>(pChangeAction);
        if (pChangeActionContent)
        {
            if (pChangeActionContent->IsTopContent() && !pChangeActionContent->IsDeletedIn())
            {
                sal_Int32 nCol, nRow, nTab, nCol2, nRow2, nTab2;
                pAction->aBigRange.GetVars(nCol, nRow, nTab, nCol2, nRow2, nTab2);
                if ((nCol >= 0) && (nCol <= MAXCOL) &&
                    (nRow >= 0) && (nRow <= MAXROW) &&
                    (nTab >= 0) && (nTab <= MAXTAB))
                {
                    ScAddress aAddress (static_cast<sal_uInt16>(nCol),
                                        static_cast<sal_uInt16>(nRow),
                                        static_cast<sal_uInt16>(nTab));
                    ScBaseCell* pCell = pDoc->GetCell(aAddress);
                    if (pCell)
                    {
                        ScBaseCell* pNewCell = NULL;
                        if (pCell->GetCellType() != CELLTYPE_FORMULA)
                            pNewCell = pCell->Clone(pDoc);
                        else
                        {
                            sal_uInt8 nMatrixFlag = static_cast<ScFormulaCell*>(pCell)->GetMatrixFlag();
                            String sFormula;
                            static_cast<ScFormulaCell*>(pCell)->GetFormula(sFormula);
                            ::rtl::OUString sOUFormula(sFormula);
                            ::rtl::OUString sOUFormula2(sOUFormula.copy(2, sOUFormula.getLength() - 3));
                            String sFormula2(sOUFormula2);
                            pNewCell = new ScFormulaCell(pDoc, aAddress, sFormula2, nMatrixFlag);
                            if (pNewCell)
                            {
                                if (nMatrixFlag == MM_FORMULA)
                                {
                                    sal_uInt16 nCols, nRows;
                                    static_cast<ScFormulaCell*>(pCell)->GetMatColsRows(nCols, nRows);
                                    static_cast<ScFormulaCell*>(pNewCell)->SetMatColsRows(nCols, nRows);
                                }
                                static_cast<ScFormulaCell*>(pNewCell)->SetInChangeTrack(sal_True);
                            }
                        }
                        pChangeActionContent->SetNewCell(pNewCell, pDoc);
                    }
                }
                else
                    OSL_FAIL("wrong cell position");
            }
        }
    }
}

void ScXMLChangeTrackingImportHelper::CreateChangeTrack(ScDocument* pTempDoc)
{
    pDoc = pTempDoc;
    if (pDoc)
    {
        pTrack = new ScChangeTrack(pDoc, aUsers);
        // #97286# old files didn't store 100th seconds, disable until encountered
        pTrack->SetTime100thSeconds( FALSE );

        ScMyActions::iterator aItr = aActions.begin();
        while (aItr != aActions.end())
        {
            ScChangeAction* pAction = NULL;

            switch ((*aItr)->nActionType)
            {
                case SC_CAT_INSERT_COLS:
                case SC_CAT_INSERT_ROWS:
                case SC_CAT_INSERT_TABS:
                {
                    pAction = CreateInsertAction(static_cast<ScMyInsAction*>(*aItr));
                }
                break;
                case SC_CAT_DELETE_COLS:
                case SC_CAT_DELETE_ROWS:
                case SC_CAT_DELETE_TABS:
                {
                    ScMyDelAction* pDelAct = static_cast<ScMyDelAction*>(*aItr);
                    pAction = CreateDeleteAction(pDelAct);
                    CreateGeneratedActions(pDelAct->aGeneratedList);
                }
                break;
                case SC_CAT_MOVE:
                {
                    ScMyMoveAction* pMovAct = static_cast<ScMyMoveAction*>(*aItr);
                    pAction = CreateMoveAction(pMovAct);
                    CreateGeneratedActions(pMovAct->aGeneratedList);
                }
                break;
                case SC_CAT_CONTENT:
                {
                    pAction = CreateContentAction(static_cast<ScMyContentAction*>(*aItr));
                }
                break;
                case SC_CAT_REJECT:
                {
                    pAction = CreateRejectionAction(static_cast<ScMyRejAction*>(*aItr));
                }
                break;
                default:
                break;
            }

            if (pAction)
                pTrack->AppendLoaded(pAction);
            else
                OSL_FAIL("no action");

            ++aItr;
        }
        if (pTrack->GetLast())
            pTrack->SetActionMax(pTrack->GetLast()->GetActionNumber());

        aItr = aActions.begin();
        while (aItr != aActions.end())
        {
            SetDependences(*aItr);

            if ((*aItr)->nActionType == SC_CAT_CONTENT)
                ++aItr;
            else
            {
                if (*aItr)
                    delete (*aItr);
                aItr = aActions.erase(aItr);
            }
        }

        aItr = aActions.begin();
        while (aItr != aActions.end())
        {
            DBG_ASSERT((*aItr)->nActionType == SC_CAT_CONTENT, "wrong action type");
            SetNewCell(static_cast<ScMyContentAction*>(*aItr));
            if (*aItr)
                delete (*aItr);
            aItr = aActions.erase(aItr);
        }
        if (aProtect.getLength())
            pTrack->SetProtection(aProtect);

        if ( pTrack->GetLast() )
            pTrack->SetLastSavedActionNumber(pTrack->GetLast()->GetActionNumber());

        pDoc->SetChangeTrack(pTrack);
    }
}
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
