/* -*- 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.
 *
 ************************************************************************/

#ifdef _MSC_VER
#pragma hdrstop
#endif

// INCLUDE ---------------------------------------------------------------

#include "XMLStylesExportHelper.hxx"

#include "unonames.hxx"
#include "XMLConverter.hxx"
#include "xmlexprt.hxx"
#include "document.hxx"

#include <bf_xmloff/xmlnmspe.hxx>
#include <bf_xmloff/XMLEventExport.hxx>

#include <tools/debug.hxx>
#include <com/sun/star/uno/Reference.h>
#include <com/sun/star/sheet/XSheetCondition.hpp>

#include <algorithm>
namespace binfilter {

using namespace ::com::sun::star;
using namespace xmloff::token;

ScMyValidation::ScMyValidation()
    : sName(),
    sErrorMessage(),
    sErrorTitle(),
    sImputMessage(),
    sImputTitle(),
    sFormula1(),
    sFormula2(),
    bShowErrorMessage(sal_False),
    bShowImputMessage(sal_False),
    bIgnoreBlanks(sal_False)
{
}

ScMyValidation::~ScMyValidation()
{
}

sal_Bool ScMyValidation::IsEqual(const ScMyValidation& aVal) const
{
    if (aVal.bIgnoreBlanks == bIgnoreBlanks &&
        aVal.bShowImputMessage == bShowImputMessage &&
        aVal.bShowErrorMessage == bShowErrorMessage &&
        aVal.aBaseCell.Sheet == aBaseCell.Sheet &&
        aVal.aBaseCell.Column == aBaseCell.Column &&
        aVal.aBaseCell.Row == aBaseCell.Row &&
        aVal.aAlertStyle == aAlertStyle &&
        aVal.aValidationType == aValidationType &&
        aVal.aOperator == aOperator &&
        aVal.sErrorTitle == sErrorTitle &&
        aVal.sImputTitle == sImputTitle &&
        aVal.sErrorMessage == sErrorMessage &&
        aVal.sImputMessage == sImputMessage &&
        aVal.sFormula1 == sFormula1 &&
        aVal.sFormula2 == sFormula2)
        return sal_True;
    else
        return sal_False;
}

ScMyValidationsContainer::ScMyValidationsContainer()
    : aValidationVec(),
    sEmptyString(),
    sERRALSTY(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_ERRALSTY)),
    sIGNOREBL(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_IGNOREBL)),
    sTYPE(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_TYPE)),
    sSHOWINP(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_SHOWINP)),
    sSHOWERR(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_SHOWERR)),
    sINPTITLE(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_INPTITLE)),
    sINPMESS(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_INPMESS)),
    sERRTITLE(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_ERRTITLE)),
    sERRMESS(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_ERRMESS)),
    sOnError(RTL_CONSTASCII_USTRINGPARAM("OnError")),
    sEventType(RTL_CONSTASCII_USTRINGPARAM("EventType")),
    sStarBasic(RTL_CONSTASCII_USTRINGPARAM("StarBasic")),
    sLibrary(RTL_CONSTASCII_USTRINGPARAM("Library")),
    sMacroName(RTL_CONSTASCII_USTRINGPARAM("MacroName"))
{
}

ScMyValidationsContainer::~ScMyValidationsContainer()
{
}

sal_Bool ScMyValidationsContainer::AddValidation(const uno::Any& aTempAny,
    sal_Int32& nValidationIndex)
{
    sal_Bool bAdded(sal_False);
    uno::Reference<beans::XPropertySet> xPropertySet;
    if (aTempAny >>= xPropertySet)
    {
        uno::Any aAny = xPropertySet->getPropertyValue(sERRMESS);
        ::rtl::OUString sErrorMessage;
        aAny >>= sErrorMessage;
        aAny = xPropertySet->getPropertyValue(sERRTITLE);
        ::rtl::OUString sErrorTitle;
        aAny >>= sErrorTitle;
        aAny = xPropertySet->getPropertyValue(sINPMESS);
        ::rtl::OUString sImputMessage;
        aAny >>= sImputMessage;
        aAny = xPropertySet->getPropertyValue(sINPTITLE);
        ::rtl::OUString sImputTitle;
        aAny >>= sImputTitle;
        aAny = xPropertySet->getPropertyValue(sSHOWERR);
        sal_Bool bShowErrorMessage(sal_False);
        aAny >>= bShowErrorMessage;
        aAny = xPropertySet->getPropertyValue(sSHOWINP);
        sal_Bool bShowImputMessage(sal_False);
        aAny >>= bShowImputMessage;
        aAny = xPropertySet->getPropertyValue(sTYPE);
        sheet::ValidationType aValidationType;
        aAny >>= aValidationType;
        if (bShowErrorMessage || bShowImputMessage || aValidationType != sheet::ValidationType_ANY ||
            sErrorMessage.getLength() || sErrorTitle.getLength() || sImputMessage.getLength() || sImputTitle.getLength())
        {
            ScMyValidation aValidation;
            aValidation.sErrorMessage = sErrorMessage;
            aValidation.sErrorTitle = sErrorTitle;
            aValidation.sImputMessage = sImputMessage;
            aValidation.sImputTitle = sImputTitle;
            aValidation.bShowErrorMessage = bShowErrorMessage;
            aValidation.bShowImputMessage = bShowImputMessage;
            aValidation.aValidationType = aValidationType;
            aAny = xPropertySet->getPropertyValue(sIGNOREBL);
            sal_Bool bIgnoreBlanks(sal_False);
            aAny >>= bIgnoreBlanks;
            aValidation.bIgnoreBlanks = bIgnoreBlanks;
            aAny = xPropertySet->getPropertyValue(sERRALSTY);
            aAny >>= aValidation.aAlertStyle;
            uno::Reference<sheet::XSheetCondition> xCondition(xPropertySet, uno::UNO_QUERY);
            if (xCondition.is())
            {
                aValidation.sFormula1 = xCondition->getFormula1();
                aValidation.sFormula2 = xCondition->getFormula2();
                aValidation.aOperator = xCondition->getOperator();
                aValidation.aBaseCell = xCondition->getSourcePosition();
            }
            //ScMyValidationRange aValidationRange;
            sal_Bool bEqualFound(sal_False);
            sal_Int32 i = 0;
            sal_Int32 nCount = aValidationVec.size();
            while (i < nCount && !bEqualFound)
            {
                bEqualFound = aValidationVec[i].IsEqual(aValidation);
                if (!bEqualFound)
                    i++;
            }
            if (bEqualFound)
                nValidationIndex = i;
            else
            {
                sal_Int32 nNameIndex = nCount + 1;
                ::rtl::OUString sCount = ::rtl::OUString::valueOf(nNameIndex);
                ::rtl::OUString sPrefix(RTL_CONSTASCII_USTRINGPARAM("val"));
                aValidation.sName += sPrefix;
                aValidation.sName += sCount;
                aValidationVec.push_back(aValidation);
                nValidationIndex = nCount;
                bAdded = sal_True;
            }
        }
    }
    return bAdded;
}

