/***************************************************************************
 *   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 for monthly report.
 *
 * @author Stephane MANKOWSKI
 */
#include "skgreportbank.h"
#include "skgtraces.h"
#include "skgdocumentbank.h"
#include "skgaccountobject.h"
#include "skgunitobject.h"

#include <kstandarddirs.h>
#include <grantlee/engine.h>
#include <grantlee/templateloader.h>
#ifdef SKGGRANTLEE17ENABLED
#include <grantlee/metatype.h>
#endif
#include <kaboutdata.h>
#include <kcomponentdata.h>
#include <kcolorscheme.h>
#include <KUrl>

#include <QTextStream>
#include <QFile>
#include <QDir>


#ifdef SKGGRANTLEE17ENABLED
GRANTLEE_BEGIN_LOOKUP(SKGObjectBase)
Q_UNUSED(object);
Q_UNUSED(property);
GRANTLEE_END_LOOKUP
#endif

SKGReportBank::SKGReportBank(SKGDocument* iDocument)
    : SKGReport(iDocument)
{
    SKGTRACEIN(1, "SKGReportBank::SKGReportBank");

    //Grantlee initialization
#ifdef SKGGRANTLEE17ENABLED
    Grantlee::MetaType::init();
    Grantlee::registerMetaType<SKGObjectBase>();
#endif
}

SKGReportBank::~SKGReportBank()
{
    SKGTRACEIN(1, "SKGReportBank::~SKGReportBank");
}

QVariantList SKGReportBank::getBudgetTable()
{
    SKGTRACEIN(10, "SKGReportBank::getBudgetTable");
    QVariantList table = m_cache["getBudgetTable"].toList();
    if (table.count() == 0) {
        SKGDocumentBank* doc = static_cast<SKGDocumentBank*>(m_document);
        table = doc ? doc->getBudget(getMonth()) : QVariantList();
        m_cache["getBudgetTable"] = table;
    }
    return table;
}

QVariantList SKGReportBank::getUnitTable()
{
    SKGTRACEIN(10, "SKGReportBank::getUnitTable");
    QVariantList table = m_cache["getUnitTable"].toList();
    if (table.count() == 0) {
        QString month = getMonth();
        if (!month.isEmpty()) {
            QDate date = QDate::fromString(month, "yyyy-MM");
            QDate date1 = date.addDays(-1);
            QDate date2 = date.addMonths(1).addDays(-1);
            QString previousmonth = date1.toString("yyyy-MM");
            SKGDocumentBank* doc = static_cast<SKGDocumentBank*>(m_document);
            KLocale* locale = KGlobal::locale();
            if (doc && locale) {
                SKGServices::SKGUnitInfo primary = doc->getPrimaryUnit();

                SKGObjectBase::SKGListSKGObjectBase units;
                SKGError err = doc->getObjects("v_unit_display", "1=1 ORDER BY t_TYPENLS", units);
                if (units.count()) {
                    QVariantList line;
                    line << "sum" << doc->getDisplay("t_UNIT") << locale->formatDate(date1, KLocale::ShortDate) << locale->formatDate(date2, KLocale::ShortDate) << "%";
                    table << QVariant(line);
                    foreach(const SKGUnitObject & unit, units) {
                        double v1 = unit.getAmount(date1);
                        double v2 = unit.getAmount(date2);
                        QVariantList line;
                        line << false << unit.getName() << v1 << v2 << (100.0 * (v2 - v1) / qAbs(v1));
                        table << QVariant(line);
                    }
                }
            }
        }
        m_cache["getUnitTable"] = table;
    }

    return table;
}

