/*******************************************************************************
**
** SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru>
** SPDX-License-Identifier: BSD-3-Clause
** This file is part of the OfficeViewer project.
**
** Redistribution and use in source and binary forms,
** with or without modification, are permitted provided
** that the following conditions are met:
**
** * Redistributions of source code must retain the above copyright notice,
**   this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright notice,
**   this list of conditions and the following disclaimer
**   in the documentation and/or other materials provided with the distribution.
** * Neither the name of the copyright holder nor the names of its contributors
**   may be used to endorse or promote products derived from this software
**   without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
** THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
** FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
** OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS;
** OR BUSINESS INTERRUPTION)
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE)
** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
** EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
*******************************************************************************/


#include "documentcache.h"
#include "imagescache.h"
#include "exportedcache.h"

#include <QDir>
#include <QFileInfo>
#include <QImage>
#include <QUrl>
#include <QtConcurrent/QtConcurrent>

namespace {
    const auto PATH_CACHE_PAGE = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/images";
    const auto PATH_CACHE_TILE = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/tiles";
    const auto PATH_CACHE_EXPORT = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/export";
} // namespace

class ChecksumWorker : public QRunnable
{
public:
    ChecksumWorker(const QString &filePath, DocumentCache *documentCache)
        : filePath(filePath)
        , documentCache(documentCache)
    {}

private:
    void run() override
    {
        QFile file(filePath);
        if (file.open(QFile::ReadOnly)) {
            QCryptographicHash hash(QCryptographicHash::Md5);

            if (hash.addData(&file))
                emit documentCache->checksumCalculated(filePath, hash.result());
        }
    }

    QString filePath;
    DocumentCache *documentCache;
};

DocumentCache::DocumentCache(QObject *parent)
    : QObject(parent)
    , m_pageCache(new ImagesCache(PATH_CACHE_PAGE, this))
    , m_tileCache(new ImagesCache(PATH_CACHE_TILE, this))
    , m_exportedCache(new ExportedCache(PATH_CACHE_EXPORT, this))
{
    connect(m_pageCache, &ImagesCache::imageLoaded, this, &DocumentCache::imageLoaded);
    connect(m_tileCache, &ImagesCache::imageLoaded, this, &DocumentCache::imageLoaded);
    connect(m_exportedCache, &ExportedCache::documentExported, this, &DocumentCache::documentExported);
}

DocumentCache::~DocumentCache()
{
    QThreadPool::globalInstance()->clear();
    QThreadPool::globalInstance()->waitForDone();
}

bool DocumentCache::loadImage(const QString &fileId, int pageNumber, const QSize &canvasSize, const QRect &rectTile, qreal zoom)
{
#ifdef DEBUG_MODE
    return false;
#endif

    if (rectTile.isNull())
        return m_pageCache->loadImage(fileId, pageNumber, canvasSize, rectTile, zoom);
    else
        return m_tileCache->loadImage(fileId, pageNumber, canvasSize, rectTile, zoom);
}

void DocumentCache::insertImage(const QString &fileId, int pageNumber, const QImage &image, const QRect &rectTile, qreal zoom)
{
    if (rectTile.isNull())
        return m_pageCache->insertImage(fileId, pageNumber, image, rectTile, zoom);
    else
        return m_tileCache->insertImage(fileId, pageNumber, image, rectTile, zoom);
}

bool DocumentCache::loadExportedDoc(const QString &fileId, const QString &pathExportedDoc, const QString &format)
{
    return m_exportedCache->loadExportedDoc(fileId, pathExportedDoc, format);
}

void DocumentCache::insertEportedDoc(const QString &fileId, const QString &pathExportedDoc, const QString &format)
{
    m_exportedCache->insertExportedDoc(fileId, pathExportedDoc, format);
}

DocumentCache *DocumentCache::instance()
{
    static DocumentCache *_instance = nullptr;

    if (_instance == nullptr)
        _instance = new DocumentCache();

    return _instance;
}

void DocumentCache::calculateChecksum(const QString &filePath)
{
    QThreadPool::globalInstance()->start(new ChecksumWorker(filePath, this));
}
