/***************************************************************************
 *   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 for operation management.
 *
 * @author Stephane MANKOWSKI / Guillaume DE BURE
 */
#include "skgoperationboardwidget.h"

#include <QDomDocument>
#include <QParallelAnimationGroup>
#include <QPropertyAnimation>

#include <KAction>

#include "skgdocumentbank.h"
#include "skgreportbank.h"
#include "skgtraces.h"
#include "skgservices.h"
#include "skgobjectbase.h"
#include "skgmainpanel.h"
#include "skgperiodedit.h"

SKGOperationBoardWidget::SKGOperationBoardWidget(SKGDocument* iDocument)
    : SKGBoardWidget(iDocument, i18nc("Dashboard widget title", "Income & Expenditure"))
{
    SKGTRACEINFUNC(10);

    m_timer.setSingleShot(true);
    connect(&m_timer, SIGNAL(timeout()), this, SLOT(dataModified()), Qt::QueuedConnection);

    // Initialize animation group
    m_anim = new QParallelAnimationGroup(this);

    QFrame* f = new QFrame();
    ui.setupUi(f);
    setMainWidget(f);

    ui.kIncomeLabel->setText("<a href=\"IC\">" % ui.kIncomeLabel->text() % "</a>");
    ui.kExpenseLabel->setText("<a href=\"EC\">" % ui.kExpenseLabel->text() % "</a>");
    ui.kSavingLabel->setText("<a href=\"SC\">" % ui.kSavingLabel->text() % "</a>");
    ui.kIncome_previousLabel->setText("<a href=\"IP\">" % ui.kIncome_previousLabel->text() % "</a>");
    ui.kExpense_previousLabel->setText("<a href=\"EP\">" % ui.kExpense_previousLabel->text() % "</a>");
    ui.kSaving_previousLabel->setText("<a href=\"SP\">" % ui.kSaving_previousLabel->text() % "</a>");

    connect(ui.kIncomeLabel, SIGNAL(linkActivated(QString)), this, SLOT(onOpen(QString)));
    connect(ui.kExpenseLabel, SIGNAL(linkActivated(QString)), this, SLOT(onOpen(QString)));
    connect(ui.kSavingLabel, SIGNAL(linkActivated(QString)), this, SLOT(onOpen(QString)));
    connect(ui.kIncome_previousLabel, SIGNAL(linkActivated(QString)), this, SLOT(onOpen(QString)));
    connect(ui.kExpense_previousLabel, SIGNAL(linkActivated(QString)), this, SLOT(onOpen(QString)));
    connect(ui.kSaving_previousLabel, SIGNAL(linkActivated(QString)), this, SLOT(onOpen(QString)));

    // Create menu
    setContextMenuPolicy(Qt::ActionsContextMenu);

    QStringList overlayopen;
    overlayopen.push_back("skg_open");
    m_menuOpen = new KAction(KIcon("view-investment", NULL, overlayopen), i18nc("Verb", "Open report..."), this);
    connect(m_menuOpen, SIGNAL(triggered(bool)), SKGMainPanel::getMainPanel(), SLOT(openPage()));
    addAction(m_menuOpen);

    {
        QAction* sep = new QAction(this);
        sep->setSeparator(true);
        addAction(sep);
    }

    m_menuTransfert = new KAction(i18nc("Noun, a type of operations", "Transfers"), this);
    m_menuTransfert->setCheckable(true);
    m_menuTransfert->setChecked(false);
    connect(m_menuTransfert, SIGNAL(triggered(bool)), this, SLOT(refreshDelayed()));
    addAction(m_menuTransfert);

    m_menuTracked = new KAction(i18nc("Noun, a type of operations", "Tracked"), this);
    m_menuTracked->setCheckable(true);
    m_menuTracked->setChecked(true);
    connect(m_menuTracked, SIGNAL(triggered(bool)), this, SLOT(refreshDelayed()));
    addAction(m_menuTracked);

    m_menuSuboperation = new KAction(i18nc("Noun, a type of operations", "On suboperations"), this);
    m_menuSuboperation->setCheckable(true);
    m_menuSuboperation->setChecked(false);
    connect(m_menuSuboperation, SIGNAL(triggered(bool)), this, SLOT(refreshDelayed()));
    addAction(m_menuSuboperation);

    {
        QAction* sep = new QAction(this);
        sep->setSeparator(true);
        addAction(sep);
    }

    m_periodEdit1 = new SKGPeriodEdit(this);
    {
        // Set default
        QDomDocument doc("SKGML");
        QDomElement root = doc.createElement("parameters");
        doc.appendChild(root);
        root.setAttribute("period", SKGServices::intToString(static_cast<int>(SKGPeriodEdit::CURRENT)));
        m_periodEdit1->setState(doc.toString());

        // Add widget in menu
        QWidgetAction* periodEditWidget = new QWidgetAction(this);
        periodEditWidget->setDefaultWidget(m_periodEdit1);

        addAction(periodEditWidget);
    }

    {
        QAction* sep = new QAction(this);
        sep->setSeparator(true);
        addAction(sep);
    }

    m_periodEdit2 = new SKGPeriodEdit(this);
    {
        // Set default
        QDomDocument doc("SKGML");
        QDomElement root = doc.createElement("parameters");
        doc.appendChild(root);
        root.setAttribute("period", SKGServices::intToString(static_cast<int>(SKGPeriodEdit::PREVIOUS)));
        m_periodEdit2->setState(doc.toString());

        // Add widget in menu
        QWidgetAction* periodEditWidget = new QWidgetAction(this);
        periodEditWidget->setDefaultWidget(m_periodEdit2);

        addAction(periodEditWidget);
    }

    // Refresh
    connect(m_periodEdit1, SIGNAL(changed()), this, SLOT(refreshDelayed()), Qt::QueuedConnection);
    connect(m_periodEdit2, SIGNAL(changed()), this, SLOT(refreshDelayed()), Qt::QueuedConnection);
    connect(getDocument(), SIGNAL(tableModified(QString,int,bool)), this, SLOT(dataModified(QString,int)), Qt::QueuedConnection);
}

