/***************************************************************************
 *   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 skrooge plugin to manage budgets
 *
 * @author Stephane MANKOWSKI
 */
#include "skgbudgetplugin.h"

#include <KActionCollection>
#include <KStandardAction>
#include <kaboutdata.h>
#include <kpluginfactory.h>
#include <klocalizedstring.h>

#include "skgbudgetpluginwidget.h"
#include "skgbudgetobject.h"
#include "skgdocumentbank.h"
#include "skgtransactionmng.h"
#include "skgbudgetruleobject.h"
#include "skgtraces.h"
#include "skgmainpanel.h"

/**
 * This plugin factory.
 */
K_PLUGIN_FACTORY(SKGBudgetPluginFactory, registerPlugin<SKGBudgetPlugin>();)

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

SKGBudgetPlugin::~SKGBudgetPlugin()
{
    SKGTRACEINFUNC(10);
    m_currentBankDocument = NULL;
}

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

    setComponentName("skrooge_budget", title());
    setXMLFile("skrooge_budget.rc");

    // Create yours actions here
    // -----------
    QStringList overlayrun;
    overlayrun.push_back("system-run");
    QAction* act = new QAction(SKGServices::fromTheme(icon(), overlayrun), i18nc("Verb", "Process budget rules"), this);
    connect(act, &QAction::triggered, this, &SKGBudgetPlugin::onProcessRules);
    registerGlobalAction("tool_process_budget_rules", act);
    return true;
}

SKGTabPage* SKGBudgetPlugin::getWidget()
{
    SKGTRACEINFUNC(10);
    return new SKGBudgetPluginWidget(m_currentBankDocument);
}

QString SKGBudgetPlugin::title() const
{
    return i18nc("The title", "Budget");
}

QString SKGBudgetPlugin::icon() const
{
    return "view-calendar-whatsnext";
}

QString SKGBudgetPlugin::toolTip() const
{
    return i18nc("The tool tip", "Budget");
}

int SKGBudgetPlugin::getOrder() const
{
    return 32;
}

QStringList SKGBudgetPlugin::tips() const
{
    QStringList output;
    return output;
}

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

SKGAdviceList SKGBudgetPlugin::advice(const QStringList& iIgnoredAdvice)
{
    SKGTRACEINFUNC(10);
    SKGAdviceList output;
    QString month = QDate::currentDate().toString("yyyy-MM");
    QString year = QDate::currentDate().toString("yyyy");

    // Alarms
    if (!iIgnoredAdvice.contains("skgbudgetplugin_alarm")) {
        SKGObjectBase::SKGListSKGObjectBase budgets;
        // Query is done on v_budget_display because v_budget_display is faster than v_budget
        SKGError err = m_currentBankDocument->getObjects("v_budget_display", "(f_CURRENTAMOUNT/f_budgeted_modified>0.8 OR (f_CURRENTAMOUNT<0 AND f_budgeted_modified>0)) AND ABS(f_CURRENTAMOUNT-f_budgeted_modified)>" % SKGServices::doubleToString(EPSILON) % " AND f_budgeted<0 AND (t_PERIOD='" % month % "' OR t_PERIOD='" % year % "');", budgets);
        int nb = budgets.count();
        if (nb) {
            SKGServices::SKGUnitInfo primary = m_currentBankDocument->getPrimaryUnit();

            for (int i = 0; !err && i < nb; ++i) {
                SKGBudgetObject budget(budgets.at(i));
                double f_CURRENTAMOUNT = SKGServices::stringToDouble(budget.getAttribute("f_CURRENTAMOUNT"));
                double f_budgeted_modified = SKGServices::stringToDouble(budget.getAttribute("f_budgeted_modified"));

                SKGAdvice ad;
                ad.setUUID("skgbudgetplugin_alarm|" % SKGServices::intToString(budget.getID()));
                ad.setPriority((f_CURRENTAMOUNT < f_budgeted_modified ? 9 : 6));
                ad.setShortMessage(i18nc("Advice on making the best (short)", "Budget alarm for '%1'", budget.getAttribute("t_CATEGORY")));
                ad.setLongMessage(i18nc("Advice on making the best (long)", "Take care to your budget.<br> %1.<br>%2 / %3",
                                        budget.getAttribute("t_CATEGORY"),
                                        m_currentBankDocument->formatMoney(f_CURRENTAMOUNT, primary),
                                        m_currentBankDocument->formatMoney(f_budgeted_modified, primary)));
                QList<SKGAdvice::SKGAdviceAction> autoCorrections;
                {
                    SKGAdvice::SKGAdviceAction a;
                    a.Title = i18nc("Advice on making the best (action)", "Open operations corresponding to this budget");
                    a.IconName = "quickopen";
                    a.IsRecommended = false;
                    autoCorrections.push_back(a);
                }
                ad.setAutoCorrections(autoCorrections);
                output.push_back(ad);
            }
        }
    }

    if (!iIgnoredAdvice.contains("skgbudgetplugin_oldprocessing")) {
        QString lastBudgetProcessingDate = m_currentBankDocument->getParameter("SKG_LAST_BUDGET_PROCESSING");
        if (lastBudgetProcessingDate.isEmpty() ||  SKGServices::stringToTime(lastBudgetProcessingDate).date() < QDate::currentDate().addMonths(-1)) {  // Ignore header
            bool exist = false;
            m_currentBankDocument->existObjects("budgetrule", "", exist);
            if (exist) {
                SKGAdvice ad;
                ad.setUUID("skgbudgetplugin_oldprocessing");
                ad.setPriority(3);
                ad.setShortMessage(i18nc("Advice on making the best (short)", "Old budget treatment"));
                ad.setLongMessage(i18nc("Advice on making the best (long)", "The budget has not been treated for at least one month."));
                QList<SKGAdvice::SKGAdviceAction> autoCorrections;
                {
                    SKGAdvice::SKGAdviceAction a;
                    a.Title = "skg://tool_process_budget_rules";
                    a.IsRecommended = true;
                    autoCorrections.push_back(a);
                }
                ad.setAutoCorrections(autoCorrections);
                output.push_back(ad);
            }
        }
    }

    return output;
}
SKGError SKGBudgetPlugin::executeAdviceCorrection(const QString& iAdviceIdentifier, int iSolution)
{
    if (m_currentBankDocument && iAdviceIdentifier.startsWith(QLatin1String("skgbudgetplugin_alarm|"))) {
        // Get parameters
        QString id = iAdviceIdentifier.right(iAdviceIdentifier.length() - 22);
        SKGBudgetObject budget(m_currentBankDocument, SKGServices::stringToInt(id));
        budget.load();

        QAction* act = SKGMainPanel::getMainPanel()->getGlobalAction("open");
        if (act) {
            act->setData(budget.getUniqueID());
            act->trigger();
        }

        return SKGError();
    }
    return SKGInterfacePlugin::executeAdviceCorrection(iAdviceIdentifier, iSolution);
}

void SKGBudgetPlugin::onProcessRules()
{
    SKGError err;
    _SKGTRACEINFUNCRC(10, err);

    {
        SKGBEGINTRANSACTION(*m_currentBankDocument, i18nc("Noun, name of the user action", "Process budget rules")  , err);
        err = SKGBudgetRuleObject::processAllRules(m_currentBankDocument);
    }
    // status bar
    IFOK(err) {
        err = SKGError(0, i18nc("Successful message after an user action", "Budget rules processed"));
    } else {
        err.addError(ERR_FAIL, i18nc("Error message", "Budget rules failed"));
    }

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

#include <skgbudgetplugin.moc>
