/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   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 .
 */

#include "xmlfilti.hxx"
#include "xmlimprt.hxx"
#include "xmldrani.hxx"
#include "xmldpimp.hxx"
#include <rangeutl.hxx>
#include <queryentry.hxx>
#include <document.hxx>

#include <o3tl/safeint.hxx>
#include <sax/tools/converter.hxx>
#include <svl/sharedstringpool.hxx>
#include <xmloff/xmltoken.hxx>
#include <xmloff/xmlnamespace.hxx>

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

using ::com::sun::star::uno::Reference;

ScXMLFilterContext::ConnStackItem::ConnStackItem(bool bOr) : mbOr(bOr), mnCondCount(0) {}

ScXMLFilterContext::ScXMLFilterContext( ScXMLImport& rImport,
                                        const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList,
                                        ScQueryParam& rParam,
                                        ScXMLDatabaseRangeContext* pTempDatabaseRangeContext) :
    ScXMLImportContext( rImport ),
    mrQueryParam(rParam),
    pDatabaseRangeContext(pTempDatabaseRangeContext),
    bSkipDuplicates(false),
    bCopyOutputData(false),
    bConditionSourceRange(false)
{
    ScDocument* pDoc(GetScImport().GetDocument());
    assert(pDoc);

    if ( !rAttrList.is() )
        return;

    for (auto &aIter : *rAttrList)
    {
        switch (aIter.getToken())
        {
            case XML_ELEMENT( TABLE, XML_TARGET_RANGE_ADDRESS ):
            {
                ScRange aScRange;
                sal_Int32 nOffset(0);
                if (ScRangeStringConverter::GetRangeFromString( aScRange, aIter.toString(), *pDoc, ::formula::FormulaGrammar::CONV_OOO, nOffset ))
                {
                    aOutputPosition = aScRange.aStart;
                    bCopyOutputData = true;
                }
            }
            break;
            case XML_ELEMENT( TABLE, XML_CONDITION_SOURCE_RANGE_ADDRESS ):
            {
                sal_Int32 nOffset(0);
                if (ScRangeStringConverter::GetRangeFromString( aConditionSourceRangeAddress, aIter.toString(), *pDoc, ::formula::FormulaGrammar::CONV_OOO, nOffset ) )
                    bConditionSourceRange = true;
            }
            break;
            case XML_ELEMENT( TABLE, XML_CONDITION_SOURCE ):
            {
                // not supported by StarOffice
            }
            break;
            case XML_ELEMENT( TABLE, XML_DISPLAY_DUPLICATES ):
            {
                bSkipDuplicates = !IsXMLToken(aIter, XML_TRUE);
            }
            break;
        }
    }
}

ScXMLFilterContext::~ScXMLFilterContext()
{
}

uno::Reference< xml::sax::XFastContextHandler > SAL_CALL ScXMLFilterContext::createFastChildContext(
    sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& xAttrList )
{
    SvXMLImportContext *pContext(nullptr);
    sax_fastparser::FastAttributeList *pAttribList =
        &sax_fastparser::castToFastAttributeList( xAttrList );

    switch (nElement)
    {
        case XML_ELEMENT( TABLE, XML_FILTER_AND ):
        {
            pContext = new ScXMLAndContext(
                GetScImport(), mrQueryParam, this);
        }
        break;
        case XML_ELEMENT( TABLE, XML_FILTER_OR ):
        {
            pContext = new ScXMLOrContext(
                GetScImport(), mrQueryParam, this);
        }
        break;
        case XML_ELEMENT( TABLE, XML_FILTER_CONDITION ):
        {
            pContext = new ScXMLConditionContext(
                GetScImport(), nElement, pAttribList, mrQueryParam, this);
        }
        break;
    }

    return pContext;
}