QVariantList SKGReportBank::getAccountTable()
{
    SKGTRACEIN(10, "SKGReportBank::getAccountTable");
    QVariantList table = m_cache["getAccountTable"].toList();
    if (table.count() == 0) {
        QString month = getMonth();
        if (!month.isEmpty()) {
            QDate date = QDate::fromString(month, "yyyy-MM");
            QDate date1 = date.addDays(-1);
            QDate date2 = date.addMonths(1).addDays(-1);
            QDate date3 = date2.addYears(-1);
            QString previousmonth = date1.toString("yyyy-MM");
            SKGDocumentBank* doc = static_cast<SKGDocumentBank*>(m_document);
            KLocale* locale = KGlobal::locale();
            if (doc && locale) {
                SKGServices::SKGUnitInfo primary = doc->getPrimaryUnit();

                SKGObjectBase::SKGListSKGObjectBase accounts;
                SKGError err = doc->getObjects("v_account_display", "1=1 ORDER BY t_TYPENLS", accounts);
                if (!err) {
                    QVariantList line;
                    line << "sum" << doc->getDisplay("t_ACCOUNT") << locale->formatDate(date1, KLocale::ShortDate) << locale->formatDate(date2, KLocale::ShortDate) <<
                         "%" << locale->formatDate(date3, KLocale::ShortDate) << locale->formatDate(date2, KLocale::ShortDate) << "%";
                    table.push_back(line);
                    double sumTypeV1 = 0;
                    double sumTypeV2 = 0;
                    double sumTypeV3 = 0;
                    double sumV1 = 0;
                    double sumV2 = 0;
                    double sumV3 = 0;
                    QString currentType;
                    int nb = accounts.count();
                    for (int i = 0; !err && i < nb; ++i) {
                        SKGAccountObject account = accounts.at(i);
                        double v1 = account.getAmount(date1);
                        double v2 = account.getAmount(date2);
                        double v3 = account.getAmount(date3);
                        QString type = account.getAttribute("t_TYPENLS");
                        bool closed = account.isClosed();
                        if (type != currentType) {
                            if (!currentType.isEmpty()) {
                                QVariantList line;
                                line << true << i18nc("Noun",  "Total of %1", currentType) << sumTypeV1 << sumTypeV2 <<
                                     (100.0 * (sumTypeV2 - sumTypeV1) / qAbs(sumTypeV1)) << sumTypeV3 << sumTypeV2 << (100.0 * (sumTypeV2 - sumTypeV3) / qAbs(sumTypeV3));
                                table.push_back(line);
                                sumTypeV1 = 0;
                                sumTypeV2 = 0;
                                sumTypeV3 = 0;
                            }
                            currentType = type;
                        }
                        if (!closed || qAbs(v1) > 0.01 || qAbs(v2) > 0.01 || qAbs(v3) > 0.01) {
                            QVariantList line;
                            line << false << account.getName() << v1 << v2 << (100.0 * (v2 - v1) / qAbs(v1)) << v3 << v2 << (100.0 * (v2 - v3) / qAbs(v3));
                            table.push_back(line);
                            ;
                        }
                        sumTypeV1 += v1;
                        sumTypeV2 += v2;
                        sumTypeV3 += v3;
                        sumV1 += v1;
                        sumV2 += v2;
                        sumV3 += v3;
                    }

                    {
                        QVariantList line;
                        line << true << i18nc("Noun",  "Total of %1", currentType) << sumTypeV1 << sumTypeV2 << (100.0 * (sumTypeV2 - sumTypeV1) / qAbs(sumTypeV1)) << sumTypeV3 << sumTypeV2 << (100.0 * (sumTypeV2 - sumTypeV3) / qAbs(sumTypeV3));
                        table.push_back(line);
                    }

                    {
                        QVariantList line;
                        line << true << i18nc("Noun, the numerical total of a sum of values", "Total") << sumV1 << sumV2 << (100.0 * (sumV2 - sumV1) / qAbs(sumV1)) << sumV3 << sumV2 << (100.0 * (sumV2 - sumV3) / qAbs(sumV3));
                        table.push_back(line);
                    }
                }
            }
        }
        m_cache["getAccountTable"] = table;
    }
    return table;
}

QVariantList SKGReportBank::getMainCategoriesMonth()
{
    SKGTRACEIN(10, "SKGReportBank::getMainCategoriesMonth");
    QVariantList table = m_cache["getMainCategoriesMonth"].toList();
    if (table.count() == 0) {
        SKGDocumentBank* doc = static_cast<SKGDocumentBank*>(m_document);
        table = doc ? doc->getMainCategories(getMonth(), 5) : QVariantList();
        m_cache["getMainCategoriesMonth"] = table;
    }
    return table;
}

QVariantList SKGReportBank::getMainCategoriesPreviousMonth()
{
    SKGTRACEIN(10, "SKGReportBank::getMainCategoriesPreviousMonth");
    QVariantList table = m_cache["getMainCategoriesPreviousMonth"].toList();
    if (table.count() == 0) {
        SKGDocumentBank* doc = static_cast<SKGDocumentBank*>(m_document);
        table = doc ? doc->getMainCategories(getPreviousMonth(), 5) : QVariantList();
        m_cache["getMainCategoriesPreviousMonth"] = table;
    }
    return table;
}

QStringList SKGReportBank::get5MainCategoriesVariation()
{
    SKGTRACEIN(10, "SKGReportBank::get5MainCategoriesVariation");
    QStringList table = m_cache["get5MainCategoriesVariation"].toStringList();
    if (table.count() == 0) {
        SKGDocumentBank* doc = static_cast<SKGDocumentBank*>(m_document);
        table = doc ? doc->get5MainCategoriesVariationList(getMonth(), getPreviousMonth()) : QStringList();
        m_cache["get5MainCategoriesVariation"] = table;
    }
    return table;
}

QStringList SKGReportBank::getTitles()
{
    QStringList output;
    output.push_back(i18nc("A monthly report title", "Report for %1", getMonth()));
    output.push_back(i18nc("A monthly report title", "Budget"));
    output.push_back(i18nc("A monthly report title", "5 main categories of expenditure"));
    output.push_back(i18nc("A monthly report title", "5 main variations"));
    output.push_back(i18nc("A monthly report title", "Amounts in accounts"));
    output.push_back(i18nc("A monthly report title", "Amounts of units"));
    output.push_back(i18nc("A monthly report title", "Advices"));

    return output;
}

