/***************************************************************************
 *   Copyright (C) 2008 by S. MANKOWSKI / G. DE BURE support@mankowski.fr  *
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 *   This program 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 this program.  If not, see <http://www.gnu.org/licenses/>  *
 ***************************************************************************/
/** @file
 * A plugin to print pages
 *
 * @author Stephane MANKOWSKI
 */
#include "skgprintplugin.h"

#include <kactioncollection.h>
#include <kstandardaction.h>
#include <kaboutdata.h>
#include <kpluginfactory.h>

#include <qtextbrowser.h>
#include <qprinter.h>
#include <qprintdialog.h>
#include <qprintpreviewdialog.h>
#include <qpainter.h>
#include <qpicture.h>
#include <qwebview.h>
#include <qwebframe.h>
#include <qbuffer.h>

#include "skgprint_settings.h"
#include "skgtraces.h"
#include "skgmainpanel.h"
#include "skgtreeview.h"

/**
 * This plugin factory.
 */
K_PLUGIN_FACTORY(SKGPrintPluginFactory, registerPlugin<SKGPrintPlugin>();)

SKGPrintPlugin::SKGPrintPlugin(QWidget* iWidget, QObject* iParent, const QVariantList& /*iArg*/) :
    SKGInterfacePlugin(iParent), m_currentDocument(nullptr)
{
    Q_UNUSED(iWidget);
    SKGTRACEINFUNC(10);
}

SKGPrintPlugin::~SKGPrintPlugin()
{
    SKGTRACEINFUNC(10);
    m_currentDocument = nullptr;
}

bool SKGPrintPlugin::setupActions(SKGDocument* iDocument, const QStringList& iArgument)
{
    SKGTRACEINFUNC(10);
    Q_UNUSED(iArgument);

    m_currentDocument = iDocument;

    setComponentName(QStringLiteral("skg_print"), title());
    setXMLFile(QStringLiteral("skg_print.rc"));

    registerGlobalAction(QStringLiteral("file_print"), KStandardAction::print(this, SLOT(onPrint()), actionCollection()));
    registerGlobalAction(QStringLiteral("file_print_preview"), KStandardAction::printPreview(this, SLOT(onPrintPreview()), actionCollection()));

    return true;
}

KConfigSkeleton* SKGPrintPlugin::getPreferenceSkeleton()
{
    return skgprint_settings::self();
}

QString SKGPrintPlugin::title() const
{
    return i18nc("Verb, action to use a printer", "print");
}

int SKGPrintPlugin::getOrder() const
{
    return 2;
}

QStringList SKGPrintPlugin::tips() const
{
    QStringList output;
    output.push_back(i18nc("Description of a tips", "<p>... you can print all opened pages.</p>"));
    return output;
}

void SKGPrintPlugin::onPrint()
{
    SKGError err;
    SKGTRACEINFUNCRC(10, err);

    if (SKGMainPanel::getMainPanel()) {
        QPrinter printer(QPrinter::HighResolution);
        QPointer<QPrintDialog> dialog = new QPrintDialog(&printer, SKGMainPanel::getMainPanel());
        dialog->setOption(QAbstractPrintDialog::PrintCurrentPage, true);
        dialog->setMinMax(1, SKGMainPanel::getMainPanel()->getTabWidget()->count());
        if (dialog->exec() == QDialog::Accepted) {
            QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
            print(&printer);
            QApplication::restoreOverrideCursor();
        }
        delete dialog;
    }
}

void SKGPrintPlugin::onPrintPreview()
{
    SKGError err;
    SKGTRACEINFUNCRC(10, err);
    QPointer<QPrintPreviewDialog> dialog = new QPrintPreviewDialog(SKGMainPanel::getMainPanel());
    connect(dialog.data(), &QPrintPreviewDialog::paintRequested, this, &SKGPrintPlugin::print);
    dialog->exec();
    delete dialog;
}