rtl::OUString ScMyValidationsContainer::GetCondition(const ScMyValidation& aValidation)
{
    ::rtl::OUString sCondition;
    if (aValidation.aValidationType != sheet::ValidationType_ANY)
    {
        switch (aValidation.aValidationType)
        {
            //case sheet::ValidationType_CUSTOM
            case sheet::ValidationType_DATE :
                sCondition += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("cell-content-is-date()"));
            break;
            case sheet::ValidationType_DECIMAL :
                sCondition += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("cell-content-is-decimal-number()"));
            break;
            //case sheet::ValidationType_LIST :
            case sheet::ValidationType_TEXT_LEN :
                if (aValidation.aOperator != sheet::ConditionOperator_BETWEEN &&
                    aValidation.aOperator != sheet::ConditionOperator_NOT_BETWEEN)
                    sCondition += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("cell-content-text-length()"));
            break;
            case sheet::ValidationType_TIME :
                sCondition += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("cell-content-is-time()"));
            break;
            case sheet::ValidationType_WHOLE :
                sCondition += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("cell-content-is-whole-number()"));
            break;
            default :
            break;
        }
        if (aValidation.sFormula1.getLength() ||
            (aValidation.aOperator == sheet::ConditionOperator_BETWEEN &&
            aValidation.aOperator == sheet::ConditionOperator_NOT_BETWEEN &&
            aValidation.sFormula2.getLength()))
        {
            if (aValidation.aValidationType != sheet::ValidationType_TEXT_LEN)
                sCondition += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" and "));
            if (aValidation.aOperator != sheet::ConditionOperator_BETWEEN &&
                aValidation.aOperator != sheet::ConditionOperator_NOT_BETWEEN)
            {
                if (aValidation.aValidationType != sheet::ValidationType_TEXT_LEN)
                    sCondition += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("cell-content()"));
                switch (aValidation.aOperator)
                {
                    case sheet::ConditionOperator_EQUAL :
                        sCondition += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("="));
                    break;
                    case sheet::ConditionOperator_GREATER :
                        sCondition += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(">"));
                    break;
                    case sheet::ConditionOperator_GREATER_EQUAL :
                        sCondition += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(">="));
                    break;
                    case sheet::ConditionOperator_LESS :
                        sCondition += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("<"));
                    break;
                    case sheet::ConditionOperator_LESS_EQUAL :
                        sCondition += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("<="));
                    break;
                    case sheet::ConditionOperator_NOT_EQUAL :
                        sCondition += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("!="));
                    break;
                    default :
                    break;
                }
                sCondition += aValidation.sFormula1;
            }
            else
            {
                if (aValidation.aValidationType == sheet::ValidationType_TEXT_LEN)
                {
                    if (aValidation.aOperator == sheet::ConditionOperator_BETWEEN)
                        sCondition += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("cell-content-text-length-is-between("));
                    else
                        sCondition += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("cell-content-text-length-is-not-between("));
                }
                else
                {
                    if (aValidation.aOperator == sheet::ConditionOperator_BETWEEN)
                        sCondition += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("cell-content-is-between("));
                    else
                        sCondition += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("cell-content-is-not-between("));
                }
                sCondition += aValidation.sFormula1;
                sCondition += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(","));
                sCondition += aValidation.sFormula2;
                sCondition += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(")"));
            }
        }
        else
            if (aValidation.aValidationType == sheet::ValidationType_TEXT_LEN)
                sCondition = ::rtl::OUString();
    }
    return sCondition;
}

rtl::OUString ScMyValidationsContainer::GetBaseCellAddress(ScDocument* pDoc, const table::CellAddress& aCell)
{
    ::rtl::OUString sAddress;
    ScXMLConverter::GetStringFromAddress( sAddress, aCell, pDoc );
    return sAddress;
}

