/***
   This file is part of fly-ocr.

   Copyright (C) 2021 LLC "RusBITech-Astra" (https://astralinux.ru)

   Foobar 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 3 of the License, or
   (at your option) any later version.

   Foobar 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 fly-ocr. If not, see <https://www.gnu.org/licenses/>.
***/

#include <QFileInfo>
#include <QPainter>
#include <QIcon>
#include <QtDebug>
#include "sourcedocumentmodel.h"

SourceDocumentPage::~SourceDocumentPage()
{
    if (temp && QFile::exists(path))
        QFile::remove(path);
}

SourceDocumentModel::SourceDocumentModel(QObject* parent) : QAbstractListModel(parent) {}

void SourceDocumentModel::add(const QStringList& paths)
{
    for (const QString& path : qAsConst(paths))
        add(path);
}

void SourceDocumentModel::add(const QString& path, bool temp, std::shared_ptr<SourceDocumentInfo> documentInfo)
{
    QFileInfo info(path);

    if (!info.isFile() || !info.exists() || !info.isReadable())
        return;

    std::shared_ptr<DisplayRenderer> renderer;

    if (info.suffix().toLower() == QStringLiteral("pdf"))
        renderer = std::make_shared<PDFRenderer>(path, QByteArray());
    else if (info.suffix().toLower() == QStringLiteral("djvu"))
        renderer = std::make_shared<DJVURenderer>(path);
    else
        renderer = std::make_shared<ImageRenderer>(path);

    QList<std::shared_ptr<SourceDocumentPage>> pages;

    for (int i = 0; i < renderer->pageCount(); ++i) {
        std::shared_ptr<SourceDocumentPage> page = std::make_shared<SourceDocumentPage>();
        page->renderer = renderer;
        page->info = documentInfo;
        page->page = i;
        page->displayName = info.fileName();
        page->path = info.canonicalFilePath();
        page->temp = temp;
        pages << page;
    }

    beginInsertRows(QModelIndex(), m_pages.count(), m_pages.count() + pages.count() - 1);
    m_pages << pages;
    endInsertRows();
}

void SourceDocumentModel::setRecognized(int p, bool recognized)
{
    if (p >= m_pages.count() || p < 0) {
        qWarning() << "invalid page number:" << p;
        return;
    }

    m_pages[p]->recognized = recognized;
    emit dataChanged(index(p), index(p), { Qt::DecorationRole });
}

void SourceDocumentModel::clearReconized()
{
    for (auto page : qAsConst(m_pages))
        page->recognized = false;
    emit dataChanged(index(0), index(m_pages.count() - 1), { Qt::DecorationRole });
}

std::shared_ptr<SourceDocumentPage> SourceDocumentModel::page(int i)
{
    return m_pages[i];
}

QModelIndex SourceDocumentModel::findFile(const QString& filePath) const
{
    for (int i = 0; i < m_pages.count(); ++i) {
        if (m_pages[i]->path == filePath)
            return index(i, 0);
    }

    return QModelIndex();
}

QList<int> SourceDocumentModel::findPages(const QString& filePath) const
{
    QList<int> pages;
    for (int i = 0; i < m_pages.count(); ++i) {
        if (m_pages[i]->path == filePath)
            pages << i;
    }
    return pages;
}

bool SourceDocumentModel::isEmpty() const
{
    return m_pages.isEmpty();
}

bool SourceDocumentModel::hasRecognitionResults() const
{
    for (int i = 0; i < m_pages.count(); ++i) {
        if (m_pages[i]->recognized)
            return true;
    }
    return false;
}

bool SourceDocumentModel::listMode() const
{
    return m_listMode;
}

QVariant SourceDocumentModel::data(const QModelIndex& index, int role) const
{
    if (index.row() < 0 || index.row() >= m_pages.count())
        return QVariant();

    if (role == Qt::DisplayRole) {
        SourceDocumentPage* p = m_pages[index.row()].get();
        return QString("%1 - %2").arg(index.row() + 1).arg(p->displayName);
    } else if (role == Qt::DecorationRole) {
        SourceDocumentPage* p = m_pages[index.row()].get();
        QImage thumbnail = p->renderer->renderThumbnail(p->page);
        if (p->recognized) {
            QPainter painter(&thumbnail);
            painter.drawPixmap(0, 0, QIcon::fromTheme("emblem-documents").pixmap(32, 32)); //TODO optimization
        }
        return m_listMode ? thumbnail.scaled(64, 64, Qt::KeepAspectRatio) : thumbnail;
    } else if (role == Qt::SizeHintRole) {
        return m_listMode ? QSize(64, 64) : QSize(60, 210);
    }

    return QVariant();
}

int SourceDocumentModel::rowCount(const QModelIndex& parent) const
{
    Q_UNUSED(parent);
    return m_pages.count();
}

bool SourceDocumentModel::removeRows(int row, int count, const QModelIndex& parent)
{
    beginRemoveRows(parent, row, row + count - 1);
    for (int i = 0; i < count; ++i) {
        m_pages.removeAt(row);
    }
    endRemoveRows();
    return true;
}

void SourceDocumentModel::setListMode(bool enabled)
{
    m_listMode = enabled;
    emit dataChanged(index(0), index(m_pages.count() - 1), { Qt::DecorationRole, Qt::SizeHintRole });
}

void SourceDocumentModel::clear()
{
    beginResetModel();
    m_pages.clear();
    endResetModel();
}
