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

#include <KActionCollection>
#include <KAboutData>
#include <KGenericFactory>
#include <KStandardDirs>

#include "skgbankpluginwidget.h"
#include "skgaccountboardwidget.h"
#include "skgmainpanel.h"
#include "skghtmlboardwidget.h"
#include "skgaccountobject.h"
#include "skgoperationobject.h"
#include "skgsuboperationobject.h"
#include "skgtraces.h"
#include "skgdocumentbank.h"
#include "skgtransactionmng.h"
#include "skgbankobject.h"

/**
 * This plugin factory.
 */
K_PLUGIN_FACTORY(SKGBankPluginFactory, registerPlugin<SKGBankPlugin>();)
/**
 * This plugin export.
 */
K_EXPORT_PLUGIN(SKGBankPluginFactory("skrooge_bank", "skrooge_bank"))

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

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

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

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

    // Menu
    m_reconciliateAction = new KAction(KIcon("skrooge_duplicate"), i18nc("Verb: Reconciliation is process through which you ensure compliance with your bank's statement", "Reconcile..."), this);
    connect(m_reconciliateAction, SIGNAL(triggered(bool)), this, SLOT(onReconciliate()));
    m_reconciliateAction->setShortcut(Qt::ALT + Qt::Key_R);
    registerGlobalAction("edit_reconciliate", m_reconciliateAction);
    return true;
}

int SKGBankPlugin::getNbDashboardWidgets()
{
    return 4;
}

QString SKGBankPlugin::getDashboardWidgetTitle(int iIndex)
{
    if (iIndex == 0) {
        return i18nc("Noun, a list of bank accounts", "Accounts (Light)");
    } else if (iIndex == 1) {
        return i18nc("Noun, a list of bank accounts", "Accounts (Full)");
    } else if (iIndex == 2) {
        return i18nc("Noun, a list of banks", "Banks (Light)");
    }
    return i18nc("Noun, a list of banks", "Banks (Full)");
}

SKGBoardWidget* SKGBankPlugin::getDashboardWidget(int iIndex)
{
    if (iIndex == 0) {
        return new SKGAccountBoardWidget(m_currentBankDocument);
    } else if (iIndex == 1) return new SKGHtmlBoardWidget(m_currentBankDocument,
                                       getDashboardWidgetTitle(iIndex),
                                       KStandardDirs().findResource("data", "skrooge/html/default/account_table.html"),
                                       QStringList() << "v_account_display", true);
    else if (iIndex == 2) {
        SKGHtmlBoardWidget* w = new SKGHtmlBoardWidget(m_currentBankDocument,
                getDashboardWidgetTitle(iIndex),
                KStandardDirs().findResource("data", "skrooge/html/default/bank_table_light.html"),
                QStringList() << "v_account_display");

        QStringList overlayopen;
        overlayopen.push_back("skg_open");
        KAction* open = new KAction(KIcon("view-investment", NULL, overlayopen), i18nc("Verb", "Open report..."), w);
        connect(open, SIGNAL(triggered(bool)), SKGMainPanel::getMainPanel(), SLOT(openPage()));
        QString u = QString("skg://skrooge_report_plugin/?grouped=Y&transfers=Y&tracked=Y&expenses=Y&incomes=Y&lines2=t_BANK&currentPage=-1&mode=0&interval=3&period=0") %
                    "&tableAndGraphState.graphMode=2&tableAndGraphState.allPositive=N&tableAndGraphState.show=graph&columns=" % SKGServices::encodeForUrl("#NOTHING#");
        open->setData(u);

        w->addAction(open);
        return w;
    }
    return new SKGHtmlBoardWidget(m_currentBankDocument,
                                  getDashboardWidgetTitle(iIndex),
                                  KStandardDirs().findResource("data", "skrooge/html/default/bank_table.html"),
                                  QStringList() << "v_account_display", true);
}

SKGTabPage* SKGBankPlugin::getWidget()
{
    SKGTRACEINFUNC(10);
    return new SKGBankPluginWidget(m_currentBankDocument);
}

QString SKGBankPlugin::title() const
{
    return i18nc("Display a list of Accounts", "Accounts");
}