void ScMyValidationsContainer::WriteMessage(ScXMLExport& rExport,
    const ::rtl::OUString& sTitle, const ::rtl::OUString& sOUMessage,
    const sal_Bool bShowMessage, const sal_Bool bIsHelpMessage)
{
    if (sTitle.getLength())
        rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_TITLE, sTitle);
    if (bShowMessage)
        rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_DISPLAY, XML_TRUE);
    else
        rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_DISPLAY, XML_FALSE);
    SvXMLElementExport* pMessage = NULL;
    if (bIsHelpMessage)
        pMessage = new SvXMLElementExport(rExport, XML_NAMESPACE_TABLE, XML_HELP_MESSAGE, sal_True, sal_True);
    else
        pMessage = new SvXMLElementExport(rExport, XML_NAMESPACE_TABLE, XML_ERROR_MESSAGE, sal_True, sal_True);
    if (sOUMessage.getLength())
    {
        sal_Int32 i = 0;
        ::rtl::OUStringBuffer sTemp;
        ::rtl::OUString sText(convertLineEnd(sOUMessage, LINEEND_LF));
        sal_Bool bPrevCharWasSpace(sal_True);
        while(i < sText.getLength())
        {
            if ((sText[i] == '\n'))
            {
                SvXMLElementExport aElemP(rExport, XML_NAMESPACE_TEXT, XML_P, sal_True, sal_False);
                rExport.GetTextParagraphExport()->exportText(sTemp.makeStringAndClear(), bPrevCharWasSpace);
            }
            else
                sTemp.append(sText[i]);
            i++;
        }
        if (sTemp.getLength())
        {
            SvXMLElementExport aElemP(rExport, XML_NAMESPACE_TEXT, XML_P, sal_True, sal_False);
            rExport.GetTextParagraphExport()->exportText(sTemp.makeStringAndClear(), bPrevCharWasSpace);
        }
    }
    if (pMessage)
        delete pMessage;
}

void ScMyValidationsContainer::WriteValidations(ScXMLExport& rExport)
{
    if (!aValidationVec.empty())
    {
        SvXMLElementExport aElemVs(rExport, XML_NAMESPACE_TABLE, XML_CONTENT_VALIDATIONS, sal_True, sal_True);
        ScMyValidationVec::iterator aItr = aValidationVec.begin();
        while (aItr != aValidationVec.end())
        {
            rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_NAME, aItr->sName);
            ::rtl::OUString sCondition = GetCondition(*aItr);
            if (sCondition.getLength())
            {
                rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_CONDITION, sCondition);
                if (aItr->bIgnoreBlanks)
                    rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_ALLOW_EMPTY_CELL, XML_FALSE);
                else
                    rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_ALLOW_EMPTY_CELL, XML_TRUE);
            }
            rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_BASE_CELL_ADDRESS, GetBaseCellAddress(rExport.GetDocument(), aItr->aBaseCell));
            SvXMLElementExport aElemV(rExport, XML_NAMESPACE_TABLE, XML_CONTENT_VALIDATION, sal_True, sal_True);
            if (aItr->bShowImputMessage || aItr->sImputMessage.getLength() || aItr->sImputTitle.getLength())
            {
                WriteMessage(rExport, aItr->sImputTitle, aItr->sImputMessage, aItr->bShowImputMessage, sal_True);
            }
            if (aItr->bShowErrorMessage || aItr->sErrorMessage.getLength() || aItr->sErrorTitle.getLength())
            {
                switch (aItr->aAlertStyle)
                {
                    case sheet::ValidationAlertStyle_INFO :
                    {
                        rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_MESSAGE_TYPE, XML_INFORMATION);
                        WriteMessage(rExport, aItr->sErrorTitle, aItr->sErrorMessage, aItr->bShowErrorMessage, sal_False);
                    }
                    break;
                    case sheet::ValidationAlertStyle_WARNING :
                    {
                        rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_MESSAGE_TYPE, XML_WARNING);
                        WriteMessage(rExport, aItr->sErrorTitle, aItr->sErrorMessage, aItr->bShowErrorMessage, sal_False);
                    }
                    break;
                    case sheet::ValidationAlertStyle_STOP :
                    {
                        rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_MESSAGE_TYPE, XML_STOP);
                        WriteMessage(rExport, aItr->sErrorTitle, aItr->sErrorMessage, aItr->bShowErrorMessage, sal_False);
                    }
                    break;
                    case sheet::ValidationAlertStyle_MACRO :
                    {
                        rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_NAME, aItr->sErrorTitle);
                        if (aItr->bShowErrorMessage)
                            rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_EXECUTE, XML_TRUE);
                        else
                            rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_EXECUTE, XML_FALSE);
                        SvXMLElementExport(rExport, XML_NAMESPACE_TABLE, XML_ERROR_MACRO, sal_True, sal_True);
                        {
                            uno::Sequence<beans::PropertyValue> aSeq(3);
                            beans::PropertyValue* pArr = aSeq.getArray();
                            pArr[0].Name = sEventType;
                            pArr[0].Value <<= sStarBasic;
                            pArr[1].Name = sLibrary;
                            pArr[1].Value <<= sEmptyString;
                            pArr[2].Name = sMacroName;
                            pArr[2].Value <<= aItr->sErrorTitle;

                            // 2) export the sequence
                            rExport.GetEventExport().ExportSingleEvent( aSeq, sOnError);
                        }
                    }
                    break;
                    default :
                    break;
                }
            }
            ++aItr;
        }
    }
}

const ::rtl::OUString& ScMyValidationsContainer::GetValidationName(const sal_Int32 nIndex)
{
    DBG_ASSERT( static_cast<sal_uInt32>(nIndex) < aValidationVec.size(), "out of range" );
    return aValidationVec[nIndex].sName;
}

//==============================================================================

sal_Int32 ScMyDefaultStyles::GetStyleNameIndex(const ScFormatRangeStyles* pCellStyles,
    const sal_uInt16 nTable, const sal_Int32 nPos,
    const sal_Int32 i, const sal_Bool bRow, sal_Bool& bIsAutoStyle)
{
    if (bRow)
        return pCellStyles->GetStyleNameIndex(nTable, nPos, i,
                                bIsAutoStyle);
    else
        return pCellStyles->GetStyleNameIndex(nTable, i, nPos,
                                bIsAutoStyle);
}