void SKGPrintPlugin::print(QPrinter* iPrinter)
{
    SKGTRACEINFUNC(10);
    if (SKGMainPanel::getMainPanel() && iPrinter) {
        SKGError err;

        // Get printer options
        int docCopies;
        int pageCopies;
        if (iPrinter->collateCopies()) {
            docCopies = 1;
            pageCopies = iPrinter->actualNumCopies();
        } else {
            docCopies = iPrinter->actualNumCopies();
            pageCopies = 1;
        }
        int fromPage = qMin(iPrinter->fromPage(), iPrinter->toPage());
        int toPage = qMax(iPrinter->fromPage(), iPrinter->toPage());

        // Compute the number of pages
        SKGTabWidget* tabs = SKGMainPanel::getMainPanel()->getTabWidget();
        int nbpages = tabs->count();

        if (fromPage == 0 && toPage == 0) {
            fromPage = 1;
            toPage = nbpages;
        }
        if (iPrinter->printRange() == QPrinter::CurrentPage) {
            fromPage = SKGMainPanel::getMainPanel()->currentPageIndex() + 1;
            toPage = fromPage;
        }

        SKGTRACEL(10) << "Nb copy document=" << docCopies << endl;
        SKGTRACEL(10) << "Nb copy page=" << docCopies << endl;
        SKGTRACEL(10) << "From=" << fromPage << endl;
        SKGTRACEL(10) << "To=" << toPage << endl;

        // Copy document
        QString html;
        for (int c = 1; !err && c <= docCopies; ++c) {
            for (int i = 1; !err && i <= nbpages; ++i) {
                // Compute page
                int pageToTreat = (iPrinter->pageOrder() == QPrinter::LastPageFirst ? nbpages + 1 - i : i);

                // Do we have to print it
                if (pageToTreat >= fromPage && pageToTreat <= toPage) {
                    // Yes, get the widget
                    // Copy pages
                    for (int p = 1; !err && p <= pageCopies; ++p) {
                        SKGTabPage* page = static_cast<SKGTabPage*>(tabs->widget(pageToTreat - 1));
                        if (page) {
                            // Add page break if needed
                            if (!html.isEmpty()) {
                                html = html % "<div style=\"page-break-after:always\"></div>";
                            }

                            // Add widgets
                            QList<QWidget*> widgets = page->printableWidgets();
                            int nbw = widgets.count();
                            for (int j = 0; !err && j < nbw; ++j) {
                                QWidget* w = widgets.at(j);
                                if (w) {
                                    // Add widget
                                    /*SKGTreeView* tw = qobject_cast< SKGTreeView* >(w);
                                    if (tw) {
                                        QTextBrowser* tb = tw->getTextBrowser();
                                        if (tb) {
                                            html = html % tb->toHtml();
                                            delete tb;
                                        }
                                    } else {*/
                                    QWebView* q = qobject_cast< QWebView* >(w);
                                    if (q) {
                                        html = html % q->page()->currentFrame()->toHtml();
                                    } else {
                                        // Save palette
                                        QPalette previousPalette = w->palette();

                                        // Draw in a picture with white background
                                        QImage image(w->size(), QImage::Format_ARGB32);
                                        QPainter painter2(&image);
                                        QPalette palette;
                                        palette.setColor(QPalette::Background, Qt::white);
                                        w->setPalette(palette);
                                        w->render(&painter2);
                                        painter2.end();

                                        // Restore palette
                                        w->setPalette(previousPalette);

                                        QByteArray byteArray;
                                        QBuffer buffer(&byteArray);
                                        image.save(&buffer, "PNG");

                                        QString imgBase64 = QString::fromLatin1(byteArray.toBase64().data());
                                        html = html % "<img src=\"data:image/png;base64," % imgBase64 % "\" />";
                                    }
                                    // }
                                }
                            }
                        }
                    }
                }
            }
        }

        // Print
        QWebView toPrint;
        toPrint.setHtml(html);
        toPrint.setFixedSize(QSize(iPrinter->width(), iPrinter->height()));
        qApp->processEvents(QEventLoop::AllEvents, 5000);

        toPrint.print(iPrinter);

        // status bar
        IFOKDO(err, SKGError(0, i18nc("Successful message after an user action", "Print successfully done.")))
        else {
            err.addError(ERR_FAIL, i18nc("Error message", "Print failed"));
        }

        // Display error
        SKGMainPanel::displayErrorMessage(err);
    }
}

#include <skgprintplugin.moc>
