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

   Copyright (C) 2016-2020 Sandro Mani <manisandro@gmail.com>
   Copyright (C) 2021 LLC "RusBITech-Astra" (https://astralinux.ru)

    Based on gImageReader source code by Sandro Mani under the GNU
    General Public License (GPL) version 3 or later

   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 "djvudocument.h"

#include <QFile>
#include <QPainter>

#include <libdjvu/ddjvuapi.h>
#include <libdjvu/miniexp.h>

/**
 * Explore the message queue until there are no message left in it.
 */
static void handle_ddjvu_messages(ddjvu_context_t* ctx, int wait)
{
    const ddjvu_message_t* msg;
    if (wait) {
        ddjvu_message_wait(ctx);
    }
    while ((msg = ddjvu_message_peek(ctx))) {
        ddjvu_message_pop(ctx);
    }
}

/**
 * Explore the message queue until the message \p mid is found.
 */
static void wait_for_ddjvu_message(ddjvu_context_t* ctx, ddjvu_message_tag_t mid)
{
    ddjvu_message_wait(ctx);
    const ddjvu_message_t* msg;
    while ((msg = ddjvu_message_peek(ctx)) && msg && (msg->m_any.tag != mid)) {
        ddjvu_message_pop(ctx);
    }
}


DjVuDocument::DjVuDocument()
{
    // creating the djvu context
    m_djvu_cxt = ddjvu_context_create("DjVuDocument");
    // creating the rendering format
    unsigned int formatmask[4] = { 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }; // R, G, B, A masks
    m_format = ddjvu_format_create(DDJVU_FORMAT_RGBMASK32, 4, formatmask);
    ddjvu_format_set_row_order(m_format, 1);
    ddjvu_format_set_y_direction(m_format, 1);
}

DjVuDocument::~DjVuDocument()
{
    closeFile();
    ddjvu_format_release(m_format);
    ddjvu_context_release(m_djvu_cxt);
}

bool DjVuDocument::openFile(const QString& fileName)
{
    // first, close the old file
    if (m_djvu_document) {
        closeFile();
    }

    // load the document...
    m_djvu_document = ddjvu_document_create_by_filename(m_djvu_cxt, QFile::encodeName(fileName).constData(), true);
    if (!m_djvu_document) { return false; }
    // ...and wait for its loading
    wait_for_ddjvu_message(m_djvu_cxt, DDJVU_DOCINFO);
    if (ddjvu_document_decoding_error(m_djvu_document)) {
        ddjvu_document_release(m_djvu_document);
        m_djvu_document = nullptr;
        return false;
    }

    int numofpages = ddjvu_document_get_pagenum(m_djvu_document);
    m_pages.clear();
    m_pages.resize(numofpages);

    // read the pages
    for (int i = 0; i < numofpages; ++i) {
        ddjvu_status_t sts;
        ddjvu_pageinfo_t info;
        while ((sts = ddjvu_document_get_pageinfo(m_djvu_document, i, &info)) < DDJVU_JOB_OK) {
            handle_ddjvu_messages(m_djvu_cxt, true);
        }
        if (sts >= DDJVU_JOB_FAILED) {
            closeFile();
            return false;
        }
        m_pages[i] = {info.width, info.height, info.dpi};
    }

    return true;
}

void DjVuDocument::closeFile()
{
    m_pages.clear();
    // releasing the old document
    if (m_djvu_document) {
        ddjvu_document_release(m_djvu_document);
    }
    m_djvu_document = nullptr;
}

QImage DjVuDocument::image(int pageno, int resolution)
{
    /*if(pageno < 0 || pageno >= pageCount()) {
    	return QImage();
    }*/

    const DjVuDocument::Page& page = m_pages[pageno];

    ddjvu_page_t* djvupage = ddjvu_page_create_by_pageno(m_djvu_document, pageno);
    // wait for the new page to be loaded
    ddjvu_status_t sts;
    while ((sts = ddjvu_page_decoding_status(djvupage)) < DDJVU_JOB_OK) {
        handle_ddjvu_messages(m_djvu_cxt, true);
    }

    double scaleFactor = double(resolution) / double(page.dpi);
    ddjvu_rect_t pagerect;
    pagerect.x = 0;
    pagerect.y = 0;
    pagerect.w = page.width * scaleFactor;
    pagerect.h = page.height * scaleFactor;
    ddjvu_rect_t renderrect = pagerect;
    QImage res_img(renderrect.w, renderrect.h, QImage::Format_RGB32);
    int res = ddjvu_page_render(djvupage, DDJVU_RENDER_COLOR, &pagerect, &renderrect, m_format, res_img.bytesPerLine(), (char*)res_img.bits());
    if (!res) {
        res_img.fill(Qt::white);
    }

    ddjvu_page_release(djvupage);
    return res_img;
}
