/***************************************************************************
 *   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 search and process operations
 *
 * @author Stephane MANKOWSKI
 */
#include "skgsearchplugin.h"
#include "skgsearchpluginwidget.h"
#include "skgsearch_settings.h"
#include "skgtraces.h"
#include "skgerror.h"
#include "skgruleobject.h"
#include "skgmainpanel.h"
#include "skgtransactionmng.h"
#include "skgalarmboardwidget.h"
#include "skgdocumentbank.h"
#include "skgcategoryobject.h"

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

/**
 * This plugin factory.
 */
K_PLUGIN_FACTORY(SKGSearchPluginFactory, registerPlugin<SKGSearchPlugin>();)
/**
 * This plugin export.
 */
K_EXPORT_PLUGIN(SKGSearchPluginFactory("skrooge_search", "skrooge_search"))

SKGSearchPlugin::SKGSearchPlugin(QObject* iParent, const QVariantList& /*iArg*/) : SKGInterfacePlugin(iParent)
{
    SKGTRACEIN(10, "SKGSearchPlugin::SKGSearchPlugin");
    m_timer.setSingleShot(true);
    connect(&m_timer, SIGNAL(timeout()), this, SLOT(raiseAlarms()));
}

SKGSearchPlugin::~SKGSearchPlugin()
{
    SKGTRACEIN(10, "SKGSearchPlugin::~SKGSearchPlugin");
    m_currentBankDocument = NULL;
    m_executeAll = NULL;
    m_executeImported = NULL;
    m_executeNotValidated = NULL;
    m_searchAction = NULL;
}

int SKGSearchPlugin::getNbDashboardWidgets()
{
    return 1;
}

QString SKGSearchPlugin::getDashboardWidgetTitle(int iIndex)
{
    if (iIndex == 0) return i18nc("Noun, alarms", "Alarms");
    return "";
}

SKGWidget* SKGSearchPlugin::getDashboardWidget(int iIndex)
{
    if (iIndex == 0) return new SKGAlarmBoardWidget(m_currentBankDocument);
    return NULL;
}

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

    setComponentData(KGlobal::mainComponent());
    setXMLFile("../skrooge_search/skrooge_search.rc");

    //Create yours actions here
    //Execute on all operation
    m_executeAll = new KAction(KIcon("system-run"), i18nc("Verb, action to execute", "Execute on all operations"), this);
    connect(m_executeAll, SIGNAL(triggered(bool)), SLOT(execute()));
    actionCollection()->addAction(QLatin1String("execute_all"), m_executeAll);

    if (SKGMainPanel::getMainPanel()) SKGMainPanel::getMainPanel()->registerGlobalAction("execute_all", m_executeAll);

    //Execute on imported operation
    {
        QStringList overlaycsv;
        overlaycsv.push_back("document-import");
        m_executeImported = new KAction(KIcon("system-run", NULL, overlaycsv), i18nc("Verb, action to execute", "Execute on imported operations"), this);
        connect(m_executeImported, SIGNAL(triggered(bool)), SLOT(execute()));
        actionCollection()->addAction(QLatin1String("execute_imported"), m_executeImported);

        if (SKGMainPanel::getMainPanel()) SKGMainPanel::getMainPanel()->registerGlobalAction("execute_imported", m_executeImported);
    }

    //Execute on not validated
    {
        QStringList overlaycsv;
        overlaycsv.push_back("dialog-ok-apply");
        m_executeNotValidated = new KAction(KIcon("system-run", NULL, overlaycsv), i18nc("Verb, action to execute", "Execute on not validated operations"), this);
        connect(m_executeNotValidated, SIGNAL(triggered(bool)), SLOT(execute()));
        actionCollection()->addAction(QLatin1String("execute_not_validated"), m_executeNotValidated);

        if (SKGMainPanel::getMainPanel()) SKGMainPanel::getMainPanel()->registerGlobalAction("execute_not_validated", m_executeNotValidated);
    }

    //Search
    m_searchAction = actionCollection()->addAction(KStandardAction::Find, "edit_find", this, SLOT(find()));

    if (SKGMainPanel::getMainPanel()) SKGMainPanel::getMainPanel()->registerGlobalAction("edit_find", m_searchAction);

    return true;
}