void SAL_CALL ScXMLFilterContext::endFastElement( sal_Int32 /*nElement*/ )
{
    mrQueryParam.bInplace = !bCopyOutputData;
    mrQueryParam.bDuplicate = !bSkipDuplicates;

    if (bCopyOutputData)
    {
        mrQueryParam.nDestCol = aOutputPosition.Col();
        mrQueryParam.nDestRow = aOutputPosition.Row();
        mrQueryParam.nDestTab = aOutputPosition.Tab();
    }

    if (bConditionSourceRange)
        pDatabaseRangeContext->SetFilterConditionSourceRangeAddress(aConditionSourceRangeAddress);
}

void ScXMLFilterContext::OpenConnection(bool b)
{
    maConnStack.emplace_back(b);
}

void ScXMLFilterContext::CloseConnection()
{
    maConnStack.pop_back();
}

bool ScXMLFilterContext::GetConnection()
{
    // For condition items in each stack, the first one gets the connection of
    // the last stack, while the rest of them get that of the current stack.

    if (maConnStack.empty())
        // This should never happen.
        return true;

    ConnStackItem& rItem = maConnStack.back();
    if (rItem.mnCondCount)
        // secondary item gets the current connection.
        return rItem.mbOr;

    // The next condition of this stack will get the current connection.
    ++rItem.mnCondCount;

    if (maConnStack.size() < 2)
        // There is no last stack.  Likely the first condition in the first
        // stack whose connection is not used.  Default in
        // ScQueryEntry::eConnect is SC_AND, so return false (AND instead of
        // OR) here. Otherwise, when saving the document again, we'd write a
        // uselessly stacked
        // <table:filter-or><table:filter-and>...</table:filter-and></table:filter-or>
        // for two conditions connected with AND.
        return false;

    std::vector<ConnStackItem>::reverse_iterator itr = maConnStack.rbegin();
    ++itr;
    return itr->mbOr; // connection of the last stack.
}

ScXMLAndContext::ScXMLAndContext( ScXMLImport& rImport,
                                  ScQueryParam& rParam,
                                  ScXMLFilterContext* pTempFilterContext) :
    ScXMLImportContext( rImport ),
    mrQueryParam(rParam),
    pFilterContext(pTempFilterContext)
{
    pFilterContext->OpenConnection(false);
}

ScXMLAndContext::~ScXMLAndContext()
{
}

uno::Reference< xml::sax::XFastContextHandler > SAL_CALL ScXMLAndContext::createFastChildContext(
    sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& xAttrList )
{
    SvXMLImportContext *pContext(nullptr);
    sax_fastparser::FastAttributeList *pAttribList =
        &sax_fastparser::castToFastAttributeList( xAttrList );

    switch (nElement)
    {
        case XML_ELEMENT( TABLE, XML_FILTER_OR ):
        {
            // not supported in StarOffice
        }
        break;
        case XML_ELEMENT( TABLE, XML_FILTER_CONDITION ):
        {
            pContext = new ScXMLConditionContext(
                GetScImport(), nElement, pAttribList, mrQueryParam, pFilterContext);
        }
        break;
    }

    return pContext;
}

void SAL_CALL ScXMLAndContext::endFastElement( sal_Int32 /*nElement*/ )
{
    pFilterContext->CloseConnection();
}

ScXMLOrContext::ScXMLOrContext( ScXMLImport& rImport,
                                ScQueryParam& rParam,
                                ScXMLFilterContext* pTempFilterContext) :
    ScXMLImportContext( rImport ),
    mrQueryParam(rParam),
    pFilterContext(pTempFilterContext)
{
    pFilterContext->OpenConnection(true);
}

ScXMLOrContext::~ScXMLOrContext()
{
}