QVariant SKGReportBank::getAdvices()
{
    SKGTRACEIN(10, "SKGReportBank::getAdvices");
    QVariant output = m_cache["getAdvices"];
    if (!output.isValid()) {
        //TODO output = qVariantFromValue(SKGMainPanel::getMainPanel()->getAdvices());
        m_cache["getAdvices"] = output;
    }
    return output;
}

QVariantList SKGReportBank::getIncomeVsExpenditure()
{
    SKGTRACEIN(10, "SKGReportBank::getIncomeVsExpenditure");
    QVariantList table = m_cache["getIncomeVsExpenditure"].toList();
    if (table.count() == 0) {
        SKGDocumentBank* doc = static_cast<SKGDocumentBank*>(m_document);
        if (doc) {
            QString month = getMonth();
            QString previousmonth = getPreviousMonth();
            SKGStringListList listTmp;
            SKGError err = doc->executeSelectSqliteOrder(
                               "SELECT TOTAL(f_CURRENTAMOUNT), d_DATEMONTH  from v_operation_display WHERE d_DATEMONTH IN ('" % month % "', '" % previousmonth % "') AND t_TRANSFER='N' group by d_DATEMONTH, t_TYPEEXPENSE",
                               listTmp);
            int nbval = listTmp.count();
            if (!err && nbval > 1) {
                QVariantList line;
                line << "sum" << "" << previousmonth << month << "max";
                table.push_back(line);

                double income_previous_month = 0;
                double expense_previous_month = 0;
                double income_month = 0;
                double expense_month = 0;

                for (int i = 1; i < nbval; ++i) { //Ignore header
                    QString m = listTmp.at(i).at(1);
                    double v = SKGServices::stringToDouble(listTmp.at(i).at(0));
                    if (v > 0 && m == month) income_month = v;
                    else if (v < 0 && m == month) expense_month = v;
                    else if (v > 0 && m == previousmonth) income_previous_month = v;
                    else if (v < 0 && m == previousmonth) expense_previous_month = v;
                }
                double saving_previous_month = income_previous_month + expense_previous_month;
                double saving_month = income_month + expense_month;

                {
                    QVariantList line;
                    line << false << doc->getDisplay("f_CURRENTAMOUNT_INCOME") << qAbs(income_previous_month) << qAbs(income_month);
                    table.push_back(line);
                }
                {
                    QVariantList line;
                    line << false << doc->getDisplay("f_CURRENTAMOUNT_EXPENSE") << qAbs(expense_previous_month) << qAbs(expense_month);
                    table.push_back(line);
                }
                {
                    QVariantList line;
                    line << true << i18nc("Noun",  "Savings possible") << saving_previous_month << saving_month;
                    table.push_back(line);
                }
                {
                    QVariantList line;
                    line << true << i18nc("Noun",  "Max") << qMax(qAbs(income_previous_month), qAbs(expense_previous_month)) << qMax(qAbs(income_month), qAbs(expense_month));
                    table.push_back(line);
                }
            }
        }
    }
    return table;
}

void SKGReportBank::addItemsInMapping(QVariantHash& iMapping)
{
    SKGReport::addItemsInMapping(iMapping);
    iMapping.insert("about_forumpage", "http://forum.kde.org/viewforum.php?f=210");
    iMapping.insert("about_newspage", "http://skrooge.org/news");
    iMapping.insert("about_operationpage", "Skrooge operation plugin;SKGOPERATION_DEFAULT_PARAMETERS");
    iMapping.insert("about_accountpage", "Skrooge bank plugin;SKGBANK_DEFAULT_PARAMETERS");
    iMapping.insert("about_maintext", i18nc("The main text of skrooge",
                                            "Skrooge allows you to keep a hold on your expenses, by tracking and budgeting them.<br/>"
                                            "What should you do now ?<br/>"
                                            "<ul>"
                                            "<li>Create at least one <a href=\"%1\">account</a></li>"
                                            "<li>Add some operations, using import or <a href=\"%2\">manual input</a></li>"
                                            "<li>Categorize them</li>"
                                            "</ul>"
                                            "<p>You may come back to this page any time by closing all tabs.<br/>"
                                            "For more information about using Skrooge, check the <a href=\"http://skrooge.org\">Skrooge website</a>.</p>"
                                            "<p>We hope that you will enjoy Skrooge</p>"
                                            "    The Skrooge Team",
                                            iMapping["about_accountpage"].toString(), iMapping["about_operationpage"].toString()));
    iMapping.insert("logo", KUrl(KStandardDirs().findResource("icon", QString::fromLatin1("hicolor/128x128/apps/skrooge.png"))).url());
    iMapping.insert("logo_black", KUrl(KStandardDirs().findResource("icon", QString::fromLatin1("hicolor/128x128/apps/skrooge-black.png"))).url());
}

#include "skgreportbank.moc"
