/***************************************************************************
 *   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 for monthly report.
 *
 * @author Stephane MANKOWSKI
 */
#include "skgmonthlypluginwidget.h"

#include <kns3/downloaddialog.h>
#include <kns3/uploaddialog.h>
#include <kzip.h>
#include <kaboutdata.h>

#include <qmenu.h>
#include <qdom.h>
#include <qprinter.h>
#include <qprintdialog.h>
#include <qtextstream.h>
#include <qfile.h>
#include <qdir.h>
#include <qdesktopservices.h>
#include <qwebframe.h>
#include <qstandardpaths.h>
#include <qdiriterator.h>
#include <qvalidator.h>

#include "skgmainpanel.h"
#include "skgtraces.h"
#include "skgreport.h"
#include "skgtransactionmng.h"

SKGMonthlyPluginWidget::SKGMonthlyPluginWidget(SKGDocument* iDocument)
    : SKGTabPage(iDocument), m_upload(nullptr)
{
    SKGTRACEINFUNC(1);
    if (!iDocument) {
        return;
    }

    ui.setupUi(this);
    ui.kMonth->setMode(SKGSimplePeriodEdit::PREVIOUS_PERIODS | SKGSimplePeriodEdit::PREVIOUS_MONTHS);
    ui.kDeleteTemplate->hide();

    ui.kRefresh->setIcon(SKGServices::fromTheme(QStringLiteral("view-refresh")));
    ui.kGetNewHotStuff->setIcon(SKGServices::fromTheme(QStringLiteral("get-hot-new-stuff")));
    ui.kDeleteTemplate->setIcon(SKGServices::fromTheme(QStringLiteral("edit-delete")));

    auto newValidator = new QRegExpValidator(QRegExp(QStringLiteral("^[\\w\\s]+$")), this);
    ui.kTemplate->setValidator(newValidator);

    connect(getDocument(), &SKGDocument::tableModified, this, &SKGMonthlyPluginWidget::dataModified, Qt::QueuedConnection);
    connect(ui.kMonth, static_cast<void (SKGComboBox::*)(const QString&)>(&SKGComboBox::currentIndexChanged), this, &SKGMonthlyPluginWidget::onPeriodChanged, Qt::QueuedConnection);

    QStringList overlays;
    overlays.push_back(QStringLiteral("list-add"));
    m_upload = new QAction(SKGServices::fromTheme(QStringLiteral("get-hot-new-stuff"), overlays), i18n("Upload"), this);
    connect(m_upload, &QAction::triggered, this, &SKGMonthlyPluginWidget::onPutNewHotStuff);
    connect(ui.kWebView, &QWebView::linkClicked, [ = ](const QUrl & val) {
        SKGMainPanel::getMainPanel()->openPage(val);
    });

    auto menu = new QMenu();
    menu->addAction(m_upload);
    ui.kGetNewHotStuff->setMenu(menu);

    connect(ui.kDeleteTemplate, &QToolButton::clicked, this, &SKGMonthlyPluginWidget::onDeleteTemplate);
    connect(ui.kTemplate, static_cast<void (SKGComboBox::*)(const QString&)>(&SKGComboBox::returnPressed), this, &SKGMonthlyPluginWidget::onAddTemplate);
    connect(ui.kTemplate, &SKGComboBox::editTextChanged, this, &SKGMonthlyPluginWidget::onTemplateChanged);
    connect(ui.kGetNewHotStuff, &QToolButton::clicked, this, &SKGMonthlyPluginWidget::onGetNewHotStuff);
    connect(ui.kRefresh, &QToolButton::clicked, this, &SKGMonthlyPluginWidget::onPeriodChanged);

    // Refresh
    fillTemplateList();
    dataModified(QStringLiteral(""), 0);
}

SKGMonthlyPluginWidget::~SKGMonthlyPluginWidget()
{
    SKGTRACEINFUNC(1);
}

QString SKGMonthlyPluginWidget::getState()
{
    SKGTRACEINFUNC(10);
    QDomDocument doc(QStringLiteral("SKGML"));
    QDomElement root = doc.createElement(QStringLiteral("parameters"));
    doc.appendChild(root);

    // Get state
    root.setAttribute(QStringLiteral("month"), ui.kMonth->text());
    root.setAttribute(QStringLiteral("template"), ui.kTemplate->text());
    root.setAttribute(QStringLiteral("web"), ui.kWebView->getState());

    return doc.toString();
}

void SKGMonthlyPluginWidget::setState(const QString& iState)
{
    SKGTRACEINFUNC(10);
    QDomDocument doc(QStringLiteral("SKGML"));
    doc.setContent(iState);
    QDomElement root = doc.documentElement();

    // Set state
    QString webS = root.attribute(QStringLiteral("web"));
    if (!webS.isEmpty()) {
        ui.kWebView->setState(webS);
    }

    QString templat = root.attribute(QStringLiteral("template"));
    if (!templat.isEmpty()) {
        bool p = ui.kTemplate->blockSignals(true);
        ui.kTemplate->setText(templat);
        ui.kTemplate->blockSignals(p);
        onTemplateChanged();
    }

    QString month = root.attribute(QStringLiteral("month"));
    if (!month.isEmpty()) {
        ui.kMonth->setText(month);
    }
    onPeriodChanged();
}

