/* -*- 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/.
 */
 
#include <orcusfiltersimpl.hxx>
#include <orcusinterface.hxx>
#include <tokenarray.hxx>
 
#include <osl/thread.hxx>
#include <sfx2/docfile.hxx>
#include <sfx2/frame.hxx>
#include <sfx2/sfxsids.hrc>
#include <svl/itemset.hxx>
#include <rtl/ustring.hxx>
#include <sal/log.hxx>
 
#include <orcus/format_detection.hpp>
#include <orcus/orcus_import_ods.hpp>
#include <orcus/stream.hpp>
#include <com/sun/star/task/XStatusIndicator.hpp>
 
using namespace com::sun::star;
 
namespace
{
uno::Reference<task::XStatusIndicator> getStatusIndicator(const SfxMedium& rMedium)
{
    uno::Reference<task::XStatusIndicator> xStatusIndicator;
    const SfxUnoAnyItem* pItem
        = rMedium.GetItemSet().GetItem<SfxUnoAnyItem>(SID_PROGRESS_STATUSBAR_CONTROL);
    if (pItem)
        xStatusIndicator.set(pItem->GetValue(), uno::UNO_QUERY);
    return xStatusIndicator;
}
 
bool loadFileContent(SfxMedium& rMedium, orcus::iface::import_filter& filter)
{
    SvStream* pStream = rMedium.GetInStream();
    pStream->Seek(0);
    static const size_t nReadBuffer = 1024 * 32;
    OStringBuffer aBuffer((int(nReadBuffer)));
    size_t nRead = 0;
    do
    {
        char pData[nReadBuffer];
        nRead = pStream->ReadBytes(pData, nReadBuffer);
        aBuffer.append(pData, nRead);
    } while (nRead == nReadBuffer);
 
    try
    {
        filter.read_stream(aBuffer);
    }
    catch (const std::exception& e)
    {
        SAL_WARN("sc", "Unable to load file via orcus filter! " << e.what());
        return false;
    }
 
    return true;
}
}
 
ScOrcusFilters::ImportResult ScOrcusFiltersImpl::importByName(ScDocument& rDoc, SfxMedium& rMedium,
                                                              const OUString& rFilterName) const
{
    const std::unordered_map<OUString, orcus::format_t> aMap = {
        { "Apache Parquet Spreadsheet", orcus::format_t::parquet },
        { "Gnumeric Spreadsheet", orcus::format_t::gnumeric },
        { "MS Excel 2003 XML Orcus", orcus::format_t::xls_xml },
        { "csv", orcus::format_t::csv },
        { "gnumeric", orcus::format_t::gnumeric },
        { "ods", orcus::format_t::ods },
        { "parquet", orcus::format_t::parquet },
        { "xls-xml", orcus::format_t::xls_xml },
        { "xlsx", orcus::format_t::xlsx },
    };
 
    if (auto it = aMap.find(rFilterName); it != aMap.end())
    {
        ScOrcusFactory aFactory(rDoc);
        aFactory.setStatusIndicator(getStatusIndicator(rMedium));
 
        auto filter = orcus::create_filter(it->second, &aFactory);
        if (!filter)
            return ImportResult::Failure;
 
        bool res = loadFileContent(rMedium, *filter);
        return res ? ImportResult::Success : ImportResult::Failure;
    }
 
    return ImportResult::NotSupported;
}
 
bool ScOrcusFiltersImpl::importODS_Styles(ScDocument& rDoc, OUString& aPath) const
{
    try
    {
#if defined _WIN32
        OString aPath8 = OUStringToOString(aPath, RTL_TEXTENCODING_UTF8);
#else
        OString aPath8 = OUStringToOString(aPath, osl_getThreadTextEncoding());
#endif
        orcus::file_content content(aPath8);
        ScOrcusFactory aFactory(rDoc);
        ScOrcusStyles aStyles(aFactory);
        orcus::import_ods::read_styles(content.str(), &aStyles);
    }
    catch (const std::exception& e)
    {
        SAL_WARN("sc", "Unable to load styles from xml file! " << e.what());
        return false;
    }
 
    return true;
}
 
std::unique_ptr<ScOrcusXMLContext> ScOrcusFiltersImpl::createXMLContext(ScDocument& rDoc,
                                                                        const OUString& rPath) const
{
    return std::make_unique<ScOrcusXMLContextImpl>(rDoc, rPath);
}
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

V530 The return value of function 'append' is required to be utilized.