uno::Reference< xml::sax::XFastContextHandler > SAL_CALL ScXMLOrContext::createFastChildContext(
    sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& xAttrList )
{
    SvXMLImportContext *pContext(nullptr);
    sax_fastparser::FastAttributeList *pAttribList =
        &sax_fastparser::castToFastAttributeList( xAttrList );

    switch (nElement)
    {
        case XML_ELEMENT( TABLE, XML_FILTER_AND ):
        {
            pContext = new ScXMLAndContext(
                GetScImport(), mrQueryParam, pFilterContext);
        }
        break;
        case XML_ELEMENT( TABLE, XML_FILTER_CONDITION ):
        {
            pContext = new ScXMLConditionContext(
                GetScImport(), nElement, pAttribList, mrQueryParam, pFilterContext);
        }
        break;
    }

    return pContext;
}

void SAL_CALL ScXMLOrContext::endFastElement( sal_Int32 /*nElement*/ )
{
    pFilterContext->CloseConnection();
}

ScXMLConditionContext::ScXMLConditionContext(
    ScXMLImport& rImport, sal_Int32 /*nElement*/,
    const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList,
    ScQueryParam& rParam,
    ScXMLFilterContext* pTempFilterContext) :
    ScXMLImportContext( rImport ),
    mrQueryParam(rParam),
    pFilterContext(pTempFilterContext),
    sDataType(GetXMLToken(XML_TEXT)),
    nField(0),
    bIsCaseSensitive(false)
{

    if ( !rAttrList.is() )
        return;

    for (auto &aIter : *rAttrList)
    {
        switch (aIter.getToken())
        {
            case XML_ELEMENT( TABLE, XML_FIELD_NUMBER ):
            {
                nField = aIter.toInt32();
            }
            break;
            case XML_ELEMENT( TABLE, XML_CASE_SENSITIVE ):
            {
                bIsCaseSensitive = IsXMLToken(aIter, XML_TRUE);
            }
            break;
            case XML_ELEMENT( TABLE, XML_DATA_TYPE ):
            case XML_ELEMENT( LO_EXT, XML_DATA_TYPE ):
            {
                sDataType = aIter.toString();
            }
            break;
            case XML_ELEMENT( TABLE, XML_VALUE ):
            {
                sConditionValue = aIter.toString();
            }
            break;
            case XML_ELEMENT( TABLE, XML_OPERATOR ):
            {
                sOperator = aIter.toString();
            }
            break;
        }
    }
}

ScXMLConditionContext::~ScXMLConditionContext()
{
}

uno::Reference< xml::sax::XFastContextHandler > SAL_CALL ScXMLConditionContext::createFastChildContext(
    sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& xAttrList )
{
    SvXMLImportContext *pContext = nullptr;
    sax_fastparser::FastAttributeList *pAttribList =
        &sax_fastparser::castToFastAttributeList( xAttrList );

    switch (nElement)
    {
        case XML_ELEMENT( TABLE, XML_FILTER_SET_ITEM ):
        {
            pContext = new ScXMLSetItemContext(
                GetScImport(), nElement, pAttribList, *this);
        }
        break;
    }

    return pContext;
}