void ScMyDefaultStyles::FillDefaultStyles(const sal_uInt16 nTable,
    const sal_Int32 nLastRow, const sal_Int32 nLastCol,
    const ScFormatRangeStyles* pCellStyles, ScDocument* pDoc,
    const sal_Bool bRow)
{
    if (pDoc)
    {
        sal_uInt16 nPos;
        sal_Int32 nLast;
        ScMyDefaultStyleList* pDefaults;
        if (bRow)
        {
            pDefaults = pRowDefaults;
            nLast = nLastRow;
        }
        else
        {
            pDefaults = pColDefaults;
            nLast = nLastCol;
        }
        sal_Bool bPrevAutoStyle;
        sal_Bool bIsAutoStyle;
        sal_Bool bResult;
        sal_Int32 nPrevIndex(0);
        sal_Int32 nIndex;
        sal_Int32 nRepeat(0);
        sal_Int32 nEmptyRepeat(0);
        for (sal_Int32 i = nLast; i >= 0; i--)
        {
            if (bRow)
                bResult = FALSE;
            else
                bResult = pDoc->GetColDefault(nTable,
                    static_cast<sal_uInt16>(i), static_cast<sal_uInt16>(nLastRow), nPos);
            if (bResult)
            {
                nEmptyRepeat = 0;
                if (!nRepeat)
                {
                    nPrevIndex = GetStyleNameIndex(pCellStyles, nTable, static_cast<sal_Int32>(nPos), i,
                                                bRow, bPrevAutoStyle);
                    (*pDefaults)[i].nIndex = nPrevIndex;
                    (*pDefaults)[i].bIsAutoStyle = bPrevAutoStyle;
                    nRepeat = 1;
                }
                else
                {
                    nIndex = GetStyleNameIndex(pCellStyles, nTable, static_cast<sal_Int32>(nPos), i,
                                            bRow, bIsAutoStyle);
                    if ((nIndex != nPrevIndex) || (bIsAutoStyle != bPrevAutoStyle))
                    {
                        nRepeat = 1;
                        nPrevIndex = GetStyleNameIndex(pCellStyles, nTable, static_cast<sal_Int32>(nPos), i,
                                                bRow, bPrevAutoStyle);
                        (*pDefaults)[i].nIndex = nPrevIndex;
                        (*pDefaults)[i].bIsAutoStyle = bPrevAutoStyle;
                    }
                    else
                    {
                        (*pDefaults)[i].nIndex = nPrevIndex;
                        (*pDefaults)[i].bIsAutoStyle = bPrevAutoStyle;
                        nRepeat++;
                        if (nRepeat > 1)
                            (*pDefaults)[i].nRepeat = nRepeat;
                    }
                }
            }
            else
            {
                nRepeat = 0;
                if (!nEmptyRepeat)
                    nEmptyRepeat = 1;
                else
                {
                    nEmptyRepeat++;
                    if (nEmptyRepeat > 1)
                        (*pDefaults)[i].nRepeat = nEmptyRepeat;
                }
            }
        }
    }
}

void ScMyDefaultStyles::FillDefaultStyles(const sal_uInt16 nTable,
    const sal_Int32 nLastRow, const sal_Int32 nLastCol,
    const ScFormatRangeStyles* pCellStyles, ScDocument* pDoc)
{
    if (pRowDefaults)
        delete pRowDefaults;
    pRowDefaults = new ScMyDefaultStyleList(nLastRow + 1);
     FillDefaultStyles(nTable, nLastRow, nLastCol, pCellStyles, pDoc, sal_True);
    if (pColDefaults)
        delete pColDefaults;
    pColDefaults = new ScMyDefaultStyleList(nLastCol + 1);
     FillDefaultStyles(nTable, nLastRow, nLastCol, pCellStyles, pDoc, sal_False);
}

ScMyDefaultStyles::~ScMyDefaultStyles()
{
    if (pRowDefaults)
        delete pRowDefaults;
    if (pColDefaults)
        delete pColDefaults;
}

ScMyRowFormatRange::ScMyRowFormatRange()
    : nStartColumn(0),
    nRepeatColumns(0),
    nRepeatRows(0),
    nIndex(-1),
    nValidationIndex(-1),
    bIsAutoStyle(sal_True)
{
}

sal_Bool ScMyRowFormatRange::operator< (const ScMyRowFormatRange& rRange) const
{
    return (nStartColumn < rRange.nStartColumn);
}

ScRowFormatRanges::ScRowFormatRanges()
    : aRowFormatRanges()
    , pRowDefaults(NULL)
    , pColDefaults(NULL)
    , nSize(0)
{
}

ScRowFormatRanges::ScRowFormatRanges(const ScRowFormatRanges* pRanges)
    : aRowFormatRanges(pRanges->aRowFormatRanges)
    , pRowDefaults(pRanges->pRowDefaults)
    , pColDefaults(pRanges->pColDefaults)
    , nSize(pRanges->nSize)
{
}

ScRowFormatRanges::~ScRowFormatRanges()
{
}

void ScRowFormatRanges::Clear()
{
    aRowFormatRanges.clear();
    nSize = 0;
}