QString SKGBankPlugin::icon() const
{
    return "view-bank";
}

QString SKGBankPlugin::toolTip() const
{
    return i18nc("This allows the user to manage his list of accounts", "Manage your accounts");
}

QStringList SKGBankPlugin::tips() const
{
    QStringList output;
    output.push_back(i18nc("Description of a tip", "<p>... you can associate a logo with your banks.</p>"));
    output.push_back(i18nc("Description of a tip", "<p>... accounts can be merged by drag & drop.</p>"));
    return output;
}

int SKGBankPlugin::getOrder() const
{
    // Must be one of the first
    return 10;
}

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

void SKGBankPlugin::refresh()
{
    SKGTRACEINFUNC(10);
    if (m_currentBankDocument && SKGMainPanel::getMainPanel()) {
        SKGObjectBase::SKGListSKGObjectBase selection = SKGMainPanel::getMainPanel()->getSelectedObjects();
        if (selection.count() > 0) {
            bool onAccount = (selection.at(0).getRealTable() == "account");
            if (m_reconciliateAction) {
                m_reconciliateAction->setEnabled(onAccount);
            }
        } else {
            if (m_reconciliateAction) {
                m_reconciliateAction->setEnabled(false);
            }
        }
    }
}

void SKGBankPlugin::onReconciliate()
{
    if (m_currentBankDocument && SKGMainPanel::getMainPanel()) {
        // Open in operation plugin
        SKGObjectBase::SKGListSKGObjectBase selection = SKGMainPanel::getMainPanel()->getSelectedObjects();
        int nb = selection.count();
        for (int i = 0; i < nb; ++i) {
            SKGAccountObject accountObj(selection[i]);
            SKGMainPanel::getMainPanel()->openPage("skg://skrooge_operation_plugin/?modeInfoZone=1&currentPage=-1&account=" % SKGServices::encodeForUrl(accountObj.getName()));
        }
    }
}

SKGAdviceList SKGBankPlugin::advice(const QStringList& iIgnoredAdvice)
{
    SKGTRACEINFUNC(10);
    SKGAdviceList output;

    // Get bank without accounts
    if (!iIgnoredAdvice.contains("skgbankplugin_withoutaccount")) {
        SKGStringListList result;
        m_currentBankDocument->executeSelectSqliteOrder("SELECT bank.t_name FROM bank WHERE NOT EXISTS (SELECT 1 FROM account WHERE account.rd_bank_id=bank.id)", result);
        int nb = result.count();
        for (int i = 1; i < nb; ++i) {  // Ignore header
            // Get parameters
            QStringList line = result.at(i);
            QString bank = line.at(0);

            SKGAdvice ad;
            ad.setUUID("skgbankplugin_withoutaccount|" % bank);
            ad.setPriority(3);
            ad.setShortMessage(i18nc("A bank is in the list of used banks, but it doesn't have any account attached", "Bank '%1' has no account", bank));
            ad.setLongMessage(i18nc("User can delete banks with no accounts", "Don't forget to remove useless banks"));
            QStringList autoCorrections;
            autoCorrections.push_back(i18nc("Action to delete a bank", "Delete '%1'", bank));
            ad.setAutoCorrections(autoCorrections);
            output.push_back(ad);
        }
    }

    // Get accounts closed with money
    if (!iIgnoredAdvice.contains("skgbankplugin_closedaccount")) {
        SKGStringListList result;
        m_currentBankDocument->executeSelectSqliteOrder("SELECT t_name FROM v_account_amount WHERE f_CURRENTAMOUNT>0.1 AND t_close='Y'", result);
        int nb = result.count();
        for (int i = 1; i < nb; ++i) {  // Ignore header
            // Get parameters
            QStringList line = result.at(i);
            QString account = line.at(0);

            SKGAdvice ad;
            ad.setUUID("skgbankplugin_closedaccount|" % account);
            ad.setPriority(3);
            ad.setShortMessage(i18nc("A account is closed but the amount is not equal to 0", "Closed account '%1' still has money", account));
            ad.setLongMessage(i18nc("Advice on making the best (long)", "This is may be not normal"));
            QList<SKGAdvice::SKGAdviceAction> autoCorrections;
            {
                SKGAdvice::SKGAdviceAction a;
                a.Title = i18nc("Action to reopen the account", "Reopen '%1'", account);
                a.IconName = "edit_undo";
                a.IsRecommended = false;
                autoCorrections.push_back(a);
            }
            {
                SKGAdvice::SKGAdviceAction a;
                a.Title = i18nc("Action to create a fake operation to set the amount of the account to 0", "Create fake operation");
                a.IconName = "edit-delete";
                a.IsRecommended = true;
                autoCorrections.push_back(a);
            }
            ad.setAutoCorrections(autoCorrections);
            output.push_back(ad);
        }
    }

    return output;
}