void ScXMLConditionContext::GetOperator(
    std::u16string_view aOpStr, ScQueryParam& rParam, ScQueryEntry& rEntry)
{
    rParam.eSearchType = utl::SearchParam::SearchType::Normal;
    if (IsXMLToken(aOpStr, XML_MATCH))
    {
        rParam.eSearchType = utl::SearchParam::SearchType::Regexp;
        rEntry.eOp = SC_EQUAL;
    }
    else if (IsXMLToken(aOpStr, XML_NOMATCH))
    {
        rParam.eSearchType = utl::SearchParam::SearchType::Regexp;
        rEntry.eOp = SC_NOT_EQUAL;
    }
    else if (aOpStr == u"=")
        rEntry.eOp = SC_EQUAL;
    else if (aOpStr == u"!=")
        rEntry.eOp = SC_NOT_EQUAL;
    else if (IsXMLToken(aOpStr, XML_BOTTOM_PERCENT))
        rEntry.eOp = SC_BOTPERC;
    else if (IsXMLToken(aOpStr, XML_BOTTOM_VALUES))
        rEntry.eOp = SC_BOTVAL;
    else if (IsXMLToken(aOpStr, XML_TOKEN_EMPTY))
        rEntry.SetQueryByEmpty();
    else if (aOpStr == u">")
        rEntry.eOp = SC_GREATER;
    else if (aOpStr == u">=")
        rEntry.eOp = SC_GREATER_EQUAL;
    else if (aOpStr == u"<")
        rEntry.eOp = SC_LESS;
    else if (aOpStr == u"<=")
        rEntry.eOp = SC_LESS_EQUAL;
    else if (IsXMLToken(aOpStr, XML_NOEMPTY))
        rEntry.SetQueryByNonEmpty();
    else if (IsXMLToken(aOpStr, XML_TOP_PERCENT))
        rEntry.eOp = SC_TOPPERC;
    else if (IsXMLToken(aOpStr, XML_TOP_VALUES))
        rEntry.eOp = SC_TOPVAL;
    else if (IsXMLToken(aOpStr, XML_CONTAINS))
        rEntry.eOp = SC_CONTAINS;
    else if (IsXMLToken(aOpStr, XML_DOES_NOT_CONTAIN))
        rEntry.eOp = SC_DOES_NOT_CONTAIN;
    else if (IsXMLToken(aOpStr, XML_BEGINS_WITH))
        rEntry.eOp = SC_BEGINS_WITH;
    else if (IsXMLToken(aOpStr, XML_DOES_NOT_BEGIN_WITH))
        rEntry.eOp = SC_DOES_NOT_BEGIN_WITH;
    else if (IsXMLToken(aOpStr, XML_ENDS_WITH))
        rEntry.eOp = SC_ENDS_WITH;
    else if (IsXMLToken(aOpStr, XML_DOES_NOT_END_WITH))
        rEntry.eOp = SC_DOES_NOT_END_WITH;
}

void ScXMLConditionContext::AddSetItem(const ScQueryEntry::Item& rItem)
{
    maQueryItems.push_back(rItem);
}

void SAL_CALL ScXMLConditionContext::endFastElement( sal_Int32 /*nElement*/ )
{
    ScQueryEntry& rEntry = mrQueryParam.AppendEntry();

    // We currently don't support per-condition case sensitivity.
    mrQueryParam.bCaseSens = bIsCaseSensitive;

    rEntry.bDoQuery = true;
    rEntry.eConnect = pFilterContext->GetConnection() ? SC_OR : SC_AND;

    GetOperator(sOperator, mrQueryParam, rEntry);
    SCCOLROW nStartPos = mrQueryParam.bByRow ? mrQueryParam.nCol1 : mrQueryParam.nRow1;
    rEntry.nField = o3tl::saturating_add(nField, nStartPos);

    if (maQueryItems.empty())
    {
        ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
        if (IsXMLToken(sOperator, XML_TOKEN_EMPTY))
            return;
        if (IsXMLToken(sDataType, XML_NUMBER))
        {
            rItem.mfVal = sConditionValue.toDouble();
            rItem.meType = ScQueryEntry::ByValue;
        }
        else if (IsXMLToken(sDataType, XML_TEXT_COLOR)
                 || IsXMLToken(sDataType, XML_BACKGROUND_COLOR))
        {
            rItem.meType = IsXMLToken(sDataType, XML_TEXT_COLOR) ? ScQueryEntry::ByTextColor
                                                                 : ScQueryEntry::ByBackgroundColor;
            if (IsXMLToken(sConditionValue, XML_TRANSPARENT)
                || IsXMLToken(sConditionValue, XML_WINDOW_FONT_COLOR))
                rItem.maColor = COL_AUTO;
            else
                sax::Converter::convertColor(rItem.maColor, sConditionValue);
        }
        else
        {
            svl::SharedStringPool& rPool = GetScImport().GetDocument()->GetSharedStringPool();
            rItem.maString = rPool.intern(sConditionValue);
            rItem.meType = ScQueryEntry::ByString;
        }
    }
    else
        rEntry.GetQueryItems().swap(maQueryItems);
}