void ScRowFormatRanges::AddRange(const sal_Int32 nPrevStartCol, const sal_Int32 nRepeat, const sal_Int32 nPrevIndex,
    const sal_Bool bPrevAutoStyle, const ScMyRowFormatRange& rFormatRange)
{
    sal_Int32 nIndex(-1);
    if ((nPrevIndex != rFormatRange.nIndex) ||
        (bPrevAutoStyle != rFormatRange.bIsAutoStyle))
        nIndex = rFormatRange.nIndex;

    sal_Bool bInserted(sal_False);
    if (!aRowFormatRanges.empty())
    {
        ScMyRowFormatRange* pRange = &aRowFormatRanges.back();
        if (pRange)
        {
            if ((nPrevStartCol == (pRange->nStartColumn + pRange->nRepeatColumns)) &&
                (pRange->bIsAutoStyle == rFormatRange.bIsAutoStyle) &&
                (pRange->nIndex == nIndex) &&
                (pRange->nValidationIndex == rFormatRange.nValidationIndex))
            {
                if (rFormatRange.nRepeatRows < pRange->nRepeatRows)
                    pRange->nRepeatRows = rFormatRange.nRepeatRows;
                pRange->nRepeatColumns += nRepeat;
                bInserted = sal_True;
            }
        }
    }
    if (!bInserted)
    {
        ScMyRowFormatRange aRange;
        aRange.nStartColumn = nPrevStartCol;
        aRange.nRepeatColumns = nRepeat;
        aRange.nRepeatRows = rFormatRange.nRepeatRows;
        aRange.nValidationIndex = rFormatRange.nValidationIndex;
        aRange.bIsAutoStyle = rFormatRange.bIsAutoStyle;
        aRange.nIndex = nIndex;
        aRowFormatRanges.push_back(aRange);
        nSize++;
    }
}

void ScRowFormatRanges::AddRange(ScMyRowFormatRange& rFormatRange,
    const sal_Int32 nRow)
{
    DBG_ASSERT(pRowDefaults, "no row defaults");
    DBG_ASSERT(pColDefaults, "no column defaults");
    sal_uInt32 nEnd (rFormatRange.nRepeatRows + nRow - 1);
    sal_Int32 nPrevIndex((*pRowDefaults)[nRow].nIndex);
    sal_Bool bPrevAutoStyle((*pRowDefaults)[nRow].bIsAutoStyle);
    sal_uInt32 i(nRow + 1);
    sal_Bool bReady(sal_False);
    while ((i < nEnd) && !bReady && (i < pRowDefaults->size()))
    {
        if ((nPrevIndex != (*pRowDefaults)[i].nIndex) ||
            (bPrevAutoStyle != (*pRowDefaults)[i].bIsAutoStyle))
            bReady = sal_True;
        else
            i += (*pRowDefaults)[i].nRepeat;
    }
    if (i > nEnd)
        i = nEnd;
    if (bReady)
        rFormatRange.nRepeatRows = i - nRow + 1;
    if (nPrevIndex == -1)
    {
        nPrevIndex = (*pColDefaults)[rFormatRange.nStartColumn].nIndex;
        bPrevAutoStyle = (*pColDefaults)[rFormatRange.nStartColumn].bIsAutoStyle;
        sal_uInt32 nPrevStartCol(rFormatRange.nStartColumn);
        sal_uInt32 nRepeat((*pColDefaults)[rFormatRange.nStartColumn].nRepeat);
        nEnd = rFormatRange.nStartColumn + rFormatRange.nRepeatColumns;
        for(i = nPrevStartCol + nRepeat; i < nEnd; i += (*pColDefaults)[i].nRepeat)
        {
            DBG_ASSERT(sal_uInt32(nPrevStartCol + nRepeat) <= nEnd, "something wents wrong");
            if ((nPrevIndex != (*pColDefaults)[i].nIndex) ||
                (bPrevAutoStyle != (*pColDefaults)[i].bIsAutoStyle))
            {
                AddRange(nPrevStartCol, nRepeat, nPrevIndex, bPrevAutoStyle, rFormatRange);
                nPrevStartCol = i;
                nRepeat = (*pColDefaults)[i].nRepeat;
                nPrevIndex = (*pColDefaults)[i].nIndex;
                bPrevAutoStyle = (*pColDefaults)[i].bIsAutoStyle;
            }
            else
                nRepeat += (*pColDefaults)[i].nRepeat;
        }
        if (sal_uInt32(nPrevStartCol + nRepeat) > nEnd)
            nRepeat = nEnd - nPrevStartCol;
        AddRange(nPrevStartCol, nRepeat, nPrevIndex, bPrevAutoStyle, rFormatRange);
    }
    else if ((nPrevIndex == rFormatRange.nIndex) &&
        (bPrevAutoStyle == rFormatRange.bIsAutoStyle))
    {
        rFormatRange.nIndex = -1;
        aRowFormatRanges.push_back(rFormatRange);
        nSize++;
    }
}

sal_Bool ScRowFormatRanges::GetNext(ScMyRowFormatRange& aFormatRange)
{
    ScMyRowFormatRangesList::iterator aItr = aRowFormatRanges.begin();
    if (aItr != aRowFormatRanges.end())
    {
        aFormatRange = (*aItr);
        aRowFormatRanges.erase(aItr);
        nSize--;
        return sal_True;
    }
    return sal_False;
}

sal_Int32 ScRowFormatRanges::GetMaxRows()
{
    ScMyRowFormatRangesList::iterator aItr = aRowFormatRanges.begin();
    sal_Int32 nMaxRows = MAXROW + 1;
    if (aItr != aRowFormatRanges.end())
        while (aItr != aRowFormatRanges.end())
        {
            if ((*aItr).nRepeatRows < nMaxRows)
                nMaxRows = (*aItr).nRepeatRows;
            ++aItr;
        }
    else
        OSL_FAIL("no ranges found");
    return nMaxRows;
}

sal_Int32 ScRowFormatRanges::GetSize()
{
    return nSize;
}

void ScRowFormatRanges::Sort()
{
    aRowFormatRanges.sort();
}

// ============================================================================
ScMyFormatRange::ScMyFormatRange()
    : nStyleNameIndex(-1),
    nValidationIndex(-1),
    bIsAutoStyle(sal_True)
{
}

sal_Bool ScMyFormatRange::operator<(const ScMyFormatRange& rRange) const
{
    if (aRangeAddress.StartRow < rRange.aRangeAddress.StartRow)
        return sal_True;
    else
        if (aRangeAddress.StartRow == rRange.aRangeAddress.StartRow)
            return (aRangeAddress.StartColumn < rRange.aRangeAddress.StartColumn);
        else
            return sal_False;
}

