/***************************************************************************
 *   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
 * This file is Skrooge plugin to generate report.
 *
 * @author Stephane MANKOWSKI / Guillaume DE BURE
 */
#include "skgreportplugin.h"

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

#include <qdom.h>

#include "skgreportpluginwidget.h"
#include "skgtraces.h"
#include "skgmainpanel.h"
#include "skgservices.h"
#include "skgaccountobject.h"
#include "skgcategoryobject.h"
#include "skgtrackerobject.h"
#include "skgunitobject.h"
#include "skgruleobject.h"
#include "skgpayeeobject.h"
#include "skgnodeobject.h"
#include "skgreportboardwidget.h"
#include "skgdocumentbank.h"
#include "skghtmlboardwidget.h"
#include "skgreport_settings.h"

/**
 * This plugin factory.
 */
K_PLUGIN_FACTORY(SKGReportPluginFactory, registerPlugin<SKGReportPlugin>();)

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

SKGReportPlugin::~SKGReportPlugin()
{
    SKGTRACEINFUNC(10);
    m_currentBankDocument = nullptr;
}

bool SKGReportPlugin::setupActions(SKGDocument* iDocument, const QStringList& iArgument)
{
    SKGTRACEINFUNC(10);
    Q_UNUSED(iArgument);
    m_currentBankDocument = qobject_cast<SKGDocumentBank*>(iDocument);
    if (m_currentBankDocument == nullptr) {
        return false;
    }

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

    // Menu
    QStringList overlayopen;
    overlayopen.push_back(QStringLiteral("quickopen"));
    auto actOpenReport = new QAction(SKGServices::fromTheme(QStringLiteral("view-statistics"), overlayopen), i18nc("Verb", "Open report..."), this);
    connect(actOpenReport, &QAction::triggered, this, &SKGReportPlugin::onOpenReport);
    actionCollection()->setDefaultShortcut(actOpenReport, Qt::META + Qt::Key_R);
    registerGlobalAction(QStringLiteral("open_report"), actOpenReport,
                         QStringList() << QStringLiteral("operation") << QStringLiteral("suboperation") << QStringLiteral("account") << QStringLiteral("unit") << QStringLiteral("category") << QStringLiteral("refund") << QStringLiteral("payee") << QStringLiteral("rule"), 1, -1, 120);


    // ---------------
    {
        auto act = new QAction(SKGServices::fromTheme(QStringLiteral("security-low"), overlayopen), i18nc("Verb", "Open very old operations..."), this);
        act->setData(QString("skg://skrooge_operation_plugin/?title_icon=security-low&title=" %
                             SKGServices::encodeForUrl(i18nc("Noun, a list of items", "Very old operations")) %
                             "&operationWhereClause=" % SKGServices::encodeForUrl(QStringLiteral("d_date<=(SELECT date('now', '-50 year')) AND d_date<>'0000-00-00'"))));
        connect(act, &QAction::triggered, SKGMainPanel::getMainPanel(),  [ = ]() {
            SKGMainPanel::getMainPanel()->openPage();
        });
        registerGlobalAction(QStringLiteral("view_open_very_old_operations"), act);
    }

    // ---------------
    {
        auto act = new QAction(SKGServices::fromTheme(QStringLiteral("security-low"), overlayopen), i18nc("Verb", "Open very far operations in the future..."), this);
        act->setData(QString("skg://skrooge_operation_plugin/?title_icon=security-low&title=" %
                             SKGServices::encodeForUrl(i18nc("Noun, a list of items", "Very far operations in the future")) %
                             "&operationWhereClause=" % SKGServices::encodeForUrl(QStringLiteral("d_date>=(SELECT date('now', '+50 year'))"))));
        connect(act, &QAction::triggered, SKGMainPanel::getMainPanel(),  [ = ]() {
            SKGMainPanel::getMainPanel()->openPage();
        });
        registerGlobalAction(QStringLiteral("view_open_very_far_operations"), act);
    }
    return true;
}

int SKGReportPlugin::getNbDashboardWidgets()
{
    return 2;
}

QString SKGReportPlugin::getDashboardWidgetTitle(int iIndex)
{
    Q_UNUSED(iIndex);
    if (iIndex == 0)  {
        return i18nc("Noun, the title of a section", "Report");
    }
    return i18nc("Dashboard header",  "Personal Financial Score");
}