ScXMLSetItemContext::ScXMLSetItemContext(
    ScXMLImport& rImport, sal_Int32 /*nElement*/,
    const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList, ScXMLConditionContext& rParent) :
    ScXMLImportContext(rImport)
{
    if ( !rAttrList.is() )
        return;

    for (auto &aIter : *rAttrList)
    {
        switch (aIter.getToken())
        {
            case XML_ELEMENT( TABLE, XML_VALUE ):
            {
                svl::SharedStringPool& rPool = GetScImport().GetDocument()->GetSharedStringPool();
                ScQueryEntry::Item aItem;
                aItem.maString = rPool.intern(aIter.toString());
                aItem.meType = ScQueryEntry::ByString;
                aItem.mfVal = 0.0;
                rParent.AddSetItem(aItem);
            }
            break;
        }
    }
}

ScXMLSetItemContext::~ScXMLSetItemContext()
{
}

ScXMLDPFilterContext::ScXMLDPFilterContext( ScXMLImport& rImport,
                                      const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList,
                                      ScXMLDataPilotTableContext* pTempDataPilotTableContext) :
    ScXMLImportContext( rImport ),
    pDataPilotTable(pTempDataPilotTableContext),
    eSearchType(utl::SearchParam::SearchType::Normal),
    nFilterFieldCount(0),
    bSkipDuplicates(false),
    bIsCaseSensitive(false),
    bConnectionOr(true),
    bNextConnectionOr(true)
{
    if ( !rAttrList.is() )
        return;

    for (auto &aIter : *rAttrList)
    {
        switch (aIter.getToken())
        {
            case XML_ELEMENT( TABLE, XML_TARGET_RANGE_ADDRESS ):
            {
                // not supported
            }
            break;
            case XML_ELEMENT( TABLE, XML_CONDITION_SOURCE_RANGE_ADDRESS ):
            {
                // not supported
            }
            break;
            case XML_ELEMENT( TABLE, XML_CONDITION_SOURCE ):
            {
                // not supported by StarOffice
            }
            break;
            case XML_ELEMENT( TABLE, XML_DISPLAY_DUPLICATES ):
            {
                bSkipDuplicates = !IsXMLToken(aIter, XML_TRUE);
            }
            break;
            }
    }
}

ScXMLDPFilterContext::~ScXMLDPFilterContext()
{
}

uno::Reference< xml::sax::XFastContextHandler > SAL_CALL ScXMLDPFilterContext::createFastChildContext(
    sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& xAttrList )
{
    SvXMLImportContext *pContext(nullptr);
    sax_fastparser::FastAttributeList *pAttribList =
        &sax_fastparser::castToFastAttributeList( xAttrList );

    switch (nElement)
    {
        case XML_ELEMENT( TABLE, XML_FILTER_AND ):
        {
            pContext = new ScXMLDPAndContext( GetScImport(), this);
        }
        break;
        case XML_ELEMENT( TABLE, XML_FILTER_OR ):
        {
            pContext = new ScXMLDPOrContext( GetScImport(), this);
        }
        break;
        case XML_ELEMENT( TABLE, XML_FILTER_CONDITION ):
        {
            pContext = new ScXMLDPConditionContext( GetScImport(), nElement, pAttribList, this);
        }
        break;
    }

    return pContext;
}

void SAL_CALL ScXMLDPFilterContext::endFastElement( sal_Int32 /*nElement*/ )
{
    aFilterFields.eSearchType = eSearchType;
    aFilterFields.bCaseSens = bIsCaseSensitive;
    aFilterFields.bDuplicate = !bSkipDuplicates;

    pDataPilotTable->SetSourceQueryParam(aFilterFields);
}

