/***************************************************************************
 *   copyright       : (C) 2003-2024 by Pascal Brachet                     *
 *   https://www.xm1math.net/texmaker/                                     *
 *                                                                         *
 *   based on qpdfview  Copyright 2012 Adam Reichold GPL                   *
 *   This program 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.                                   *
 *                                                                         *
 *   @license GPL-2.0+ <https://spdx.org/licenses/GPL-2.0+.html>           *
 ***************************************************************************/

/*

Copyright 2012 Adam Reichold

This file is part of qpdfview.

modified by Pascal Brachet

*/

#include "presentationview.h"
#include <QApplication>
#include <QScreen>
#include <QtConcurrent>
#include <QToolTip>


PresentationView::PresentationView(QMutex* mutex, QPdfDocument* document) : QWidget(),
    m_mutex(0),
    m_document(0),
    m_numberOfPages(-1),
    m_currentPage(-1),
    m_returnToPage(-1),
//    m_links(),
    m_scaleFactor(1.0),
    m_pixelRatio(1.0),
    m_normalizedTransform(),
    m_boundingRect(),
    m_image(),
    m_render(0)
{

    setMouseTracking(true);

    m_render = new QFutureWatcher< void >(this);
    connect(m_render, SIGNAL(finished()), SLOT(on_render_finished()));

    connect(this, SIGNAL(imageReady(QImage)), SLOT(on_imageReady(QImage)));

    m_mutex = mutex;
    m_document = document;

    m_numberOfPages = m_document->pageCount();
    m_currentPage = 1;
    m_returnToPage = -1;

     m_pixelRatio=qApp->devicePixelRatio();

     prepareView();
    setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
    setWindowState(windowState() | Qt::WindowFullScreen);
}

PresentationView::~PresentationView()
{
    m_render->cancel();
    m_render->waitForFinished();

    //qDeleteAll(m_links);
}

int PresentationView::numberOfPages() const
{
    return m_numberOfPages;
}

int PresentationView::currentPage() const
{
    return m_currentPage;
}

void PresentationView::previousPage()
{
    jumpToPage(currentPage() - 1, false);
}

void PresentationView::nextPage()
{
    jumpToPage(currentPage() + 1, false);
}

void PresentationView::firstPage()
{
    jumpToPage(1);
}

void PresentationView::lastPage()
{
    jumpToPage(numberOfPages());
}

void PresentationView::jumpToPage(int page, bool returnTo)
{
    if(m_currentPage != page && page >= 1 && page <= m_numberOfPages)
    {
        if(returnTo)
        {
            m_returnToPage = m_currentPage;
        }

        m_currentPage = page;

        prepareView();
    }
}

void PresentationView::startRender()
{
    if(!m_render->isRunning())
    {
        #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
        m_render->setFuture(QtConcurrent::run(&PresentationView::render,this, m_currentPage - 1, m_scaleFactor));
        #else
        m_render->setFuture(QtConcurrent::run(this, &PresentationView::render, m_currentPage - 1, m_scaleFactor));
        #endif
    }
}

void PresentationView::cancelRender()
{
    m_render->cancel();

    m_image = QImage();
}

void PresentationView::on_render_finished()
{
    update();
}

void PresentationView::on_imageReady(QImage image)
{
    if(PageItem::invertColors())
    {
        image.invertPixels();
    }

    if(!m_render->isCanceled())
    {
        m_image = image;
    }
}

void PresentationView::resizeEvent(QResizeEvent* event)
{
    Q_UNUSED(event);

    prepareView();
}

void PresentationView::paintEvent(QPaintEvent* event)
{
    Q_UNUSED(event);

    QPainter painter(this);

    painter.fillRect(rect(), QBrush(PageItem::invertColors() ? Qt::white : Qt::black));

    if(!m_image.isNull())
    {
        painter.fillRect(m_boundingRect, QBrush(Qt::white));
        painter.drawImage(m_boundingRect.topLeft(), m_image);
    }
    else
    {
        startRender();
    }
}

