/**************************************************************************
 **                                                                      **
 ** Copyright (C) 2011-2026 Lukas Spies                                  **
 ** Contact: https://photoqt.org                                         **
 **                                                                      **
 ** This file is part of PhotoQt.                                        **
 **                                                                      **
 ** PhotoQt is free software: you can redistribute it and/or modify      **
 ** it under the terms of the GNU General Public License as published by **
 ** the Free Software Foundation, either version 2 of the License, or    **
 ** (at your option) any later version.                                  **
 **                                                                      **
 ** PhotoQt 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 General Public License for more details.                         **
 **                                                                      **
 ** You should have received a copy of the GNU General Public License    **
 ** along with PhotoQt. If not, see <http://www.gnu.org/licenses/>.      **
 **                                                                      **
 **************************************************************************/

#include <pqc_providerfolderthumb.h>
#include <pqc_providerthumb.h>
#include <pqc_settingscpp.h>
#include <pqc_imagehandler.h>
#include <scripts/pqc_scriptsfilespaths.h>
#include <QPainter>
#include <QImage>
#include <QCollator>

QQuickImageResponse *PQCAsyncImageProviderFolderThumb::requestImageResponse(const QString &url, const QSize &requestedSize) {

    PQCAsyncImageResponseFolderThumb *response = new PQCAsyncImageResponseFolderThumb(url, ((requestedSize.isValid() && !requestedSize.isNull()) ? requestedSize : QSize(256,256)));
    QThreadPool::globalInstance()->setMaxThreadCount(qMax(1,PQCSettingsCPP::get().getThumbnailsMaxNumberThreads()));
    pool.start(response);
    return response;
}

/***********************************************************/

PQCAsyncImageResponseFolderThumbCache& PQCAsyncImageResponseFolderThumbCache::get() {
    static PQCAsyncImageResponseFolderThumbCache instance;
    return instance;
}
PQCAsyncImageResponseFolderThumbCache::PQCAsyncImageResponseFolderThumbCache() {
    cache.clear();
}
bool PQCAsyncImageResponseFolderThumbCache::loadFromCache(QString foldername, int numEnabledFormats, QFileInfoList &entries) {
    const QString key = generateCacheKey(foldername, numEnabledFormats);
    if(cache.contains(key)) {
        entries = cache.value(key);
        return true;
    }
    return false;
}
void PQCAsyncImageResponseFolderThumbCache::saveToCache(QString foldername, int numEnabledFormats, QFileInfoList &entries) {
    cache.insert(generateCacheKey(foldername, numEnabledFormats), entries);
}

const QString PQCAsyncImageResponseFolderThumbCache::generateCacheKey(QString foldername, int numEnabledFormats) {

    PQCSettingsCPP& settings = PQCSettingsCPP::get();

    const bool useDefaultSort = (settings.getFiledialogFolderContentThumbnailsSortBy() == "default");
    const QString sortBy = useDefaultSort ? settings.getImageviewSortImagesBy() : settings.getFiledialogFolderContentThumbnailsSortBy();
    const int ascending = useDefaultSort ? settings.getImageviewSortImagesAscending() : settings.getFiledialogFolderContentThumbnailsSortAscending();

    return foldername
           % "::"
           % QString::number(numEnabledFormats)
           % "::"
           % QString::number(QFileInfo(foldername).lastModified().toMSecsSinceEpoch())
           % "::"
           % sortBy
           % "::"
           % QString::number(ascending ? 1 : 0);

}

/***********************************************************/

PQCAsyncImageResponseFolderThumb::PQCAsyncImageResponseFolderThumb(const QString &url, const QSize &requestedSize) {

    m_requestedSize = requestedSize;
    m_index = url.split(":://::")[1].toInt();
    m_folder = url.split(":://::")[0];

    setAutoDelete(false);

}

PQCAsyncImageResponseFolderThumb::~PQCAsyncImageResponseFolderThumb() {
}

QQuickTextureFactory *PQCAsyncImageResponseFolderThumb::textureFactory() const {
    return QQuickTextureFactory::textureFactoryForImage(m_image);
}

void PQCAsyncImageResponseFolderThumb::run() {

    if(m_index == 0 || PQCScriptsFilesPaths::get().isExcludeDirFromCaching(m_folder)) {
        m_image = QImage(QSize(1,1), QImage::Format_ARGB32);
        Q_EMIT finished();
        return;
    }

    // get folder contents
    QString fname;
    int count;

    // we cache fileinfo lists to speed up subsequent lodings
    QFileInfoList fileinfolist;
    const int checknum = PQCImageHandler::get().getNumFormatsEnabled();
    if(!PQCAsyncImageResponseFolderThumbCache::get().loadFromCache(m_folder, checknum, fileinfolist)) {

        QDir dir(m_folder);

        QStringList checkForTheseFormats(checknum);
        const QSet<QString> lst = PQCImageHandler::get().getEnabledSuffixes();
        for(const QString &c : lst)
            checkForTheseFormats << QString("*.%1").arg(c);

        dir.setNameFilters(checkForTheseFormats);
        dir.setFilter(QDir::Files);

        bool sortAscending = (PQCSettingsCPP::get().getFiledialogFolderContentThumbnailsSortBy()=="default"
                                  ? PQCSettingsCPP::get().getImageviewSortImagesAscending()
                                  : PQCSettingsCPP::get().getFiledialogFolderContentThumbnailsSortAscending());
        QString sortBy = (PQCSettingsCPP::get().getFiledialogFolderContentThumbnailsSortBy()=="default"
                              ? PQCSettingsCPP::get().getImageviewSortImagesBy()
                              : PQCSettingsCPP::get().getFiledialogFolderContentThumbnailsSortBy());

        QDir::SortFlags sortFlags = QDir::IgnoreCase;
        if(sortAscending)
            sortFlags |= QDir::Reversed;
        if(sortBy == "name")
            sortFlags |= QDir::Name;
        else if(sortBy == "time")
            sortFlags |= QDir::Time;
        else if(sortBy == "size")
            sortFlags |= QDir::Size;
        else if(sortBy == "type")
            sortFlags |= QDir::Type;

        if(sortBy != "naturalname")
            dir.setSorting(sortFlags);

        fileinfolist = dir.entryInfoList();
        count = fileinfolist.size();

        if(sortBy == "naturalname") {
            QCollator collator;
            collator.setLocale(QLocale::system());
#ifndef PQMWITHOUTICU
            collator.setCaseSensitivity(Qt::CaseInsensitive);
            collator.setIgnorePunctuation(true);
            collator.setNumericMode(true);
#endif
            if(!sortAscending)
                std::sort(fileinfolist.begin(), fileinfolist.end(), [&collator](const QFileInfo &file1, const QFileInfo &file2) { return collator.compare(file2.fileName(), file1.fileName()) < 0; });
            else
                std::sort(fileinfolist.begin(), fileinfolist.end(), [&collator](const QFileInfo &file1, const QFileInfo &file2) { return collator.compare(file1.fileName(), file2.fileName()) < 0; });
        }

        PQCAsyncImageResponseFolderThumbCache::get().saveToCache(m_folder, checknum, fileinfolist);

    } else
        count = fileinfolist.length();

    // no images inside folder
    if(count == 0) {
        m_image = QImage(QSize(1,1), QImage::Format_ARGB32);
        Q_EMIT finished();
        return;
    }

    // get current image filename
    fname = fileinfolist[(m_index-1)%count].absoluteFilePath();

    // load thumbnail
    PQCAsyncImageResponseThumb loader(fname,m_requestedSize);
    loader.loadImage();
    m_image = loader.m_image;

    Q_EMIT finished();

}