ScFormatRangeStyles::ScFormatRangeStyles()
    : aTables(),
    aStyleNames(),
    aAutoStyleNames()
{
}

ScFormatRangeStyles::~ScFormatRangeStyles()
{
    ScMyOUStringVec::iterator i = aStyleNames.begin();
    while (i != aStyleNames.end())
    {
        delete *i;
        ++i;
    }
    i = aAutoStyleNames.begin();
    while (i != aAutoStyleNames.end())
    {
        delete *i;
        ++i;
    }
    ScMyFormatRangeListVec::iterator j = aTables.begin();
    while (j != aTables.end())
    {
        delete *j;
        ++j;
    }
}

void ScFormatRangeStyles::AddNewTable(const sal_Int16 nTable)
{
    sal_Int16 nSize = aTables.size() - 1;
    if (nTable > nSize)
        for (sal_Int16 i = nSize; i < nTable; i++)
        {
            ScMyFormatRangeAddresses* aRangeAddresses = new ScMyFormatRangeAddresses;
            aTables.push_back(aRangeAddresses);
        }
}

sal_Bool ScFormatRangeStyles::AddStyleName(::rtl::OUString* rpString, sal_Int32& rIndex, const sal_Bool bIsAutoStyle)
{
    if (bIsAutoStyle)
    {
        aAutoStyleNames.push_back(rpString);
        rIndex = aAutoStyleNames.size() - 1;
        return sal_True;
    }
    else
    {
        sal_Int32 nCount = aStyleNames.size();
        sal_Bool bFound(sal_False);
        sal_Int32 i = nCount - 1;
        while ((i >= 0) && (!bFound))
        {
            if (aStyleNames.at(i)->equals(*rpString))
                bFound = sal_True;
            else
                i--;
        }
        if (bFound)
        {
            rIndex = i;
            return sal_False;
        }
        else
        {
            aStyleNames.push_back(rpString);
            rIndex = aStyleNames.size() - 1;
            return sal_True;
        }
    }
}

sal_Int32 ScFormatRangeStyles::GetIndexOfStyleName(const ::rtl::OUString& rString, const ::rtl::OUString& rPrefix, sal_Bool& bIsAutoStyle)
{
    sal_Int32 nPrefixLength = rPrefix.getLength();
    ::rtl::OUString sTemp = rString.copy(nPrefixLength);
    sal_Int32 nIndex = sTemp.toInt32();
    if (aAutoStyleNames.at(nIndex - 1)->equals(rString))
    {
        bIsAutoStyle = sal_True;
        return nIndex - 1;
    }
    else
    {
        sal_Int32 i = 0;
        sal_Bool bFound(sal_False);
        while (!bFound && static_cast<sal_uInt32>(i) < aStyleNames.size())
        {
            if (aStyleNames[i]->equals(rString))
                bFound = sal_True;
            else
                i++;
        }
        if (bFound)
        {
            bIsAutoStyle = sal_False;
            return i;
        }
        else
        {
            i = 0;
            while (!bFound && static_cast<sal_uInt32>(i) < aAutoStyleNames.size())
            {
                if (aAutoStyleNames[i]->equals(rString))
                    bFound = sal_True;
                else
                    i++;
            }
            if (bFound)
            {
                bIsAutoStyle = sal_True;
                return i;
            }
            else
                return -1;
        }
    }
}

sal_Int32 ScFormatRangeStyles::GetStyleNameIndex(const sal_uInt16 nTable,
    const sal_Int32 nColumn, const sal_Int32 nRow, sal_Bool& bIsAutoStyle) const
{
    DBG_ASSERT(static_cast<sal_uInt32>(nTable) < aTables.size(), "wrong table");
    ScMyFormatRangeAddresses* pFormatRanges = aTables[nTable];
    ScMyFormatRangeAddresses::iterator aItr = pFormatRanges->begin();
    while (aItr != pFormatRanges->end())
    {
        if (((*aItr).aRangeAddress.StartColumn <= nColumn) &&
            ((*aItr).aRangeAddress.EndColumn >= nColumn) &&
            ((*aItr).aRangeAddress.StartRow <= nRow) &&
            ((*aItr).aRangeAddress.EndRow >= nRow))
        {
            bIsAutoStyle = aItr->bIsAutoStyle;
            return (*aItr).nStyleNameIndex;
        }
        else
            ++aItr;
    }
    return -1;
}

sal_Int32 ScFormatRangeStyles::GetStyleNameIndex(const sal_uInt16 nTable, const sal_Int32 nColumn, const sal_Int32 nRow,
    sal_Bool& bIsAutoStyle, sal_Int32& nValidationIndex, sal_Int32& nNumberFormat, const sal_Bool bRemoveRange)
{
    DBG_ASSERT(static_cast<sal_uInt32>(nTable) < aTables.size(), "wrong table");
    ScMyFormatRangeAddresses* pFormatRanges = aTables[nTable];
    ScMyFormatRangeAddresses::iterator aItr = pFormatRanges->begin();
    while (aItr != pFormatRanges->end())
    {
        if (((*aItr).aRangeAddress.StartColumn <= nColumn) &&
            ((*aItr).aRangeAddress.EndColumn >= nColumn) &&
            ((*aItr).aRangeAddress.StartRow <= nRow) &&
            ((*aItr).aRangeAddress.EndRow >= nRow))
        {
            bIsAutoStyle = aItr->bIsAutoStyle;
            nValidationIndex = aItr->nValidationIndex;
            nNumberFormat = aItr->nNumberFormat;
            if (((*pRowDefaults)[nRow].nIndex != -1))
            {
                if (((*pRowDefaults)[nRow].nIndex == (*aItr).nStyleNameIndex) &&
                    ((*pRowDefaults)[nRow].bIsAutoStyle == (*aItr).bIsAutoStyle))
                    return -1;
                else
                    return (*aItr).nStyleNameIndex;
            }
            else if (((*pColDefaults)[nColumn].nIndex != -1) &&
                ((*pColDefaults)[nColumn].nIndex == (*aItr).nStyleNameIndex) &&
                ((*pColDefaults)[nColumn].bIsAutoStyle == (*aItr).bIsAutoStyle))
                return -1;
            else
                return (*aItr).nStyleNameIndex;
        }
        else
        {
            if (bRemoveRange && (*aItr).aRangeAddress.EndRow < nRow)
                aItr = pFormatRanges->erase(aItr);
            else
                ++aItr;
        }
    }
    return -1;
}

