/***************************************************************************
 *   Copyright (C) 2010 by SIDDHARTH SHARMA siddharth.kde@gmail.com        *
 *                                                                         *
 *   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/>  *
 ***************************************************************************/
#include "skgdataengine.h"


#include <Plasma/DataContainer>

#include "skgtraces.h"
#include "skgservices.h"
#include "skgmainpanel.h"
#include "skgdocumentbank.h"
#include "skgunitobject.h"
#include "skginterfaceplugin.h"

#include <QStringListModel>
#include <KMessageBox>
#include <sys/stat.h>

/**
  * Name of a source
  */
#define SRC_ACCOUNTS "Accounts"
/**
  * Name of a source
  */
#define SRC_INCOMESANDEXPENDITURES "Incomes & Expenditures"
/**
  * Name of a source
  */
#define SRC_BANKS "Banks"
/**
  * Name of a source
  */
#define SRC_HIGHLIGHTED "Highlighted Operations"
/**
  * Name of a source
  */
#define SRC_SCHEDULED "Scheduled Operations"
/**
  * Name of a source
  */
#define SRC_UNITS "Units"
/**
  * Name of a source
  */
#define SRC_ADVICES "Advices"

SKGDataEngine::SKGDataEngine(QObject* parent, const QVariantList& args): DataEngine(parent, args), document(NULL) {}

SKGDataEngine::~SKGDataEngine()
{
    document = NULL;
}

void SKGDataEngine::init()
{
    Plasma::DataEngine::init();

    // Get the document behind the current document
    SKGMainPanel* panel = SKGMainPanel::getMainPanel();
    if (panel) setDocument(qobject_cast<SKGDocumentBank*> (panel->getDocument()));
}

QStringList SKGDataEngine::sources() const
{
    QStringList sources;
    if (this->getDocument()) sources << SRC_ACCOUNTS << SRC_INCOMESANDEXPENDITURES << SRC_BANKS << SRC_HIGHLIGHTED << SRC_SCHEDULED << SRC_UNITS << SRC_ADVICES;
    return sources;
}

bool SKGDataEngine::updateSourceEvent(const QString& source)
{
    if (!document) return false;
    if (source == SRC_ACCOUNTS) {
        return getAccountData();
    } else if (source == SRC_INCOMESANDEXPENDITURES) {
        return getIncomeExpenditureData();
    } else if (source == SRC_HIGHLIGHTED) {
        return getHighlightedOperationData();
    } else if (source == SRC_SCHEDULED) {
        return getScheduledOperationData();
    } else if (source == SRC_UNITS) {
        return getUnitsData();
    } else if (source == SRC_ADVICES) {
        return getAdvicesData();
    }
    return false;
}

bool SKGDataEngine::sourceRequestEvent(const QString& source)
{
    return updateSourceEvent(source);
}

bool SKGDataEngine::getAccountData()
{
    removeAllData(SRC_ACCOUNTS);
    if (!document) return false;

    SKGStringListList sqlResult;

    // Fetch results in the database
    SKGError err = document->executeSelectSqliteOrder("SELECT t_name, t_bank, t_typenls, f_CURRENTAMOUNT, t_close FROM v_account_display ORDER BY t_type,t_name", sqlResult);

    // We may receive an error from querying the SQLite database
    if (err) return false;

    // Put the data in the dataengine
    int nb = sqlResult.count();
    for (int i = 1 ; i < nb ; ++i) {
        QStringList values;
        values << sqlResult.at(i).at(1); // Account type
        values << sqlResult.at(i).at(2); // Bank name
        values << sqlResult.at(i).at(3); // Amount of money
        values << sqlResult.at(i).at(4); // Account closed

        setData(SRC_ACCOUNTS, sqlResult.at(i).at(0), values);
    }
    return true;
}


bool SKGDataEngine::getIncomeExpenditureData()
{
    removeAllData(SRC_INCOMESANDEXPENDITURES);
    if (!document) return false;

    QDate date = QDate::currentDate();

    QString month = date.toString("yyyy-MM");
    QString previousmonth = date.addMonths(-1).toString("yyyy-MM");

    SKGStringListList data;
    SKGError err = document->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", data);

    // We may receive an error from querying the SQLite database
    if (err) return false;

    // Put the data in the dataengine
    int nb = data.count();
    for (int i = 0 ; i < nb ; ++i) {
        setData(SRC_INCOMESANDEXPENDITURES, data.at(i).at(0), data.at(i).at(1));
    }
    return true;
}