void ScXMLDPFilterContext::AddFilterField (const ScQueryEntry& aFilterField)
{
    aFilterFields.Resize(nFilterFieldCount + 1);
    ScQueryEntry& rEntry(aFilterFields.GetEntry(nFilterFieldCount));
    rEntry = aFilterField;
    rEntry.bDoQuery = true;
    ++nFilterFieldCount;
}

ScXMLDPAndContext::ScXMLDPAndContext( ScXMLImport& rImport,
                                      ScXMLDPFilterContext* pTempFilterContext) :
    ScXMLImportContext( rImport )
{
    pFilterContext = pTempFilterContext;
    pFilterContext->OpenConnection(false);
}

ScXMLDPAndContext::~ScXMLDPAndContext()
{
}

uno::Reference< xml::sax::XFastContextHandler > SAL_CALL ScXMLDPAndContext::createFastChildContext(
    sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& xAttrList )
{
    SvXMLImportContext *pContext(nullptr);
    sax_fastparser::FastAttributeList *pAttribList =
        &sax_fastparser::castToFastAttributeList( xAttrList );

    switch (nElement)
    {
        case XML_ELEMENT( TABLE, XML_FILTER_OR ):
        {
            // not supported in StarOffice
        }
        break;
        case XML_ELEMENT( TABLE, XML_FILTER_CONDITION ):
        {
            pContext = new ScXMLDPConditionContext( GetScImport(), nElement, pAttribList, pFilterContext);
        }
        break;
    }

    return pContext;
}

void SAL_CALL ScXMLDPAndContext::endFastElement( sal_Int32 /*nElement*/ )
{
    pFilterContext->CloseConnection();
}

ScXMLDPOrContext::ScXMLDPOrContext( ScXMLImport& rImport,
                                    ScXMLDPFilterContext* pTempFilterContext) :
    ScXMLImportContext( rImport ),
    pFilterContext(pTempFilterContext)
{
    pFilterContext->OpenConnection(true);
}

ScXMLDPOrContext::~ScXMLDPOrContext()
{
}

uno::Reference< xml::sax::XFastContextHandler > SAL_CALL ScXMLDPOrContext::createFastChildContext(
    sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& xAttrList )
{
    SvXMLImportContext *pContext(nullptr);
    sax_fastparser::FastAttributeList *pAttribList =
        &sax_fastparser::castToFastAttributeList( xAttrList );

    switch (nElement)
    {
        case XML_ELEMENT( TABLE, XML_FILTER_AND ):
        {
            pContext = new ScXMLDPAndContext( GetScImport(), pFilterContext);
        }
        break;
        case XML_ELEMENT( TABLE, XML_FILTER_CONDITION ):
        {
            pContext = new ScXMLDPConditionContext( GetScImport(), nElement, pAttribList, pFilterContext);
        }
        break;
    }

    return pContext;
}

void SAL_CALL ScXMLDPOrContext::endFastElement( sal_Int32 /*nElement*/ )
{
    pFilterContext->CloseConnection();
}

ScXMLDPConditionContext::ScXMLDPConditionContext( ScXMLImport& rImport,
                                      sal_Int32 /*nElement*/,
                                      const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList,
                                      ScXMLDPFilterContext* pTempFilterContext) :
    ScXMLImportContext( rImport ),
    pFilterContext(pTempFilterContext),
    sDataType(GetXMLToken(XML_TEXT)),
    nField(0),
    bIsCaseSensitive(false)
{

    if ( !rAttrList.is() )
        return;

    for (auto &aIter : *rAttrList)
    {
        switch (aIter.getToken())
        {
            case XML_ELEMENT( TABLE, XML_FIELD_NUMBER ):
            {
                nField = aIter.toInt32();
            }
            break;
            case XML_ELEMENT( TABLE, XML_CASE_SENSITIVE ):
            {
                bIsCaseSensitive = IsXMLToken(aIter, XML_TRUE);
            }
            break;
            case XML_ELEMENT( TABLE, XML_DATA_TYPE ):
            {
                sDataType = aIter.toString();
            }
            break;
            case XML_ELEMENT( TABLE, XML_VALUE ):
            {
                sConditionValue = aIter.toString();
            }
            break;
            case XML_ELEMENT( TABLE, XML_OPERATOR ):
            {
                sOperator = aIter.toString();
            }
            break;
        }
    }
}