void ScFormatRangeStyles::GetFormatRanges(const sal_Int32 nStartColumn, const sal_Int32 nEndColumn, const sal_Int32 nRow,
                    const sal_Int16 nTable, ScRowFormatRanges* pRowFormatRanges)
{
    sal_Int32 nTotalColumns = nEndColumn - nStartColumn + 1;
    DBG_ASSERT(static_cast<sal_uInt32>(nTable) < aTables.size(), "wrong table");
    ScMyFormatRangeAddresses* pFormatRanges = aTables[nTable];
    ScMyFormatRangeAddresses::iterator aItr = pFormatRanges->begin();
    sal_Int32 nColumns = 0;
    while (aItr != pFormatRanges->end() && nColumns < nTotalColumns)
    {
        if (((*aItr).aRangeAddress.StartRow <= nRow) &&
            ((*aItr).aRangeAddress.EndRow >= nRow))
        {
            if ((((*aItr).aRangeAddress.StartColumn <= nStartColumn) &&
                ((*aItr).aRangeAddress.EndColumn >= nStartColumn)) ||
                (((*aItr).aRangeAddress.StartColumn <= nEndColumn) &&
                ((*aItr).aRangeAddress.EndColumn >= nEndColumn)) ||
                (((*aItr).aRangeAddress.StartColumn >= nStartColumn) &&
                ((*aItr).aRangeAddress.EndColumn <= nEndColumn)))
            {
                ScMyRowFormatRange aRange;
                aRange.nIndex = aItr->nStyleNameIndex;
                aRange.nValidationIndex = aItr->nValidationIndex;
                aRange.bIsAutoStyle = aItr->bIsAutoStyle;
                if ((aItr->aRangeAddress.StartColumn < nStartColumn) &&
                    (aItr->aRangeAddress.EndColumn >= nStartColumn))
                {
                    if (aItr->aRangeAddress.EndColumn >= nEndColumn)
                        aRange.nRepeatColumns = nTotalColumns;
                    else
                        aRange.nRepeatColumns = aItr->aRangeAddress.EndColumn - nStartColumn + 1;
                    aRange.nStartColumn = nStartColumn;
                }
                else if ((aItr->aRangeAddress.StartColumn >= nStartColumn) &&
                    (aItr->aRangeAddress.EndColumn <= nEndColumn))
                {
                    aRange.nRepeatColumns = aItr->aRangeAddress.EndColumn - aItr->aRangeAddress.StartColumn + 1;
                    aRange.nStartColumn = aItr->aRangeAddress.StartColumn;
                }
                else if ((aItr->aRangeAddress.StartColumn >= nStartColumn) &&
                    (aItr->aRangeAddress.StartColumn <= nEndColumn) &&
                    (aItr->aRangeAddress.EndColumn > nEndColumn))
                {
                    aRange.nRepeatColumns = nEndColumn - aItr->aRangeAddress.StartColumn + 1;
                    aRange.nStartColumn = aItr->aRangeAddress.StartColumn;
                }
                aRange.nRepeatRows = aItr->aRangeAddress.EndRow - nRow + 1;
                pRowFormatRanges->AddRange(aRange, nRow);
                nColumns += aRange.nRepeatColumns;
            }
            ++aItr;
        }
        else
        {
            if(aItr->aRangeAddress.EndRow < nRow)
                aItr = pFormatRanges->erase(aItr);
            else
                ++aItr;
        }
    }
    pRowFormatRanges->Sort();
}

void ScFormatRangeStyles::AddRangeStyleName(const table::CellRangeAddress aCellRangeAddress,
    const sal_Int32 nStringIndex, const sal_Bool bIsAutoStyle, const sal_Int32 nValidationIndex,
    const sal_Int32 nNumberFormat)
{
    ScMyFormatRange aFormatRange;
    aFormatRange.aRangeAddress = aCellRangeAddress;
    aFormatRange.nStyleNameIndex = nStringIndex;
    aFormatRange.nValidationIndex = nValidationIndex;
    aFormatRange.nNumberFormat = nNumberFormat;
    aFormatRange.bIsAutoStyle = bIsAutoStyle;
    DBG_ASSERT(static_cast<sal_uInt32>(aCellRangeAddress.Sheet) < aTables.size(), "wrong table");
    ScMyFormatRangeAddresses* pFormatRanges = aTables[aCellRangeAddress.Sheet];
    pFormatRanges->push_back(aFormatRange);
}

rtl::OUString* ScFormatRangeStyles::GetStyleNameByIndex(const sal_Int32 nIndex, const sal_Bool bIsAutoStyle)
{
    if (bIsAutoStyle)
        return aAutoStyleNames[nIndex];
    else
        return aStyleNames[nIndex];
}

void ScFormatRangeStyles::Sort()
{
    sal_Int16 nTables = aTables.size();
    for (sal_Int16 i = 0; i < nTables; i++)
        if (!aTables[i]->empty())
            aTables[i]->sort();
}

//===========================================================================

ScColumnRowStylesBase::ScColumnRowStylesBase()
    : aStyleNames()
{
}