void SKGSearchPlugin::refresh()
{
    SKGTRACEIN(10, "SKGSearchPlugin::refresh");
    if (SKGMainPanel::getMainPanel()) {
        if (SKGMainPanel::getMainPanel()) {
            bool test = (SKGMainPanel::getMainPanel()->getSelectedObjects().count() > 0);
            if (m_executeImported) m_executeImported->setEnabled(test);
            if (m_executeAll) m_executeAll->setEnabled(test);
            if (m_executeNotValidated) m_executeNotValidated->setEnabled(test);
        }

        //Start alarm
        if (m_currentBankDocument && m_currentBankDocument->getDatabase() != NULL) {
            QString doc_id = m_currentBankDocument->getUniqueIdentifier();
            if (m_docUniqueIdentifier != doc_id) {
                m_docUniqueIdentifier = doc_id;

                raiseAlarms();
            }
        }
    }
}

void SKGSearchPlugin::raiseAlarms()
{
    if (m_currentBankDocument) {
        SKGObjectBase::SKGListSKGObjectBase rules;
        SKGError err = m_currentBankDocument->getObjects("v_rule", "t_action_type='A' ORDER BY i_ORDER", rules);
        int nb = rules.count();
        if (!err && nb) {
            for (int i = 0; !err && i < nb; ++i) {
                SKGRuleObject rule = rules.at(i);
                rule.execute();
            }
        }

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

        m_timer.start(skgsearch_settings::alarm_frequency() * 60 * 1000);
    }
}