ScXMLDPConditionContext::~ScXMLDPConditionContext()
{
}

void ScXMLDPConditionContext::getOperatorXML(
    std::u16string_view sTempOperator, ScQueryOp& aFilterOperator, utl::SearchParam::SearchType& rSearchType)
{
    rSearchType = utl::SearchParam::SearchType::Normal;
    if (IsXMLToken(sTempOperator, XML_MATCH))
    {
        rSearchType = utl::SearchParam::SearchType::Regexp;
        aFilterOperator = SC_EQUAL;
    }
    else if (IsXMLToken(sTempOperator, XML_NOMATCH))
    {
        rSearchType = utl::SearchParam::SearchType::Regexp;
        aFilterOperator = SC_NOT_EQUAL;
    }
    else if (sTempOperator == u"=")
        aFilterOperator = SC_EQUAL;
    else if (sTempOperator == u"!=")
        aFilterOperator = SC_NOT_EQUAL;
    else if (IsXMLToken(sTempOperator, XML_BOTTOM_PERCENT))
        aFilterOperator = SC_BOTPERC;
    else if (IsXMLToken(sTempOperator, XML_BOTTOM_VALUES))
        aFilterOperator = SC_BOTVAL;
    else if (sTempOperator == u">")
        aFilterOperator = SC_GREATER;
    else if (sTempOperator == u">=")
        aFilterOperator = SC_GREATER_EQUAL;
    else if (sTempOperator == u"<")
        aFilterOperator = SC_LESS;
    else if (sTempOperator == u"<=")
        aFilterOperator = SC_LESS_EQUAL;
    else if (IsXMLToken(sTempOperator, XML_TOP_PERCENT))
        aFilterOperator = SC_TOPPERC;
    else if (IsXMLToken(sTempOperator, XML_TOP_VALUES))
        aFilterOperator = SC_TOPVAL;
}

void SAL_CALL ScXMLDPConditionContext::endFastElement( sal_Int32 /*nElement*/ )
{
    ScQueryEntry aFilterField;
    aFilterField.nField = nField;
    if (pFilterContext->GetConnection())
        aFilterField.eConnect = SC_OR;
    else
        aFilterField.eConnect = SC_AND;
    pFilterContext->SetIsCaseSensitive(bIsCaseSensitive);
    if (IsXMLToken(sOperator, XML_TOKEN_EMPTY))
        aFilterField.SetQueryByEmpty();
    else if (IsXMLToken(sOperator, XML_NOEMPTY))
        aFilterField.SetQueryByNonEmpty();
    else
    {
        utl::SearchParam::SearchType eSearchType = utl::SearchParam::SearchType::Normal;
        getOperatorXML(sOperator, aFilterField.eOp, eSearchType);
        pFilterContext->SetSearchType(eSearchType);
        ScQueryEntry::Item& rItem = aFilterField.GetQueryItem();
        svl::SharedStringPool& rPool = GetScImport().GetDocument()->GetSharedStringPool();

        if (IsXMLToken(sDataType, XML_NUMBER))
        {
            rItem.mfVal = sConditionValue.toDouble();
            rItem.maString = rPool.intern(sConditionValue);
            rItem.meType = ScQueryEntry::ByValue;
        }
        else
        {
            rItem.maString = rPool.intern(sConditionValue);
            rItem.meType = ScQueryEntry::ByString;
            rItem.mfVal = 0.0;
        }
    }
    pFilterContext->AddFilterField(aFilterField);
}

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