QString SKGMonthlyPluginWidget::getDefaultStateAttribute()
{
    return QStringLiteral("SKGMONTHLY_DEFAULT_PARAMETERS");
}

QWidget* SKGMonthlyPluginWidget::mainWidget()
{
    return ui.kWebView;
}

void SKGMonthlyPluginWidget::fillTemplateList()
{
    disconnect(ui.kTemplate, static_cast<void (SKGComboBox::*)(const QString&)>(&SKGComboBox::currentIndexChanged), this, &SKGMonthlyPluginWidget::onPeriodChanged);
    // Get previous selected item
    QString current = ui.kTemplate->text();

    // Fill
    ui.kTemplate->clear();
    const auto dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, KAboutData::applicationData().componentName() % "/html", QStandardPaths::LocateDirectory);
    for (const auto& dir : dirs) {
        QDirIterator it(dir, QStringList() << QStringLiteral("*.txt"));
        while (it.hasNext()) {
            QString file = it.next();

            QFileInfo f(file);
            QString file2 = f.completeBaseName();
            if (!ui.kTemplate->contains(file2) && file2 != QStringLiteral("main")) {
                ui.kTemplate->addItem(file2, file);
            }
        }
    }

    // Set previous selected itemData
    if (!current.isEmpty() && ui.kTemplate->contains(current)) {
        ui.kTemplate->setCurrentItem(current);
    }
    connect(ui.kTemplate, static_cast<void (SKGComboBox::*)(const QString&)>(&SKGComboBox::currentIndexChanged), this, &SKGMonthlyPluginWidget::onPeriodChanged, Qt::QueuedConnection);
}