SKGOperationBoardWidget::~SKGOperationBoardWidget()
{
    SKGTRACEINFUNC(10);
    m_menuTransfert = NULL;
    m_menuTracked = NULL;
    m_anim = NULL;
}

QString SKGOperationBoardWidget::getState()
{
    QDomDocument doc("SKGML");
    QDomElement root = doc.createElement("parameters");
    doc.appendChild(root);

    root.setAttribute("menuTransfert", m_menuTransfert && m_menuTransfert->isChecked() ? "Y" : "N");
    root.setAttribute("menuTracked", m_menuTracked && m_menuTracked->isChecked() ? "Y" : "N");
    root.setAttribute("menuSuboperation", m_menuSuboperation && m_menuSuboperation->isChecked() ? "Y" : "N");
    root.setAttribute("period1", m_periodEdit1->getState());
    root.setAttribute("period2", m_periodEdit2->getState());
    return doc.toString();
}

void SKGOperationBoardWidget::setState(const QString& iState)
{
    QDomDocument doc("SKGML");
    doc.setContent(iState);
    QDomElement root = doc.documentElement();
    if (m_menuTransfert) {
        m_menuTransfert->setChecked(root.attribute("menuTransfert") == "Y");
    }
    if (m_menuTracked) {
        m_menuTracked->setChecked(root.attribute("menuTracked") != "N");
    }
    if (m_menuSuboperation) {
        m_menuSuboperation->setChecked(root.attribute("menuSuboperation") == "Y");
    }
    QString period1 = root.attribute("period1");
    if (m_periodEdit1 && !period1.isEmpty()) {
        m_periodEdit1->setState(period1);
    }
    QString period2 = root.attribute("period2");
    if (m_periodEdit2 && !period2.isEmpty()) {
        m_periodEdit2->setState(period2);
    }
    refreshDelayed();
}

