#include "comic.h"
#include "pdf_comic.h"

#if defined USE_PDFIUM && !defined NO_PDF

int pdfRead(void *param,
            unsigned long position,
            unsigned char *pBuf,
            unsigned long size)
{

    QFile *file = static_cast<QFile *>(param);

    file->seek(position);

    qint64 numBytesRead = file->read(reinterpret_cast<char *>(pBuf), size);

    if (numBytesRead > 0) {
        return numBytesRead;
    }

    return 0;
}

// pdfium is not threadsafe
// We need to use mutex locking & refcounting to avoid crashes

int PdfiumComic::refcount = 0;
QMutex PdfiumComic::pdfmutex;

PdfiumComic::PdfiumComic()
{
    QMutexLocker locker(&pdfmutex);
    if (++refcount == 1) {
        FPDF_InitLibrary();
    }
}

PdfiumComic::~PdfiumComic()
{
    QMutexLocker locker(&pdfmutex);
    if (doc) {
        FPDF_CloseDocument(doc);
    }
    if (--refcount == 0) {
        FPDF_DestroyLibrary();
    }
}

bool PdfiumComic::openComic(const QString &path)
{
    pdfFile.setFileName(path);

    if (pdfFile.open(QIODevice::ReadOnly) == false) {
        qDebug() << "unable to open file : " << path;
        return false;
    }

    fileAccess.m_FileLen = pdfFile.size();
    fileAccess.m_GetBlock = pdfRead;
    fileAccess.m_Param = &pdfFile;

    QMutexLocker lock(&pdfmutex);
    doc = FPDF_LoadCustomDocument(&fileAccess, NULL);
    if (doc) {
        return true;
    } else {
        qDebug() << FPDF_GetLastError();
        return false;
    }
}

void PdfiumComic::closeComic()
{
    QMutexLocker locker(&pdfmutex);
    FPDF_CloseDocument(doc);
}

unsigned int PdfiumComic::numPages()
{
    if (doc) {
        QMutexLocker locker(&pdfmutex);
        return FPDF_GetPageCount(doc);
    } else {
        return 0; //-1?
    }
}

QImage PdfiumComic::getPage(const int page)
{
    if (!doc) {
        return QImage();
    }

    QImage image;
    FPDF_PAGE pdfpage;
    FPDF_BITMAP bitmap;

    QMutexLocker locker(&pdfmutex);
    pdfpage = FPDF_LoadPage(doc, page);

    if (!pdfpage) {
        // TODO report error
        qDebug() << FPDF_GetLastError();
        return QImage();
    }

    // TODO: make target DPI configurable
    // TODO: max render size too
    QSize pagesize((FPDF_GetPageWidth(pdfpage) / 72) * 150,
                   (FPDF_GetPageHeight(pdfpage) / 72) * 150);
    auto maxSize = 4096;
    if (pagesize.width() > maxSize || pagesize.height() > maxSize) {
        pagesize.scale(maxSize, maxSize, Qt::KeepAspectRatio);
    }
    auto minSize = 2560;
    if (pagesize.width() < minSize || pagesize.height() < minSize) {
        pagesize.scale(minSize, minSize, Qt::KeepAspectRatio);
    }
    image = QImage(pagesize, QImage::Format_ARGB32); // QImage::Format_RGBX8888);
    if (image.isNull()) {
        // TODO report OOM error
        qDebug() << "Image too large, OOM";
        return image;
    }
    image.fill(0xFFFFFFFF);

    bitmap = FPDFBitmap_CreateEx(image.width(), image.height(), FPDFBitmap_BGRA, image.scanLine(0), image.bytesPerLine());
    // TODO: make render flags costumizable
    FPDF_RenderPageBitmap(bitmap, pdfpage, 0, 0, image.width(), image.height(), 0, (FPDF_LCD_TEXT));
    FPDFBitmap_Destroy(bitmap);
    FPDF_ClosePage(pdfpage);
    return image;
}
#endif // USE_PDFIUM