SKGBoardWidget* SKGReportPlugin::getDashboardWidget(int iIndex)
{
    Q_UNUSED(iIndex);
    if (iIndex == 0)  {
        return new SKGReportBoardWidget(SKGMainPanel::getMainPanel(), m_currentBankDocument);
    }
    // Get QML mode for dashboard
    KConfigSkeleton* skl = SKGMainPanel::getMainPanel()->getPluginByName(QStringLiteral("Dashboard plugin"))->getPreferenceSkeleton();
    KConfigSkeletonItem* sklItem = skl->findItem(QStringLiteral("qmlmode"));
    bool qml = sklItem->property().toBool();

    return new SKGHtmlBoardWidget(SKGMainPanel::getMainPanel(), m_currentBankDocument,
                                  getDashboardWidgetTitle(iIndex) % " - %1",
                                  QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("skrooge/html/default/personal_finance_score.") % (qml ?  QStringLiteral("qml") :  QStringLiteral("html"))),
                                  QStringList() << QStringLiteral("v_suboperation_consolidated"), SKGSimplePeriodEdit::PREVIOUS_MONTHS);
}

SKGTabPage* SKGReportPlugin::getWidget()
{
    SKGTRACEINFUNC(10);
    return new SKGReportPluginWidget(SKGMainPanel::getMainPanel(), m_currentBankDocument);
}

QWidget* SKGReportPlugin::getPreferenceWidget()
{
    SKGTRACEINFUNC(10);
    auto w = new QWidget();
    ui.setupUi(w);
    return w;
}

KConfigSkeleton* SKGReportPlugin::getPreferenceSkeleton()
{
    return skgreport_settings::self();
}

QString SKGReportPlugin::title() const
{
    return i18nc("Noun", "Report");
}

QString SKGReportPlugin::icon() const
{
    return QStringLiteral("view-statistics");
}

QString SKGReportPlugin::toolTip() const
{
    return i18nc("Noun", "Generate report");
}

int SKGReportPlugin::getOrder() const
{
    return 40;
}

QStringList SKGReportPlugin::tips() const
{
    QStringList output;
    output.push_back(i18nc("Description of a tips", "<p>... you can double click on a value in '%1' to show corresponding operations.</p>", title()));
    output.push_back(i18nc("Description of a tips", "<p>... you can open reports for selections made in other pages.</p>"));
    output.push_back(i18nc("Description of a tips", "<p>... you can export reports in many formats.</p>"));
    return output;
}

bool SKGReportPlugin::isInPagesChooser() const
{
    return true;
}

void SKGReportPlugin::getTitleAndWhereClause(const SKGObjectBase::SKGListSKGObjectBase& iSelection, QString& oTitle, QString& oWhereClause) const
{
    int nb = iSelection.count();
    if (nb > 0) {
        QString table = iSelection.at(0).getRealTable();
        if (table == QStringLiteral("account")) {
            oWhereClause = QStringLiteral("rd_account_id in (");
            oTitle = i18nc("Noun, a list of items", "Operations of account ");

            for (int i = 0; i < nb; ++i) {
                SKGAccountObject tmp(iSelection.at(i));
                if (i) {
                    oWhereClause += ',';
                    oTitle += ',';
                }
                oWhereClause += SKGServices::intToString(tmp.getID());
                oTitle += i18n("'%1'", tmp.getName());
            }
            oWhereClause += ')';
        } else if (table == QStringLiteral("unit")) {
            oWhereClause = QStringLiteral("rc_unit_id in (");
            oTitle = i18nc("Noun, a list of items", "Operations with Unit equal to ");

            for (int i = 0; i < nb; ++i) {
                SKGUnitObject tmp(iSelection.at(i));
                if (i) {
                    oWhereClause += ',';
                    oTitle += ',';
                }
                oWhereClause += SKGServices::intToString(tmp.getID());
                oTitle += i18n("'%1'", tmp.getName());
            }
            oWhereClause += ')';
        } else if (table == QStringLiteral("category")) {
            oWhereClause = QStringLiteral("t_REALCATEGORY in (");
            QString wc2;
            oTitle = i18nc("Noun, a list of items", "Operations with Category equal to ");

            for (int i = 0; i < nb; ++i) {
                SKGCategoryObject tmp(iSelection.at(i));
                if (i) {
                    oWhereClause += ',';
                    wc2 += QStringLiteral(" OR ");
                    oTitle += ',';
                }
                oWhereClause += '\'' % SKGServices::stringToSqlString(tmp.getFullName()) % '\'';
                wc2 += "t_REALCATEGORY like '" % SKGServices::stringToSqlString(tmp.getFullName()) % "%'";
                oTitle += i18n("'%1'", tmp.getFullName());
            }
            oWhereClause += ") OR " % wc2;
        } else if (table == QStringLiteral("refund")) {
            oWhereClause = QStringLiteral("r_refund_id in (");
            oTitle = i18nc("Noun, a list of items", "Operations followed by ");

            for (int i = 0; i < nb; ++i) {
                SKGTrackerObject tmp(iSelection.at(i));
                if (i) {
                    oWhereClause += ',';
                    oTitle += ',';
                }
                oWhereClause += SKGServices::intToString(tmp.getID());
                oTitle += i18n("'%1'", tmp.getName());
            }
            oWhereClause += ')';
        } else if (table == QStringLiteral("payee")) {
            oWhereClause = QStringLiteral("r_payee_id in (");
            oTitle = i18nc("Noun, a list of items", "Operations assigned to ");

            for (int i = 0; i < nb; ++i) {
                SKGPayeeObject tmp(iSelection.at(i));
                if (i) {
                    oWhereClause += ',';
                    oTitle += ',';
                }
                oWhereClause += SKGServices::intToString(tmp.getID());
                oTitle += i18n("'%1'", tmp.getName());
            }
            oWhereClause += ')';
        } else if (table == QStringLiteral("operation")) {
            oWhereClause = QStringLiteral("i_OPID in (");
            oTitle = i18nc("Noun, a list of items", "Selected operations");

            for (int i = 0; i < nb; ++i) {
                if (i) {
                    oWhereClause += ',';
                }
                oWhereClause += SKGServices::intToString(iSelection.at(i).getID());
            }
            oWhereClause += ')';
        } else if (table == QStringLiteral("suboperation")) {
            oWhereClause = QStringLiteral("i_SUBOPID in (");
            oTitle = i18nc("Noun, a list of items", "Selected sub operations");

            for (int i = 0; i < nb; ++i) {
                if (i) {
                    oWhereClause += ',';
                }
                oWhereClause += SKGServices::intToString(iSelection.at(i).getID());
            }
            oWhereClause += ')';
        } else if (table == QStringLiteral("rule")) {
            oTitle = i18nc("Noun, a list of items", "Operations corresponding to rule ");

            for (int i = 0; i < nb; ++i) {
                SKGRuleObject tmp(iSelection.at(i));
                QString ruleWc = tmp.getSelectSqlOrder();
                if (!ruleWc.isEmpty()) {
                    if (!oWhereClause.isEmpty()) {
                        oWhereClause += QStringLiteral(" OR ");
                        oTitle += ',';
                    }
                    oWhereClause += '(' % ruleWc % ')';
                    oTitle += i18n("'%1'", tmp.getSearchDescription());
                }
            }
        }
    }
}