void PresentationView::keyPressEvent(QKeyEvent* event)
{
    if(event->modifiers() == Qt::NoModifier)
    {
        switch(event->key())
        {
        case Qt::Key_PageUp:
        case Qt::Key_Up:
        case Qt::Key_Left:
        case Qt::Key_Backspace:
            previousPage();

            event->accept();
            return;
        case Qt::Key_PageDown:
        case Qt::Key_Down:
        case Qt::Key_Right:
        case Qt::Key_Space:
            nextPage();

            event->accept();
            return;
        case Qt::Key_Home:
            firstPage();

            event->accept();
            return;
        case Qt::Key_End:
            lastPage();

            event->accept();
            return;
        case Qt::Key_Return:
            jumpToPage(m_returnToPage);

            event->accept();
            return;
        case Qt::Key_F12:
        case Qt::Key_Escape:
            close();

            event->accept();
            return;
        }
    }
int qtKeyCode = event->key();

if(event->modifiers() & Qt::ShiftModifier) {
	qtKeyCode += Qt::SHIFT;
}
if(event->modifiers() & Qt::ControlModifier) {
	qtKeyCode += Qt::CTRL;
}
if(event->modifiers() & Qt::AltModifier) {
	qtKeyCode += Qt::ALT;
}
if(event->modifiers() & Qt::MetaModifier) {
	qtKeyCode += Qt::META;
}
QKeySequence s1 = QKeySequence(qtKeyCode);
if (s1.matches(QKeySequence("PgUp"))==QKeySequence::ExactMatch) previousPage();
else if (s1.matches(QKeySequence("PgDown"))==QKeySequence::ExactMatch) nextPage();
else if (s1.matches(QKeySequence("Home"))==QKeySequence::ExactMatch) firstPage();
else if (s1.matches(QKeySequence("End"))==QKeySequence::ExactMatch) lastPage();
else if (s1.matches(QKeySequence("Escape"))==QKeySequence::ExactMatch) close();
else QWidget::keyPressEvent(event);
}

void PresentationView::mouseMoveEvent(QMouseEvent* event)
{
    QApplication::restoreOverrideCursor();


    QToolTip::hideText();
}

void PresentationView::mousePressEvent(QMouseEvent* event)
{

}

void PresentationView::prepareView()
{
    m_mutex->lock();


    QSizeF size = m_document->pageSize(m_currentPage - 1);

    //delete page;

    m_mutex->unlock();

    {
        m_scaleFactor = qMin(width() / size.width(), height() / size.height());

        m_boundingRect.setLeft(0.5 * (width() - m_scaleFactor * size.width()));
        m_boundingRect.setTop(0.5 * (height() - m_scaleFactor * size.height()));
        m_boundingRect.setWidth(m_scaleFactor * size.width());
        m_boundingRect.setHeight(m_scaleFactor * size.height());

        m_normalizedTransform.reset();
        m_normalizedTransform.translate(m_boundingRect.left(), m_boundingRect.top());
        m_normalizedTransform.scale(m_boundingRect.width(), m_boundingRect.height());
    }

    cancelRender();

    update();
}

void PresentationView::render(int index, qreal scaleFactor)
{
    QMutexLocker mutexLocker(m_mutex);

    if(m_render->isCanceled())
    {
        return;
    }

    
qreal extra=1.0;

#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
if (m_pixelRatio>1) extra=m_pixelRatio;//qApp->devicePixelRatio();
#else
if (m_pixelRatio>=2) extra=m_pixelRatio;//qApp->devicePixelRatio();
#endif



const QSizeF size = m_document->pageSize(index) * scaleFactor * extra ;
    //QImage image = m_document->render(index,QSize(size.width()* physicalDpiX()/72,size.height()* physicalDpiY()/72));
QImage image = m_document->render(index,QSize(size.width(),size.height()));

#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
if (m_pixelRatio>1) image.setDevicePixelRatio(m_pixelRatio);//image.setDevicePixelRatio(qApp->devicePixelRatio());
#else
if (m_pixelRatio>=2) image.setDevicePixelRatio(m_pixelRatio);//image.setDevicePixelRatio(qApp->devicePixelRatio());
#endif

    //delete page;

    if(m_render->isCanceled())
    {
        return;
    }

    emit imageReady(image);
}