void SKGOperationBoardWidget::onOpen(const QString& iLink)
{
    // Call operation plugin
    QString wc;
    if (iLink.endsWith(QLatin1String("C"))) {
        wc = m_periodEdit1->getWhereClause() % " AND t_TYPEACCOUNT<>'L'";
    } else {
        wc = m_periodEdit2->getWhereClause() % " AND t_TYPEACCOUNT<>'L'";
    }

    if (iLink.startsWith(QLatin1String("I"))) {
        wc = wc % " AND t_TYPEEXPENSE='+'";
    } else if (iLink.startsWith(QLatin1String("E"))) {
        wc = wc % " AND t_TYPEEXPENSE='-'";
    }

    wc = wc % (m_menuTransfert && m_menuTransfert->isChecked() ? "" : " AND t_TRANSFER='N'") % (m_menuTracked && m_menuTracked->isChecked() ? "" : " AND t_REFUND=''");

    QString title;
    if (iLink == "IC") {
        title = i18nc("Title of a list of operations", "Incomes of %1", ui.kLabel->text());
    } else if (iLink == "EC") {
        title = i18nc("Title of a list of operations", "Expenses of %1", ui.kLabel->text());
    } else if (iLink == "SC") {
        title = i18nc("Title of a list of operations", "Savings of %1", ui.kLabel->text());
    } else if (iLink == "IP") {
        title = i18nc("Title of a list of operations", "Incomes of %1", ui.kLabel_previous->text());
    } else if (iLink == "EP") {
        title = i18nc("Title of a list of operations", "Expenses of %1", ui.kLabel_previous->text());
    } else if (iLink == "SP") {
        title = i18nc("Title of a list of operations", "Savings of %1", ui.kLabel_previous->text());
    }

    bool onSubOperation = (m_menuSuboperation && m_menuSuboperation->isChecked());
    SKGMainPanel::getMainPanel()->openPage("skg://skrooge_operation_plugin/" % QString(onSubOperation ? "SKGOPERATION_CONSOLIDATED_DEFAULT_PARAMETERS/" : "") % "?operationTable=" % SKGServices::encodeForUrl(onSubOperation ? "v_suboperation_consolidated" : "v_operation_display") % "&title_icon=view-financial-list&currentPage=-1&title=" % SKGServices::encodeForUrl(title) %
                                           "&operationWhereClause=" % SKGServices::encodeForUrl(wc));
}

void SKGOperationBoardWidget::refreshDelayed()
{
    m_timer.start(300);
}