void SKGReportPlugin::onOpenReport()
{
    SKGError err;
    SKGTRACEINFUNCRC(10, err);
    if (SKGMainPanel::getMainPanel()) {
        SKGObjectBase::SKGListSKGObjectBase selection = SKGMainPanel::getMainPanel()->getSelectedObjects();

        int nb = selection.count();
        if (nb > 0) {
            QString titleTable;
            QString wc;
            getTitleAndWhereClause(selection, titleTable, wc);

            // Call report plugin
            SKGMainPanel::getMainPanel()->openPage("skg://skrooge_report_plugin/?period=0&title_icon=" % icon() % "&title=" % SKGServices::encodeForUrl(titleTable) % "&operationWhereClause=" % SKGServices::encodeForUrl(wc));
        }
    }
}

SKGAdviceList SKGReportPlugin::advice(const QStringList& iIgnoredAdvice)
{
    SKGTRACEINFUNC(10);
    SKGAdviceList output;

    // Very old operation
    if (!iIgnoredAdvice.contains(QStringLiteral("skgreportplugin_veryold"))) {
        bool exist = false;
        m_currentBankDocument->existObjects(QStringLiteral("operation"), QStringLiteral("d_date<=(SELECT date('now', '-50 year')) AND d_date<>'0000-00-00'"), exist);
        if (exist) {
            SKGAdvice ad;
            ad.setUUID(QStringLiteral("skgreportplugin_veryold"));
            ad.setPriority(3);
            ad.setShortMessage(i18nc("Advice on making the best (short)", "Some operations are very old"));
            ad.setLongMessage(i18nc("Advice on making the best (long)", "For performances reasons, very old operations are not taken into account in graph report. Check if these operations are normal."));
            QStringList autoCorrections;
            autoCorrections.push_back(QStringLiteral("skg://view_open_very_old_operations"));
            ad.setAutoCorrections(autoCorrections);
            output.push_back(ad);
        }
    }

    // Very far operation
    if (!iIgnoredAdvice.contains(QStringLiteral("skgreportplugin_veryfar"))) {
        bool exist = false;
        m_currentBankDocument->existObjects(QStringLiteral("operation"), QStringLiteral("d_date>=(SELECT date('now', '+50 year'))"), exist);
        if (exist) {
            SKGAdvice ad;
            ad.setUUID(QStringLiteral("skgreportplugin_veryfar"));
            ad.setPriority(3);
            ad.setShortMessage(i18nc("Advice on making the best (short)", "Some operations are very far in the future"));
            ad.setLongMessage(i18nc("Advice on making the best (long)", "For performances reasons, operations very far in the future are not taken into account in graph report. Check if these operations are normal."));
            QStringList autoCorrections;
            autoCorrections.push_back(QStringLiteral("skg://view_open_very_far_operations"));
            ad.setAutoCorrections(autoCorrections);
            output.push_back(ad);
        }
    }
    return output;
}

#include <skgreportplugin.moc>