void SKGSearchPlugin::execute()
{
    SKGError err;
    SKGTRACEINRC(1, "SKGSearchPlugin::execute", err);

    //Get rules
    SKGObjectBase::SKGListSKGObjectBase rules = SKGMainPanel::getMainPanel()->getSelectedObjects();

    int nb = rules.count();
    if (m_currentBankDocument) {
        SKGBEGINPROGRESSTRANSACTION(*m_currentBankDocument, i18nc("Noun, name of the user action", "Process execution"), err, nb);
        SKGRuleObject::ProcessMode mode = SKGRuleObject::ALL;
        if (sender() == m_executeImported) mode = SKGRuleObject::IMPORTED;
        else if (sender() == m_executeNotValidated) mode = SKGRuleObject::IMPORTEDNOTVALIDATE;
        for (int i = 0; !err && i < nb; ++i) {
            SKGRuleObject rule = rules.at(i);
            err = rule.execute(mode);
            if (!err) err = m_currentBankDocument->stepForward(i + 1);
        }
    }

    //status bar
    if (!err) err = SKGError(0, i18nc("Successful message after an user action", "Process executed"));
    else err.addError(ERR_FAIL, i18nc("Error message",  "Process execution failed"));

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

void SKGSearchPlugin::find()
{
    SKGError err;
    SKGTRACEINRC(10, "SKGSearchPlugin::find", err);
    if (SKGMainPanel::getMainPanel()) {
        SKGObjectBase::SKGListSKGObjectBase selection = SKGMainPanel::getMainPanel()->getSelectedObjects();

        QString xmlsearchcondition;
        int nb = selection.count();
        if (nb > 0) {
            QString table = selection.at(0).getRealTable();
            if (table == "account") {
                QDomDocument doc("SKGML");
                QDomElement element = doc.createElement("element");
                doc.appendChild(element);
                for (int i = 0; i < nb; ++i) {
                    QDomElement elementLine = doc.createElement("element");
                    element.appendChild(elementLine);

                    QDomElement elementElement = doc.createElement("element");
                    elementLine.appendChild(elementElement);

                    elementElement.setAttribute("attribute", "t_ACCOUNT");
                    elementElement.setAttribute("operator", "#ATT#='#V1S#'");
                    elementElement.setAttribute("value", selection.at(i).getAttribute("t_name"));
                }
                xmlsearchcondition = doc.toString();
            } else if (table == "category") {
                QDomDocument doc("SKGML");
                QDomElement element = doc.createElement("element");
                doc.appendChild(element);
                for (int i = 0; i < nb; ++i) {
                    QDomElement elementLine = doc.createElement("element");
                    element.appendChild(elementLine);

                    QDomElement elementElement = doc.createElement("element");
                    elementLine.appendChild(elementElement);

                    elementElement.setAttribute("attribute", "t_REALCATEGORY");
                    elementElement.setAttribute("operator", "#ATT#='#V1S#'");
                    SKGCategoryObject cat = selection.at(i);
                    elementElement.setAttribute("value", cat.getFullName());
                }
                xmlsearchcondition = doc.toString();
            } else if (table == "refund") {
                QDomDocument doc("SKGML");
                QDomElement element = doc.createElement("element");
                doc.appendChild(element);
                for (int i = 0; i < nb; ++i) {
                    QDomElement elementLine = doc.createElement("element");
                    element.appendChild(elementLine);

                    QDomElement elementElement = doc.createElement("element");
                    elementLine.appendChild(elementElement);

                    elementElement.setAttribute("attribute", "t_REALREFUND");
                    elementElement.setAttribute("operator", "#ATT#='#V1S#'");
                    elementElement.setAttribute("value", selection.at(i).getAttribute("t_name"));
                }
                xmlsearchcondition = doc.toString();
            } else if (table == "payee") {
                QDomDocument doc("SKGML");
                QDomElement element = doc.createElement("element");
                doc.appendChild(element);
                for (int i = 0; i < nb; ++i) {
                    QDomElement elementLine = doc.createElement("element");
                    element.appendChild(elementLine);

                    QDomElement elementElement = doc.createElement("element");
                    elementLine.appendChild(elementElement);

                    elementElement.setAttribute("attribute", "t_PAYEE");
                    elementElement.setAttribute("operator", "#ATT#='#V1S#'");
                    elementElement.setAttribute("value", selection.at(i).getAttribute("t_name"));
                }
                xmlsearchcondition = doc.toString();
            } else if (table == "operation") {
                QStringList attributeForQuery;
                attributeForQuery << "d_date" << "i_number" << "t_mode" << "t_PAYEE" << "t_comment" << "t_REALCATEGORY" << "t_status" << "t_bookmarked" << "t_imported" << "t_ACCOUNT" << "f_REALCURRENTAMOUNT" << "t_REALREFUND";

                QDomDocument doc("SKGML");
                QDomElement element = doc.createElement("element");
                doc.appendChild(element);
                for (int i = 0; i < nb; ++i) {
                    QDomElement elementLine = doc.createElement("element");
                    element.appendChild(elementLine);

                    for (int j = 0; j < attributeForQuery.count(); ++j) {
                        QString att = attributeForQuery.at(j);
                        QString attRead = (att == "t_REALCATEGORY" ? "t_CATEGORY" : (att == "f_REALCURRENTAMOUNT" ? "f_CURRENTAMOUNT" : (att == "t_REALREFUND" ? "t_REFUND" : att)));

                        SKGObjectBase op(selection.at(i).getDocument(), "v_operation_display_all", selection.at(i).getID());
                        op.load();

                        QString val = op.getAttribute(attRead);
                        if (!val.isEmpty() && !(att == "i_number" && val == "0")) {
                            QDomElement elementElement = doc.createElement("element");
                            elementLine.appendChild(elementElement);

                            elementElement.setAttribute("attribute", att);
                            elementElement.setAttribute("operator", att.startsWith(QLatin1String("f_")) || att.startsWith(QLatin1String("i_")) ? "#ATT#=#V1#" : "#ATT#='#V1S#'");
                            elementElement.setAttribute("value", val);
                        }
                    }
                }
                xmlsearchcondition = doc.toString();
            }
        }

        //Call report plugin
        QDomDocument doc("SKGML");
        if (m_currentBankDocument) doc.setContent(m_currentBankDocument->getParameter("SKGSEARCH_DEFAULT_PARAMETERS"));
        QDomElement root = doc.documentElement();
        if (root.isNull()) {
            root = doc.createElement("parameters");
            doc.appendChild(root);
        }

        root.setAttribute("xmlsearchcondition", xmlsearchcondition);
        root.setAttribute("currentPage", "0");
        SKGMainPanel::getMainPanel()->openPage(SKGMainPanel::getMainPanel()->getPluginByName("Skrooge search plugin"), -1, doc.toString());
    }
}

SKGTabPage* SKGSearchPlugin::getWidget()
{
    SKGTRACEIN(10, "SKGSearchPlugin::getWidget");
    return new SKGSearchPluginWidget(m_currentBankDocument);
}

QWidget* SKGSearchPlugin::getPreferenceWidget()
{
    SKGTRACEIN(10, "SKGSearchPlugin::getPreferenceWidget");
    QWidget* widget = new QWidget();
    ui.setupUi(widget);
    return widget;
}

KConfigSkeleton* SKGSearchPlugin::getPreferenceSkeleton()
{
    return skgsearch_settings::self();
}

QString SKGSearchPlugin::title() const
{
    return i18nc("Noun", "Search and process");
}

QString SKGSearchPlugin::icon() const
{
    return "edit-find";
}

QString SKGSearchPlugin::toolTip() const
{
    return i18nc("Noun", "Search and process management");
}

int SKGSearchPlugin::getOrder() const
{
    return 35;
}

QStringList SKGSearchPlugin::tips() const
{
    QStringList output;
    output.push_back(i18nc("Description of a tips", "<p>... skrooge can search and automatically process some operations.</p>"));
    output.push_back(i18nc("Description of a tips", "<p>... you can create alarms based on searches.</p>"));
    return output;
}

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

SKGAdviceList SKGSearchPlugin::advices() const
{
    SKGTRACEIN(10, "SKGSearchPlugin::advices");
    SKGAdviceList output;

    //Alarms
    SKGObjectBase::SKGListSKGObjectBase rules;
    SKGError err = m_currentBankDocument->getObjects("v_rule", "t_action_type='A' ORDER BY i_ORDER", rules);
    int nb = rules.count();
    if (nb) {
        SKGServices::SKGUnitInfo primary = m_currentBankDocument->getPrimaryUnit();

        for (int i = 0; !err && i < nb; ++i) {
            SKGRuleObject rule = rules.at(i);
            SKGRuleObject::SKGAlarmInfo alarm = rule.getAlarmInfo();

            double percent = 100 * alarm.Amount / alarm.Limit;
            if (percent >= 80) {
                SKGAdvice ad;
                ad.setUUID("skgsearchplugin_alarm|" % SKGServices::intToString(rule.getID()));
                ad.setPriority(9);
                ad.setShortMessage(alarm.Message);
                ad.setLongMessage(i18nc("Advice on making the best (long)", "Take care to your alarms.<br> %1.<br>%2 / %3", alarm.Message, m_currentBankDocument->formatMoney(alarm.Amount, primary), m_currentBankDocument->formatMoney(alarm.Limit, primary)));
                QStringList autoCorrections;
                autoCorrections.push_back(i18nc("Advice on making the best (action)", "Open operations corresponding to this alarm"));
                ad.setAutoCorrections(autoCorrections);
                output.push_back(ad);
            }
        }
    }

    return output;
}

SKGError SKGSearchPlugin::executeAdviceCorrection(const QString& iAdviceIdentifier, int iSolution) const
{
    if (m_currentBankDocument && iAdviceIdentifier.startsWith(QLatin1String("skgsearchplugin_alarm|"))) {
        //Get parameters
        QString id = iAdviceIdentifier.right(iAdviceIdentifier.length() - 22);
        SKGRuleObject rule(m_currentBankDocument, SKGServices::stringToInt(id));
        rule.load();
        SKGSearchPluginWidget::open(rule); //FIXME //TODO
        return SKGError();
    }

    return SKGInterfacePlugin::executeAdviceCorrection(iAdviceIdentifier, iSolution);
}
#include "skgsearchplugin.moc"