SKGError SKGBankPlugin::executeAdviceCorrection(const QString& iAdviceIdentifier, int iSolution)
{
    if (m_currentBankDocument && iAdviceIdentifier.startsWith(QLatin1String("skgbankplugin_withoutaccount|"))) {
        // Get parameters
        QString bank = iAdviceIdentifier.right(iAdviceIdentifier.length() - 29);

        SKGError err;
        {
            SKGBEGINTRANSACTION(*m_currentBankDocument, i18nc("Delete banks with no account", "Delete unused banks")  , err);

            SKGBankObject bankObj(m_currentBankDocument);
            err = bankObj.setName(bank);
            IFOKDO(err, bankObj.load())
            IFOKDO(err, bankObj.remove())
        }

        // status bar
        IFOKDO(err, SKGError(0, i18nc("Successfully deleted a bank with no account", "Unused bank deleted")))
        else {
            err.addError(ERR_FAIL, i18nc("Could not delete a bank with no account", "Unused bank deletion failed"));
        }

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

        return SKGError();
    } else if (m_currentBankDocument && iAdviceIdentifier.startsWith(QLatin1String("skgbankplugin_closedaccount|"))) {
        // Get parameters
        QString account = iAdviceIdentifier.right(iAdviceIdentifier.length() - 28);

        SKGAccountObject accountObj(m_currentBankDocument);
        SKGError err = accountObj.setName(account);
        IFOKDO(err, accountObj.load())

        if (iSolution == 0) {
            {
                SKGBEGINTRANSACTION(*m_currentBankDocument, i18nc("Reopen a closed account", "Reopen account '%1'", account)  , err);
                IFOKDO(err, accountObj.setClosed(false))
                IFOKDO(err, accountObj.save())
            }

            // status bar
            IFOKDO(err, SKGError(0, i18nc("Successfully reopen account", "Account reopened")))
            else {
                err.addError(ERR_FAIL, i18nc("Failure", "reopening of the account failed"));
            }
        } else if (iSolution == 1) {
            {
                SKGBEGINTRANSACTION(*m_currentBankDocument, i18nc("Noun, name of the user action", "Create fake operation"), err);

                SKGOperationObject op;
                IFOKDO(err, accountObj.setClosed(false))
                IFOKDO(err, accountObj.addOperation(op))
                IFOKDO(err, op.setDate(QDate::currentDate()))
                IFOKDO(err, op.setComment(i18nc("Noun, default comment for a fake operation", "Fake operation")))
                SKGUnitObject unit;
                IFOKDO(err, accountObj.getUnit(unit))
                IFOKDO(err, op.setUnit(unit))
                IFOKDO(err, op.save())

                SKGSubOperationObject sop;
                IFOKDO(err, op.addSubOperation(sop))
                IFOKDO(err, sop.setQuantity(-accountObj.getAmount(QDate::currentDate())))
                IFOKDO(err, sop.save())

                // Send message
                IFOKDO(err, op.getDocument()->sendMessage(i18nc("An information to the user that something was added", "The operation '%1' has been added", op.getDisplayName()), SKGDocument::Hidden));
            }

            // status bar
            IFOKDO(err, SKGError(0, i18nc("Successful message after an user action", "Fake operation created.")))
            else {
                err.addError(ERR_FAIL, i18nc("Error message",  "Creation failed"));
            }
        }

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

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

#include "skgbankplugin.moc"