void SKGMonthlyPluginWidget::onAddTemplate()
{
    QString templat = ui.kTemplate->text().trimmed();
    QString templateDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + KAboutData::applicationData().componentName();
    QString templatFileName = templateDir % "/html/" % templat % ".txt";
    QStringList templates;
    const auto dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, KAboutData::applicationData().componentName() % "/html", QStandardPaths::LocateDirectory);
    for (const auto& dir : dirs) {
        QDirIterator it(dir, QStringList() << QStringLiteral("*.txt"));
        while (it.hasNext()) {
            templates.append(it.next());
        }
    }

    if (!templat.isEmpty() && (!templates.contains(templatFileName) || QFileInfo(templatFileName).isWritable())) {
        SKGError err;
        if (!templates.contains(templatFileName)) {
            // Create the new template
            QString source = QStandardPaths::locate(QStandardPaths::GenericDataLocation, KAboutData::applicationData().componentName() % "/html/tutorial.txt");
            QDir(templateDir).mkpath(QStringLiteral("html"));
            if (SKGServices::upload(QUrl::fromLocalFile(source), QUrl::fromLocalFile(templatFileName))) {
                err.setReturnCode(ERR_FAIL).setMessage(i18nc("An error message", "Impossible to copy file from '%1' to '%2'", source, templatFileName));
            } else {
                fillTemplateList();
            }
        }

        // Open the created or already existing file
        QDesktopServices::openUrl(QUrl::fromLocalFile(templatFileName));

        onTemplateChanged();

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

void SKGMonthlyPluginWidget::onDeleteTemplate()
{
    QString templat = ui.kTemplate->text().trimmed();
    QString templatFileName = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + KAboutData::applicationData().componentName() % "/html/" % templat % ".txt";
    if (!templat.isEmpty()) {
        // This is a new source
        SKGError err;

        // Delete the file
        QFile file(templatFileName);
        if (!file.remove()) {
            err.setReturnCode(ERR_INVALIDARG).setMessage(i18nc("Error message",  "Deletion of '%1' failed", templatFileName));
        }

        IFOK(err) ui.kTemplate->removeItem(ui.kTemplate->findText(templat));

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

void SKGMonthlyPluginWidget::onTemplateChanged()
{
    QString templat = ui.kTemplate->text().trimmed();
    QString templatFileName = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + KAboutData::applicationData().componentName() % "/html/" % templat % ".txt";
    bool local = !templat.isEmpty() && QFileInfo(templatFileName).isWritable();
    ui.kDeleteTemplate->setVisible(local);
    m_upload->setEnabled(local);
}

void SKGMonthlyPluginWidget::dataModified(const QString& iTableName, int iIdTransaction)
{
    SKGTRACEINFUNC(1);
    Q_UNUSED(iIdTransaction);

    QSqlDatabase* db = getDocument()->getDatabase();
    setEnabled(db != nullptr);
    // TODO(Stephane MANKOWSKI): v_operation_display must be generic
    if (db != nullptr && (iTableName == QStringLiteral("v_operation_display") || iTableName.isEmpty())) {
        // Fill combo

        QDate date = QDate::currentDate();
        QStringList list;
        // TODO(Stephane MANKOWSKI): v_operation_display must be generic
        getDocument()->getDistinctValues(QStringLiteral("v_operation_display"), QStringLiteral("MIN(d_DATEMONTH)"), QStringLiteral("d_date<=CURRENT_DATE"), list);
        if (!list.isEmpty()) {
            if (!list[0].isEmpty()) {
                date = SKGServices::periodToDate(list[0]);
            }
        }

        ui.kMonth->setFirstDate(date);
        ui.kRefresh->setEnabled(!list.isEmpty());
    }
}

QString SKGMonthlyPluginWidget::getPeriod()
{
    return ui.kMonth->period();
}

void SKGMonthlyPluginWidget::onPeriodChanged()
{
    SKGTRACEINFUNC(1);
    QString month = getPeriod();
    if (!month.isEmpty()) {
        // Display report
        QString htmlReport = getDocument()->getParameter("SKG_MONTHLY_REPORT_" % month);
        if (htmlReport.isEmpty() || sender() == ui.kRefresh || sender() == ui.kTemplate) {
            SKGError err;
            SKGBEGINLIGHTTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Compute monthly report for '%1'", month), err);
            htmlReport = getReport();
            err = getDocument()->setParameter("SKG_MONTHLY_REPORT_" % month, htmlReport);
        }

        // Display html report
        ui.kWebView->setHtml(htmlReport);
        ui.kWebView->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
    }
}

void SKGMonthlyPluginWidget::onGetNewHotStuff()
{
    QPointer<KNS3::DownloadDialog> dialog = new KNS3::DownloadDialog(KAboutData::applicationData().componentName() % "_monthly.knsrc", this);
    dialog->exec();
    delete dialog;

    fillTemplateList();
}

void SKGMonthlyPluginWidget::onPutNewHotStuff()
{
    QString templat = ui.kTemplate->text().trimmed();

    // Create zip file
    QString templatFileName = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + KAboutData::applicationData().componentName() % "/html/" % templat % ".txt";
    QString templatHFileName = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + KAboutData::applicationData().componentName() % "/html/" % templat % ".html";
    QString zipFileName = QDir::tempPath() % "/" % templat % ".zip";
    KZip zip(zipFileName);
    if (zip.open(QIODevice::WriteOnly)) {
        zip.addLocalFile(templatFileName, templat % ".txt");
        if (QFile(templatHFileName).exists()) {
            zip.addLocalFile(templatHFileName, templat % ".html");
        }
        zip.close();

        // Create screen shots
        QWebFrame* frame = ui.kWebView->page()->mainFrame();
        QString preview2 = QDir::tempPath() % "/" % templat % "_preview2.png";
        frame->setScrollBarValue(Qt::Vertical, frame->scrollBarMaximum(Qt::Vertical));
        ui.kWebView->exportInFile(preview2);

        QString preview3 = QDir::tempPath() % "/" % templat % "_preview3.png";
        frame->setScrollBarValue(Qt::Vertical, frame->scrollBarMaximum(Qt::Vertical) / 2);
        ui.kWebView->exportInFile(preview3);

        QString preview1 = QDir::tempPath() % "/" % templat % "_preview1.png";
        frame->setScrollBarValue(Qt::Vertical, 0);
        ui.kWebView->exportInFile(preview1);

        // Open dialog
        QPointer<KNS3::UploadDialog> dialog = new KNS3::UploadDialog(KAboutData::applicationData().componentName() % "_monthly.knsrc", this);

        dialog->setUploadFile(QUrl::fromLocalFile(zipFileName));
        dialog->setUploadName(templat);
        dialog->setPreviewImageFile(0, QUrl::fromLocalFile(preview1));
        dialog->setPreviewImageFile(1, QUrl::fromLocalFile(preview2));
        dialog->setPreviewImageFile(2, QUrl::fromLocalFile(preview3));
        dialog->setDescription(i18nc("Default description for a monthly report template", "My favorite template"));
        dialog->setVersion(QStringLiteral("0.1"));
        dialog->setChangelog(QStringLiteral("V0.1 - Initial version"));
        dialog->exec();
        delete dialog;

        // Delete temporary files
        QFile(zipFileName).remove();
        QFile(preview1).remove();
        QFile(preview2).remove();
        QFile(preview3).remove();
    }
}

QString SKGMonthlyPluginWidget::getReport()
{
    QString html;
    SKGError err;
    SKGTRACEINFUNCRC(10, err);
    QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));

    // Get period
    if (!getPeriod().isEmpty()) {
        SKGReport* rep = getDocument()->getReport();
        if (rep) {
            rep->setPeriod(getPeriod());
            err = rep->getReportFromTemplate(rep, ui.kTemplate->itemData(ui.kTemplate->currentIndex()).toString(), html);

            delete rep;
        }
    }
    QApplication::restoreOverrideCursor();

    // status bar
    IFKO(err) html += err.getFullMessageWithHistorical();
    return html;
}