ScColumnRowStylesBase::~ScColumnRowStylesBase()
{
    ScMyOUStringVec::iterator i = aStyleNames.begin();
    while (i != aStyleNames.end())
    {
        delete *i;
        ++i;
    }
}

sal_Int32 ScColumnRowStylesBase::AddStyleName(::rtl::OUString* pString)
{
    aStyleNames.push_back(pString);
    return aStyleNames.size() - 1;
}

sal_Int32 ScColumnRowStylesBase::GetIndexOfStyleName(const ::rtl::OUString& rString, const ::rtl::OUString& rPrefix)
{
    sal_Int32 nPrefixLength = rPrefix.getLength();
    ::rtl::OUString sTemp = rString.copy(nPrefixLength);
    sal_Int32 nIndex = sTemp.toInt32();
    if (aStyleNames.at(nIndex - 1)->equals(rString))
        return nIndex - 1;
    else
    {
        sal_Int32 i = 0;
        sal_Bool bFound(sal_False);
        while (!bFound && static_cast<sal_uInt32>(i) < aStyleNames.size())
        {
            if (aStyleNames.at(i)->equals(rString))
                bFound = sal_True;
            else
                i++;
        }
        if (bFound)
            return i;
        else
            return -1;
    }
}

rtl::OUString* ScColumnRowStylesBase::GetStyleNameByIndex(const sal_Int32 nIndex)
{
    if ( nIndex < 0 || nIndex >= (sal_Int32)aStyleNames.size() )
    {
        // #i61888# should no longer happen, use first style then
        DBG_ERRORFILE("GetStyleNameByIndex: invalid index");
        return aStyleNames[0];
    }

    return aStyleNames[nIndex];
}

//===========================================================================

ScColumnStyles::ScColumnStyles()
    : ScColumnRowStylesBase(),
    aTables()
{
}

ScColumnStyles::~ScColumnStyles()
{
}

void ScColumnStyles::AddNewTable(const sal_Int16 nTable, const sal_Int32 nFields)
{
    sal_Int16 nSize = aTables.size() - 1;
    if (nTable > nSize)
        for (sal_Int32 i = nSize; i < nTable; i++)
        {
            ScMyColumnStyleVec aFieldsVec(nFields + 1, ScColumnStyle());
            aTables.push_back(aFieldsVec);
        }
}

sal_Int32 ScColumnStyles::GetStyleNameIndex(const sal_Int16 nTable, const sal_Int32 nField,
    sal_Bool& bIsVisible)
{
    DBG_ASSERT(static_cast<sal_uInt32>(nTable) < aTables.size(), "wrong table");
    if (static_cast<sal_uInt32>(nField) < aTables[nTable].size())
    {
        bIsVisible = aTables[nTable][nField].bIsVisible;
        return aTables[nTable][nField].nIndex;
    }
    else
    {
        bIsVisible = aTables[nTable][aTables[nTable].size() - 1].bIsVisible;
        return aTables[nTable][aTables[nTable].size() - 1].nIndex;
    }
}

void ScColumnStyles::AddFieldStyleName(const sal_Int16 nTable, const sal_Int32 nField,
    const sal_Int32 nStringIndex, const sal_Bool bIsVisible)
{
    DBG_ASSERT(static_cast<sal_uInt32>(nTable) < aTables.size(), "wrong table");
    DBG_ASSERT(aTables[nTable].size() >= static_cast<sal_uInt32>(nField), "wrong field");
    ScColumnStyle aStyle;
    aStyle.nIndex = nStringIndex;
    aStyle.bIsVisible = bIsVisible;
    if (aTables[nTable].size() == static_cast<sal_uInt32>(nField))
        aTables[nTable].push_back(aStyle);
    aTables[nTable][nField] = aStyle;
}

rtl::OUString* ScColumnStyles::GetStyleName(const sal_Int16 nTable, const sal_Int32 nField)
{
    sal_Bool bTemp;
    return GetStyleNameByIndex(GetStyleNameIndex(nTable, nField, bTemp));
}

//===========================================================================

ScRowStyles::ScRowStyles()
    : ScColumnRowStylesBase(),
    aTables()
{
}

ScRowStyles::~ScRowStyles()
{
}

void ScRowStyles::AddNewTable(const sal_Int16 nTable, const sal_Int32 nFields)
{
    sal_Int16 nSize = aTables.size() - 1;
    if (nTable > nSize)
        for (sal_Int32 i = nSize; i < nTable; i++)
        {
            ScMysalInt32Vec aFieldsVec(nFields + 1, -1);
            aTables.push_back(aFieldsVec);
        }
}

sal_Int32 ScRowStyles::GetStyleNameIndex(const sal_Int16 nTable, const sal_Int32 nField)
{
    DBG_ASSERT(static_cast<sal_uInt32>(nTable) < aTables.size(), "wrong table");
    if (static_cast<sal_uInt32>(nField) < aTables[nTable].size())
        return aTables[nTable][nField];
    else
        return aTables[nTable][aTables[nTable].size() - 1];
}

void ScRowStyles::AddFieldStyleName(const sal_Int16 nTable, const sal_Int32 nField,
    const sal_Int32 nStringIndex)
{
    DBG_ASSERT(static_cast<sal_uInt32>(nTable) < aTables.size(), "wrong table");
    DBG_ASSERT(aTables[nTable].size() >= static_cast<sal_uInt32>(nField), "wrong field");
    if (aTables[nTable].size() == static_cast<sal_uInt32>(nField))
        aTables[nTable].push_back(nStringIndex);
    aTables[nTable][nField] = nStringIndex;
}

rtl::OUString* ScRowStyles::GetStyleName(const sal_Int16 nTable, const sal_Int32 nField)
{
    return GetStyleNameByIndex(GetStyleNameIndex(nTable, nField));
}
}

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