bool SKGDataEngine::getHighlightedOperationData()
{
    removeAllData(SRC_HIGHLIGHTED);
    if (!document) return false;

    SKGStringListList sqlResult;

    // Fetch results in the database
    SKGError err = document->executeSelectSqliteOrder("SELECT id, d_date, t_payee, f_currentamount FROM v_operation_display WHERE t_bookmarked='Y' ORDER BY d_date", sqlResult);

    // We may receive an error from querying the SQLite database
    if (err) return false;

    // Put the data in the dataengine
    int nb = sqlResult.count();
    for (int i = 1 ; i < nb ; ++i) {
        QStringList values;
        values << sqlResult.at(i).at(1); // Date
        values << sqlResult.at(i).at(2); // Payee
        values << sqlResult.at(i).at(3); // Amount

        setData(SRC_HIGHLIGHTED, sqlResult.at(i).at(0), values);
    }

    return true;
}

bool SKGDataEngine::getScheduledOperationData()
{
    removeAllData(SRC_SCHEDULED);
    if (!document) return false;

    SKGStringListList sqlResult;

    // Fetch results in the database
    SKGError err = document->executeSelectSqliteOrder("SELECT id, d_date, t_payee, f_currentamount FROM v_recurrentoperation_display ORDER BY d_date LIMIT 5", sqlResult);

    // We may receive an error from querying the SQLite database
    if (err) return false;

    // Put the data in the dataengine
    int nb = sqlResult.count();
    for (int i = 1 ; i < nb ; ++i) {
        QStringList values;
        values << sqlResult.at(i).at(1); // Date
        values << sqlResult.at(i).at(2); // Payee
        values << sqlResult.at(i).at(3); // Amount

        setData(SRC_SCHEDULED, sqlResult.at(i).at(0), values);
    }

    return true;
}

bool SKGDataEngine::getUnitsData()
{
    removeAllData(SRC_UNITS);
    if (!document) return false;

    SKGStringListList sqlResult;

    // Fetch results in the database
    SKGError err = document->executeSelectSqliteOrder("SELECT id FROM v_unit_display WHERE t_type != 1 ORDER BY t_type ASC, t_name ASC", sqlResult);

    // We may receive an error from querying the SQLite database
    if (err) return false;

    // Put the data in the dataengine
    int nb = sqlResult.count();
    for (int i = 1 ; i < nb ; ++i) {
        int unit_id = SKGServices::stringToInt(sqlResult.at(i).at(0));

        QStringList values;
        SKGUnitObject unit(document, unit_id);

        values << unit.getName();
        values << unit.getSymbol();
        values << SKGServices::doubleToString(unit.getAmount());
        values << unit.getAttribute("t_TYPENLS");
        values << document->formatPercentage(unit.getDailyChange());

        setData(SRC_UNITS, sqlResult.at(i).at(0), values);
    }

    return true;
}

bool SKGDataEngine::getAdvicesData()
{
    removeAllData(SRC_ADVICES);
    if (!document) return false;

    //Get list of ignored advices
    QString currentMonth = QDate::currentDate().toString("yyyy-MM");
    QStringList ignoredAdvices = getDocument()->getParameters("advices", "t_value='I' OR t_value='I_" % currentMonth % '\'');

    //Build the list of all advices by requesting all plugins
    int index = 0;
    while (index >= 0) {
        SKGInterfacePlugin* plugin = SKGMainPanel::getMainPanel()->getPluginByIndex(index);
        if (plugin) {
            foreach(const SKGAdvice & advice, plugin->advices()) {
                if (!ignoredAdvices.contains(advice.getUUID()) && !ignoredAdvices.contains(SKGServices::splitCSVLine(advice.getUUID(), '|').at(0))) {
                    QVariantList values;
                    values.append(SKGServices::intToString(advice.getPriority()));
                    values.append(advice.getShortMessage());
                    values.append(advice.getLongMessage());
                    values.append(advice.getAutoCorrections());

                    setData(SRC_ADVICES, advice.getUUID(), values);
                }
            }
        } else index = -2;
        ++index;
    }

    return true;
}

void SKGDataEngine::setDocument(SKGDocumentBank* iDocument)
{
    document = iDocument;

    // Whenever a table is modified, update sources
    if (document) connect(document, SIGNAL(transactionSuccessfullyEnded(int)), this, SLOT(updateAllSources())); //TODO How to updale only modified sources
}
/*
transactionEnded(int trans)
{
  .. get your list of sources by name ..
  foreach :: updateSourceEvent(name);
}
*/

SKGDocumentBank* SKGDataEngine::getDocument()  const
{
    return document;
}

// This does the magic that allows Plasma to load
// this plugin.  The first argument must match
// the X-Plasma-EngineName in the .desktop file.

K_EXPORT_PLASMA_DATAENGINE(dataengine_skrooge, SKGDataEngine)

// this is needed since skgdataengine is a QObject
#include "skgdataengine.moc"