void SKGOperationBoardWidget::dataModified(const QString& iTableName, int iIdTransaction)
{
    SKGTRACEINFUNC(10);
    Q_UNUSED(iIdTransaction);
    QString table = (m_menuSuboperation && m_menuSuboperation->isChecked() ? "v_suboperation_consolidated" : "v_operation_display");
    if (m_periodEdit1 && m_periodEdit2 && (iTableName == table || iTableName.isEmpty())) {
        // Set titles
        ui.kLabel->setText(m_periodEdit1->text());
        ui.kLabel_previous->setText(m_periodEdit2->text());

        SKGDocumentBank* doc = qobject_cast<SKGDocumentBank*>(getDocument());
        if (doc) {
            if (m_menuOpen) {
                QString url = QString("skg://skrooge_report_plugin/?grouped=")
                              % (m_menuTransfert && m_menuTransfert->isChecked() ? "Y" : "N") % "&transfers="
                              % (m_menuTransfert && m_menuTransfert->isChecked() ? "Y" : "N") % "&tracked="
                              % (m_menuTracked && m_menuTracked->isChecked() ? "Y" : "N") % "&expenses=Y&incomes=Y&lines2=t_TYPEEXPENSENLS&columns=d_DATEMONTH&currentPage=-1" %
                              "&mode=0&interval=3&period=3" %
                              "&tableAndGraphState.graphMode=1&tableAndGraphState.allPositive=Y&tableAndGraphState.show=graph&title=" %
                              SKGServices::encodeForUrl(i18nc("Noun, the title of a section", "Income & Expenditure"));
                m_menuOpen->setData(url);
            }

            SKGServices::SKGUnitInfo primary = doc->getPrimaryUnit();
            SKGServices::SKGUnitInfo secondary = doc->getSecondaryUnit();

            SKGReportBank* bk = qobject_cast< SKGReportBank* >(doc->getReport());
            if (bk) {
                QVariantList table2 = bk->getIncomeVsExpenditure(m_menuSuboperation && m_menuSuboperation->isChecked(),
                                      m_menuTransfert && m_menuTransfert->isChecked(),
                                      m_menuTracked && m_menuTracked->isChecked(),
                                      m_periodEdit1->getWhereClause(),
                                      m_periodEdit2->getWhereClause());
                delete bk;

                QList<QVariant> l1 = table2.value(1).toList();
                QList<QVariant> l2 = table2.value(2).toList();
                double income_previous_month = l1.value(2).toDouble();
                double expense_previous_month = l2.value(2).toDouble();
                double income_month = l1.value(3).toDouble();
                double expense_month = l2.value(3).toDouble();

                // Set Maximum
                int max = qMax(income_previous_month, qMax(expense_previous_month, qMax(income_month, expense_month)));
                if (max == 0) {
                    max = 100.0;
                }
                ui.kIncome->setMaximum(max);
                ui.kIncome_previous->setMaximum(max);
                ui.kExpense->setMaximum(max);
                ui.kExpense_previous->setMaximum(max);
                ui.kSaving->setMaximum(max);
                ui.kSaving_previous->setMaximum(max);

                // Set texts and tool tips
                ui.kIncome->setFormat(doc->formatMoney(income_month, primary, false));
                ui.kIncome_previous->setFormat(doc->formatMoney(income_previous_month, primary, false));
                ui.kExpense->setFormat(doc->formatMoney(expense_month, primary, false));
                ui.kExpense_previous->setFormat(doc->formatMoney(expense_previous_month, primary, false));
                ui.kSaving->setFormat(doc->formatMoney(income_month - expense_month, primary, false));
                ui.kSaving_previous->setFormat(doc->formatMoney(income_previous_month - expense_previous_month, primary, false));
                if (!secondary.Symbol.isEmpty() && secondary.Value) {
                    ui.kIncome->setToolTip(doc->formatMoney(income_month, secondary, false));
                    ui.kIncome_previous->setToolTip(doc->formatMoney(income_previous_month, secondary, false));
                    ui.kExpense->setToolTip(doc->formatMoney(expense_month, secondary, false));
                    ui.kExpense_previous->setToolTip(doc->formatMoney(expense_previous_month, secondary, false));
                    ui.kSaving->setToolTip(doc->formatMoney(income_month - expense_month, secondary, false));
                    ui.kSaving_previous->setToolTip(doc->formatMoney(income_previous_month - expense_previous_month, secondary, false));
                }

                // Change colors
                ui.kIncome->setLimits(0, 0, max);
                ui.kIncome_previous->setLimits(0, 0, max);
                ui.kExpense->setLimits(max, -1, -1);
                ui.kExpense_previous->setLimits(max, -1, -1);
                ui.kSaving->setLimits(income_month - expense_month < 0 ? max : 0, 0.1 * income_month, max);
                ui.kSaving_previous->setLimits(income_previous_month - expense_previous_month < 0 ? max : 0, 0.1 * income_previous_month, max);

                // Set values
                m_anim->clear();
                {
                    QPropertyAnimation* panim = new QPropertyAnimation(ui.kIncome, "value");
                    panim->setDuration(1000);
                    panim->setStartValue(0);
                    panim->setEndValue(static_cast<int>(income_month));
                    m_anim->addAnimation(panim);
                }

                {
                    QPropertyAnimation* panim = new QPropertyAnimation(ui.kIncome_previous, "value");
                    panim->setDuration(1000);
                    panim->setStartValue(0);
                    panim->setEndValue(static_cast<int>(income_previous_month));
                    m_anim->addAnimation(panim);
                }

                {
                    QPropertyAnimation* panim = new QPropertyAnimation(ui.kExpense, "value");
                    panim->setDuration(1000);
                    panim->setStartValue(0);
                    panim->setEndValue(static_cast<int>(expense_month));
                    m_anim->addAnimation(panim);
                }

                {
                    QPropertyAnimation* panim = new QPropertyAnimation(ui.kExpense_previous, "value");
                    panim->setDuration(1000);
                    panim->setStartValue(0);
                    panim->setEndValue(static_cast<int>(expense_previous_month));
                    m_anim->addAnimation(panim);
                }

                {
                    QPropertyAnimation* panim = new QPropertyAnimation(ui.kSaving, "value");
                    panim->setDuration(1000);
                    panim->setStartValue(0);
                    panim->setEndValue(static_cast<int>(qAbs(income_month - expense_month)));
                    m_anim->addAnimation(panim);
                }

                {
                    QPropertyAnimation* panim = new QPropertyAnimation(ui.kSaving_previous, "value");
                    panim->setDuration(1000);
                    panim->setStartValue(0);
                    panim->setEndValue(static_cast<int>(qAbs(income_previous_month - expense_previous_month)));
                    m_anim->addAnimation(panim);
                }

                QTimer::singleShot(1000, m_anim, SLOT(start()));
            }

            // No widget if no account
            bool exist = false;
            doc->existObjects("account", "", exist);
            if (parentWidget()) {
                setVisible(exist);
            }
        }
    }
}

#include "skgoperationboardwidget.moc"
