/***************************************************************************
 *   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 import and export operation.
 *
 * @author Stephane MANKOWSKI / Guillaume DE BURE
 */
#include "skgimportexportplugin.h"
#include "skgtraces.h"
#include "skgerror.h"
#include "skgbankincludes.h"
#include "skgmainpanel.h"
#include "skgoperationobject.h"
#include "skgimportexport_settings.h"

#include <kactioncollection.h>
#include <kaction.h>
#include <kactionmenu.h>
#include <kfiledialog.h>
#include <kaboutdata.h>

#include <QTextCodec>
#include <QDomDocument>
#include <kencodingfiledialog.h>
#include <KMessageBox>
#include <kpassworddialog.h>

/**
 * This plugin factory.
 */
K_PLUGIN_FACTORY(SKGImportExportPluginFactory, registerPlugin<SKGImportExportPlugin>();)
/**
 * This plugin export.
 */
K_EXPORT_PLUGIN(SKGImportExportPluginFactory("skrooge_importexport", "skrooge_importexport"))

SKGImportExportPlugin::SKGImportExportPlugin(QObject* iParent, const QVariantList& /*iArg*/) : SKGInterfacePlugin(iParent)
{
    SKGTRACEIN(10, "SKGImportExportPlugin::SKGImportExportPlugin");
}

SKGImportExportPlugin::~SKGImportExportPlugin()
{
    SKGTRACEIN(10, "SKGImportExportPlugin::~SKGImportExportPlugin");
    m_currentBankDocument = NULL;

    m_importAction = NULL;
    m_importCsvUnitAction = NULL;
    m_exportFileAction = NULL;
    m_processingFoundTransfert = NULL;
    m_processingAnonymize = NULL;
    m_processingBank = NULL;
    m_validateImportedOperationsAction = NULL;
    m_openNotValidatedAction = NULL;
    m_mergeImportedOperationAction = NULL;
}

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

    // Tell the host application to load my GUI component
    setComponentData(KGlobal::mainComponent());
    setXMLFile("../skrooge_importexport/skrooge_importexport.rc");

    //Imports
    KActionMenu* imports = new  KActionMenu(KIcon("document-import"), i18nc("Verb, action to import items from another format", "Import"), this);
    actionCollection()->addAction(QLatin1String("import"), imports);

    //Import
    QStringList overlay;
    overlay.push_back("skrooge");

    m_importAction = new KAction(KIcon("document-import", NULL, overlay), i18nc("Verb, action to import items from another format", "Import..."), this);
    m_importAction->setShortcut(Qt::CTRL + Qt::ALT + Qt::Key_I);
    connect(m_importAction, SIGNAL(triggered(bool)), SLOT(import()));
    actionCollection()->addAction(QLatin1String("import_operation"), m_importAction);
    imports->addAction(m_importAction);
    m_importAction->setShortcut(Qt::CTRL + Qt::META + Qt::Key_I);

    if (SKGMainPanel::getMainPanel()) SKGMainPanel::getMainPanel()->registerGlobalAction("import_operation", m_importAction);

    //Import CSV Unit
    QStringList overlaycsv;
    overlaycsv.push_back("text-csv");
    m_importCsvUnitAction = new KAction(KIcon("document-import", NULL, overlaycsv), i18nc("Verb, action to import", "Import currency values..."), this);
    connect(m_importCsvUnitAction, SIGNAL(triggered(bool)), SLOT(import()));
    actionCollection()->addAction(QLatin1String("import_csv_unit"), m_importCsvUnitAction);
    imports->addAction(m_importCsvUnitAction);

    if (SKGMainPanel::getMainPanel()) SKGMainPanel::getMainPanel()->registerGlobalAction("import_csv_unit", m_importCsvUnitAction);

    //Exports
    KActionMenu* exports = new  KActionMenu(KIcon("document-export"), i18nc("Verb, action to export items in another format", "Export"), this);
    actionCollection()->addAction(QLatin1String("export"), exports);

    //Export
    m_exportFileAction = new KAction(KIcon("document-export"), i18nc("Verb, action to export items to another format", "Export..."), this);
    connect(m_exportFileAction, SIGNAL(triggered(bool)), SLOT(exportFile()));
    actionCollection()->addAction(QLatin1String("export_operation"), m_exportFileAction);
    exports->addAction(m_exportFileAction);
    m_exportFileAction->setShortcut(Qt::CTRL + Qt::META + Qt::Key_E);

    if (SKGMainPanel::getMainPanel()) SKGMainPanel::getMainPanel()->registerGlobalAction("export_operation", m_exportFileAction);

    //Processing
    KActionMenu* processing = new  KActionMenu(KIcon("tools-wizard"), i18nc("Noun, apply some kind of transformation on an item", "Processing"), this);
    actionCollection()->addAction(QLatin1String("processing"), processing);

    //Processing found and group
    QStringList overlaytransfers;
    overlaytransfers.push_back("view-financial-transfer");

    m_processingFoundTransfert = new KAction(KIcon("tools-wizard", NULL, overlaytransfers), i18nc("Verb, action to find and group transfers", "Find and group transfers"), this);
    connect(m_processingFoundTransfert, SIGNAL(triggered(bool)), SLOT(foundTransfer()));
    actionCollection()->addAction(QLatin1String("process_foundtransfer"), m_processingFoundTransfert);
    processing->addAction(m_processingFoundTransfert);
    m_processingFoundTransfert->setShortcut(Qt::CTRL + Qt::META + Qt::Key_G);

    if (SKGMainPanel::getMainPanel()) SKGMainPanel::getMainPanel()->registerGlobalAction("process_foundtransfer", m_processingFoundTransfert);

    m_processingAnonymize = new KAction(KIcon("tools-wizard", NULL, overlaytransfers), i18nc("Verb, action to anonymize a document", "Anonymize"), this);
    connect(m_processingAnonymize, SIGNAL(triggered(bool)), SLOT(anonymize()));
    actionCollection()->addAction(QLatin1String("process_anonymize"), m_processingAnonymize);
    processing->addAction(m_processingAnonymize);

    if (SKGMainPanel::getMainPanel()) SKGMainPanel::getMainPanel()->registerGlobalAction("process_anonymize", m_processingAnonymize);

    //Processing banks
    m_processingBank = new KAction(KIcon("tools-wizard"), i18nc("Verb, action to clean an import", "Clean bank's imports"), this);
    connect(m_processingBank, SIGNAL(triggered(bool)), SLOT(cleanBanks()));
    actionCollection()->addAction(QLatin1String("process_banks"), m_processingBank);
    processing->addAction(m_processingBank);

    if (SKGMainPanel::getMainPanel()) SKGMainPanel::getMainPanel()->registerGlobalAction("process_banks", m_processingBank);

    //Processing banks
    QStringList overlayValidate;
    overlayValidate.push_back("dialog-ok-apply");
    m_validateImportedOperationsAction = new KAction(KIcon("document-import", NULL, overlayValidate), i18nc("Verb, action to validate imported operations", "Validate imported operations"), this);
    connect(m_validateImportedOperationsAction, SIGNAL(triggered(bool)), SLOT(validateImportedOperations()));
    actionCollection()->addAction(QLatin1String("validate_imported_operation"), m_validateImportedOperationsAction);
    m_validateImportedOperationsAction->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_V);

    if (SKGMainPanel::getMainPanel()) SKGMainPanel::getMainPanel()->registerGlobalAction("validate_imported_operation", m_validateImportedOperationsAction);

    QStringList overlayopen;
    overlayopen.push_back("skg_open");
    m_openNotValidatedAction = new KAction(KIcon("document-import", NULL, overlayopen), i18nc("Verb, action to open", "Open imported operations not yet validated..."), this);
    connect(m_openNotValidatedAction, SIGNAL(triggered(bool)), this, SLOT(openNotValidated()));
    actionCollection()->addAction(QLatin1String("view_open_not_validated"), m_openNotValidatedAction);
    m_openNotValidatedAction->setShortcut(Qt::META + Qt::Key_V);

    if (SKGMainPanel::getMainPanel()) SKGMainPanel::getMainPanel()->registerGlobalAction("view_open_not_validated", m_openNotValidatedAction);

    m_mergeImportedOperationAction = new KAction(KIcon("merge"), i18nc("Verb, action to merge", "Merge imported operations"), this);
    connect(m_mergeImportedOperationAction, SIGNAL(triggered(bool)), SLOT(mergeImportedOperation()));
    actionCollection()->addAction(QLatin1String("merge_imported_operation"), m_mergeImportedOperationAction);
    m_mergeImportedOperationAction->setShortcut(Qt::CTRL + Qt::ALT + Qt::Key_M);

    if (SKGMainPanel::getMainPanel()) SKGMainPanel::getMainPanel()->registerGlobalAction("merge_imported_operation", m_mergeImportedOperationAction);

    //Get last argument
    connect(this, SIGNAL(importFile(QString)), this, SLOT(import(QString)), Qt::QueuedConnection);

    //Open/import input file
    int nbArg = iArgument.count();
    if (nbArg) {
        QString filename = iArgument.at(nbArg - 1);
        QString extension = QFileInfo(filename).suffix().toUpper();
        QString extensionDocument = m_currentBankDocument->getFileExtension().toUpper();
        if (QFile(filename).exists() && extension != extensionDocument) {
            processArguments(iArgument);
        }
    }

    //Krunner operations
    QString dirName = QDir::homePath() % "/.skrooge/";
    QStringList fileList = QDir(dirName).entryList(QDir::Files);
    if (fileList.count()) m_currentBankDocument->sendMessage(i18nc("Information message", "You have some krunner's operations to import"));

    return true;
}

void SKGImportExportPlugin::processArguments(const QStringList& iArgument)
{
    SKGTRACEIN(10, "SKGImportExportPlugin::processArguments");
    int nbArg = iArgument.count();
    if (nbArg) {
        QString filename = iArgument.at(nbArg - 1);
        if (QFile(filename).exists()) Q_EMIT importFile(filename);
    }
}

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

    ui.kHeaderPositionFrm->hide();
    ui.kColumnsPositionsFrm->hide();
    ui.kCsvMappingFrm->hide();

    return widget;
}

KConfigSkeleton* SKGImportExportPlugin::getPreferenceSkeleton()
{
    return skgimportexport_settings::self();
}

QString SKGImportExportPlugin::title() const
{
    return i18nc("Noun", "Import / Export");
}

QString SKGImportExportPlugin::icon() const
{
    return "utilities-file-archiver";
}

QString SKGImportExportPlugin::toolTip() const
{
    return i18nc("Noun", "Import / Export management");
}

QStringList SKGImportExportPlugin::tips() const
{
    QStringList output;
    output.push_back(i18nc("Description of a tips", "<p>... skrooge is able to detect automatically transfers after an import.</p>"));
    output.push_back(i18nc("Description of a tips", "<p>... you can import many files in one shot.</p>"));
    output.push_back(i18nc("Description of a tips", "<p>... unit amounts can be imported through a CSV file.</p>"));
    output.push_back(i18nc("Description of a tips", "<p>... you can customize your CSV import with regular expressions defined in setting panel.</p>"));
    output.push_back(i18nc("Description of a tips", "<p>... you can export the full content of your document into a XML file.</p>"));
    output.push_back(i18nc("Description of a tips", "<p>... you can apply automatic rules after an import to set the right categories.</p>"));
    return output;
}

int SKGImportExportPlugin::getOrder() const
{
    return 70;
}

void SKGImportExportPlugin::refresh()
{
    SKGTRACEIN(10, "SKGImportExportPlugin::refresh");

    if (m_currentBankDocument && SKGMainPanel::getMainPanel()) {
        bool test = (m_currentBankDocument->getDatabase() != NULL);
        if (m_openNotValidatedAction) m_openNotValidatedAction->setEnabled(test);
        if (m_importAction) m_importAction->setEnabled(test);
        if (m_exportFileAction) m_exportFileAction->setEnabled(test);
        if (m_importCsvUnitAction) m_importCsvUnitAction->setEnabled(test);
        if (m_processingFoundTransfert) m_processingFoundTransfert->setEnabled(test);
        if (m_processingAnonymize) m_processingAnonymize->setEnabled(test);
        if (m_processingBank) m_processingBank->setEnabled(test);

        SKGObjectBase::SKGListSKGObjectBase selection = SKGMainPanel::getMainPanel()->getSelectedObjects();
        if (selection.count() > 0 && test) {
            bool onOperation = (selection.at(0).getRealTable() == "operation" &&  selection.at(0).getTable() != "v_operation_consolidated");
            if (m_validateImportedOperationsAction) m_validateImportedOperationsAction->setEnabled(onOperation);
            if (m_mergeImportedOperationAction) m_mergeImportedOperationAction->setEnabled(onOperation);
        } else {
            if (m_validateImportedOperationsAction) m_validateImportedOperationsAction->setEnabled(false);
            if (m_mergeImportedOperationAction) m_mergeImportedOperationAction->setEnabled(false);
        }
    }
}

void SKGImportExportPlugin::import(const QString& iFile)
{
    SKGError err;
    SKGTRACEINRC(10, "SKGImportExportPlugin::import", err);
    if (m_currentBankDocument) {
        QList<QString> fileNames;
        QString lastCodecUsed = m_currentBankDocument->getParameter("SKG_LAST_CODEC_USED_FOR_IMPORT");
        if (lastCodecUsed.isEmpty()) lastCodecUsed = QTextCodec::codecForLocale()->name();
        QString codec;

        if (iFile.isEmpty()) {
            //Panel to ask files
            KEncodingFileDialog::Result result = KEncodingFileDialog::getOpenUrlsAndEncoding(lastCodecUsed, "kfiledialog:///IMPEXP",
                                                 sender() == m_importCsvUnitAction ? QString("*.csv|" % i18nc("A file format", "CSV Files")) :
                                                 SKGImportExportManager::getImportMimeTypeFilter(),
                                                 SKGMainPanel::getMainPanel());
            fileNames = result.URLs.toStringList();
            codec = result.encoding;
        } else {
            fileNames.push_back(iFile);
            QString codec = lastCodecUsed;
        }

        int nbFiles = fileNames.count();
        if (nbFiles) {
            {
                SKGBEGINPROGRESSTRANSACTION(*m_currentBankDocument, i18nc("Noun, name of the user action", "Import with codec %1", codec), err, nbFiles);

                //Read Setting
                bool automatic_validation = skgimportexport_settings::automatic_validation();
                bool automatic_rule = skgimportexport_settings::apply_rules();

                if (!err) err = m_currentBankDocument->setParameter("SKG_LAST_CODEC_USED_FOR_IMPORT", codec);

                for (int i = 0; !err && i < nbFiles; ++i) {
                    //Get Filename
                    QString fileName = fileNames.at(i);

                    //Import
                    SKGImportExportManager imp1(m_currentBankDocument, fileName);
                    imp1.setAutomaticValidation(automatic_validation);
                    imp1.setAutomaticApplyRules(i == nbFiles - 1 ? automatic_rule : false); //Apply rules only on the last import for better performances
                    imp1.setCodec(codec);

                    if (QFileInfo(fileName).suffix().toUpper() == "CSV") { //TODO: Better
                        QMap<QString, QString> parameters = imp1.getImportParameters();

                        parameters["automatic_search_header"] = (skgimportexport_settings::automatic_search_header() ? "Y" : "N");
                        parameters["header_position"] = SKGServices::intToString(skgimportexport_settings::header_position());

                        parameters["mapping_date"] = skgimportexport_settings::mapping_date();
                        parameters["mapping_account"] = skgimportexport_settings::mapping_account();
                        parameters["mapping_number"] = skgimportexport_settings::mapping_number();
                        parameters["mapping_mode"] = skgimportexport_settings::mapping_mode();
                        parameters["mapping_payee"] = skgimportexport_settings::mapping_payee();
                        parameters["mapping_comment"] = skgimportexport_settings::mapping_comment();
                        parameters["mapping_status"] = skgimportexport_settings::mapping_status();
                        parameters["mapping_bookmarked"] = skgimportexport_settings::mapping_bookmarked();
                        parameters["mapping_category"] = skgimportexport_settings::mapping_category();
                        parameters["mapping_amount"] = skgimportexport_settings::mapping_amount();
                        parameters["mapping_quantity"] = skgimportexport_settings::mapping_quantity();
                        parameters["mapping_unit"] = skgimportexport_settings::mapping_unit();
                        parameters["mapping_idtransaction"] = skgimportexport_settings::mapping_idtransaction();
                        parameters["mapping_idgroup"] = skgimportexport_settings::mapping_idgroup();
                        parameters["mapping_sign"] = skgimportexport_settings::mapping_sign();
                        parameters["mapping_debit"] = skgimportexport_settings::mapping_debit();
                        parameters["mapping_property"] = skgimportexport_settings::mapping_property();

                        parameters["automatic_search_columns"] = (skgimportexport_settings::automatic_search_columns() ? "Y" : "N");
                        parameters["columns_positions"] = skgimportexport_settings::columns_positions();
                        parameters["mode_csv_unit"] = (sender() == m_importCsvUnitAction ? "Y" : "N");

                        imp1.setImportParameters(parameters);
                    }


                    if (!err) err = imp1.importFile();
                    if (err && err.getReturnCode() == ERR_ENCRYPTION) {
                        QString pwd;
                        QString additionalMessage;
                        do {
                            //Reset error
                            err = SKGError(ERR_FAIL, i18nc("Error message", "Import of file named '%1' failed", fileName));
                            pwd = "";

                            //Use password dialog
                            QApplication::restoreOverrideCursor();
                            QPointer<KPasswordDialog> dlg = new KPasswordDialog(SKGMainPanel::getMainPanel());
                            dlg->setPrompt(additionalMessage % i18nc("Question", "This file seems to be protected.\nPlease enter the password."));
                            if (dlg->exec() == QDialog::Accepted) pwd = dlg->password();
                            delete dlg;
                            QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));

                            //Load file
                            if (!pwd.isEmpty()) {
                                QMap<QString, QString> parameters;
                                parameters["password"] = pwd;
                                imp1.setImportParameters(parameters);
                                err = imp1.importFile();
                                if (err) {
                                    if (err.getReturnCode() == ERR_ENCRYPTION) {
                                        additionalMessage = i18nc("The user did not provide the correct password", "<b>Wrong password.</b>\n");
                                    } else {
                                        //Import error
                                        break;
                                    }
                                }
                            } else {
                                err = SKGError(ERR_FAIL, i18nc("Error message", "Import canceled by user"));
                                break;
                            }
                        } while (err);
                    }

                    if (err) {
                        err.addError(ERR_FAIL, i18nc("Error message", "Import of file named '%1' failed", fileName));
                    }

                    if (!err) err = m_currentBankDocument->stepForward(i + 1);
                }
            }
        }

        //status bar
        if (!err) {
            err = SKGError(0, i18np("%1 file successfully imported.", "%1 files successfully imported.", nbFiles));
        }

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

        //Open last modified operations if setting activated
        if (!err) openLastModifiedIfSetting();
    }
}

void SKGImportExportPlugin::exportFile()
{
    SKGError err;
    SKGTRACEINRC(10, "SKGImportExportPlugin::exportFile", err);
    if (m_currentBankDocument) {
        QString lastCodecUsed = m_currentBankDocument->getParameter("SKG_LAST_CODEC_USED_FOR_IMPORT");
        if (lastCodecUsed.isEmpty()) lastCodecUsed = QTextCodec::codecForLocale()->name();
        QString fileName = SKGMainPanel::getSaveFileName("kfiledialog:///IMPEXP", SKGImportExportManager::getExportMimeTypeFilter(),
                           SKGMainPanel::getMainPanel(), QString(), &lastCodecUsed);
        if (fileName.isEmpty() || !m_currentBankDocument) return;


        {
            SKGBEGINTRANSACTION(*m_currentBankDocument, i18nc("Noun, name of the user action", "Export"), err);
            if (!err) {
                SKGImportExportManager imp1(m_currentBankDocument, fileName);
                imp1.setCodec(lastCodecUsed);
                err = imp1.exportFile();
            }
        }

        //status bar
        if (!err) err = SKGError(0, i18nc("Successful message after an user action", "File '%1' successfully exported.", fileName));
        else err.addError(ERR_FAIL, i18nc("Error message", "Export of '%1' failed", fileName));

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

void SKGImportExportPlugin::anonymize()
{
    SKGError err;
    SKGTRACEINRC(10, "SKGImportExportPlugin::anonymize", err);
    if (m_currentBankDocument) {
        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
        SKGImportExportManager imp1(m_currentBankDocument);
        err = imp1.anonymize();
        QApplication::restoreOverrideCursor();

        //status bar
        if (!err) err = SKGError(0, i18nc("An anonymized document is a document where all private data has been removed", "Document anonymized."));

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

void SKGImportExportPlugin::foundTransfer()
{
    SKGError err;
    SKGTRACEINRC(10, "SKGImportExportPlugin::foundTransfer", err);
    if (m_currentBankDocument) {
        int NbOperationsMerged = 0;
        {
            SKGBEGINTRANSACTION(*m_currentBankDocument, i18nc("Noun, name of the user action", "Find and group transfers"), err);
            if (!err) {
                SKGImportExportManager imp1(m_currentBankDocument);
                err = imp1.findAndGroupTransfers(NbOperationsMerged);
            }
        }

        //status bar
        if (!err) err = SKGError(0, i18np("Document successfully processed. %1 operation merged.",
                                              "Document successfully processed. %1 operations merged.", NbOperationsMerged));
        else err.addError(ERR_FAIL, i18nc("Error message", "Processing failed."));

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

        //Open last modified operations if setting activated
        if (!err) openLastModifiedIfSetting();
    }
}

void SKGImportExportPlugin::cleanBanks()
{
    SKGError err;
    SKGTRACEINRC(10, "SKGImportExportPlugin::cleanBanks", err);
    {
        SKGBEGINTRANSACTION(*m_currentBankDocument, i18nc("Noun, name of the user action", "Clean bank's imports"), err);
        if (!err) {
            SKGImportExportManager imp1(m_currentBankDocument);
            err = imp1.cleanBankImport();
        }
    }

    //status bar
    if (!err) err = SKGError(0, i18nc("Successful message after an user action", "Document successfully cleaned."));
    else err.addError(ERR_FAIL, i18nc("Error message", "Clean failed."));

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

    //Open last modified operations if setting activated
    if (!err) openLastModifiedIfSetting();
}

void SKGImportExportPlugin::validateImportedOperations()
{
    SKGError err;
    SKGTRACEINRC(10, "SKGImportExportPlugin::validateImportedOperations", err);

    if (SKGMainPanel::getMainPanel() && m_currentBankDocument) {
        SKGObjectBase::SKGListSKGObjectBase selection = SKGMainPanel::getMainPanel()->getSelectedObjects();
        int nb = selection.count();
        {
            SKGBEGINPROGRESSTRANSACTION(*m_currentBankDocument, i18nc("Noun, name of the user action", "Validate imported operations"), err, nb);
            for (int i = 0; !err && i < nb; ++i) {
                SKGOperationObject op = selection[i];
                if (op.getAttribute("t_imported") == "P") {
                    err = op.setImported(true);
                    if (!err) err = op.save();
                }
                if (!err) err = m_currentBankDocument->stepForward(i + 1);
            }
        }
    }

    //status bar
    if (!err) err = SKGError(0, i18nc("Successful message after an user action", "Imported operations validated."));
    else err.addError(ERR_FAIL, i18nc("Error message", "Validation failed"));

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

void SKGImportExportPlugin::mergeImportedOperation()
{
    SKGError err;
    SKGTRACEINRC(10, "SKGImportExportPlugin::mergeImportedOperation", err);

    if (SKGMainPanel::getMainPanel() && m_currentBankDocument) {
        SKGObjectBase::SKGListSKGObjectBase selection = SKGMainPanel::getMainPanel()->getSelectedObjects();
        int nb = selection.count();
        err = SKGError(ERR_INVALIDARG, i18nc("Error message", "Invalid selection, you must select one imported operation and one manual operation with same amounts"));
        if (nb == 2) {
            SKGOperationObject opImported = selection.at(0);
            SKGOperationObject opManual = selection.at(1);
            if (opImported.isImported() != opManual.isImported()) {
                if (!opImported.isImported())  qSwap(opImported, opManual);
                int rc = KMessageBox::Yes;
                if (opImported.getCurrentAmount() != opManual.getCurrentAmount()) {
                    rc = KMessageBox::questionYesNo(SKGMainPanel::getMainPanel(),
                                                    i18nc("Question",  "Amounts are not equals. Do you want to force the merge ?"),
                                                    i18nc("Question",  "Do you want to force the merge ?"),
                                                    KStandardGuiItem::yes(), KStandardGuiItem::no()
                                                   );
                }

                if (rc == KMessageBox::Yes) {
                    SKGBEGINTRANSACTION(*m_currentBankDocument, i18nc("Noun, name of the user action", "Merge imported operations"), err);
                    err = opManual.mergeAttribute(opImported);
                    if (err) err.addError(ERR_FAIL, i18nc("Error message", "Merge failed"));
                }
            }
        }
    }

    //status bar
    if (!err) err = SKGError(0, i18nc("Successful message after an user action", "Imported operations merged."));

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

void SKGImportExportPlugin::openLastModifiedIfSetting()
{
    //Read Setting
    bool open_after_import_or_processing = skgimportexport_settings::open_after_import_or_processing();
    if (open_after_import_or_processing) {
        //Open last operations
        KAction* action = SKGMainPanel::getMainPanel()->getGlobalAction("view_open_last_modified");
        if (action) {
            action->trigger();
        }
    }
}

void SKGImportExportPlugin::openNotValidated() const
{
    SKGTRACEIN(10, "SKGImportExportPlugin::openNotValidated");
    QString wc = "t_imported='P'";
    QString title = i18nc("Noun, a list of items", "Operations imported and not yet validated");

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

    root.setAttribute("operationWhereClause", wc);
    root.setAttribute("title", title);
    root.setAttribute("title_icon", icon());

    if (SKGMainPanel::getMainPanel()) SKGMainPanel::getMainPanel()->openPage(SKGMainPanel::getMainPanel()->getPluginByName("Skrooge operation plugin"), -1, doc.toString());
}

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

    //Check operations not validated
    bool exist = false;
    m_currentBankDocument->existObjects("operation", "t_imported='P'", exist);
    if (exist) {
        SKGAdvice ad;
        ad.setUUID("skgimportexportplugin_notvalidated");
        ad.setPriority(4);
        ad.setShortMessage(i18nc("Advice on making the best (short)", "Many operations imported and not yet validated"));
        ad.setLongMessage(i18nc("Advice on making the best (long)", "After importing operations, you should review them, make corrections on, for instance, category, payee. Once done, you should mark the imported operation as validated, so that you know the operation has been fully processed."));
        QStringList autoCorrections;
        autoCorrections.push_back(i18nc("Advice on making the best (action)", "Open operations imported and not yet validated"));
        autoCorrections.push_back(i18nc("Advice on making the best (action)", "Validate operations that do not require further action"));
        ad.setAutoCorrections(autoCorrections);
        output.push_back(ad);
    }

    //Krunner operations
    QString dirName = QDir::homePath() % "/.skrooge/";
    QStringList fileList = QDir(dirName).entryList(QDir::Files);
    int nb = fileList.count();
    if (nb) {
        QStringList listAccounts;
        m_currentBankDocument->getDistinctValues("account", "t_name", "t_type IN ('C', 'D', 'W') and t_close='N'", listAccounts);
        int nbAccounts = listAccounts.count();
        for (int i = 0; i < nb; ++i) {
            QString fileName = dirName % fileList.at(i);
            QFile file(fileName);
            if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
                QTextStream stream(&file);
                QString action = stream.readLine().trimmed();
                QString date = KGlobal::locale()->formatDate(SKGServices::stringToTime(stream.readLine().trimmed()).date(), KLocale::ShortDate);
                QString amount = m_currentBankDocument->formatMoney(SKGServices::stringToDouble(stream.readLine().trimmed()), m_currentBankDocument->getPrimaryUnit())  ;
                QString payee = stream.readLine().trimmed();
                SKGAdvice ad;
                ad.setUUID("skgimportexportplugin_krunner_" % fileName);
                ad.setPriority(8);
                ad.setShortMessage(i18nc("Advice on making the best (short)", "Krunner's operation ongoing [%1 %2 %3]", date, amount, payee));
                ad.setLongMessage(i18nc("Advice on making the best (long)", "Operations created through krunner have to be fully created in skrooge."));
                QStringList autoCorrections;
                for (int j = 0; j < nbAccounts; ++j) {
                    autoCorrections.push_back(i18nc("Advice on making the best (action)", "Import operation in %1", listAccounts.at(j)));
                }
                autoCorrections.push_back(i18nc("Advice on making the best (action)", "Remove operation"));
                ad.setAutoCorrections(autoCorrections);
                output.push_back(ad);

                //Close file
                file.close();
            }
        }
    }
    return output;
}

SKGError SKGImportExportPlugin::executeAdviceCorrection(const QString& iAdviceIdentifier, int iSolution) const
{
    if (iAdviceIdentifier == "skgimportexportplugin_notvalidated" && m_currentBankDocument) {
        if (iSolution == 0) {
            //Open operations imported and not yet validated
            this->openNotValidated();
        } else {
            //Validate all operations
            SKGError err;
            {
                SKGBEGINTRANSACTION(*m_currentBankDocument, i18nc("Noun, name of the user action", "Validate all operations"), err);
                err = m_currentBankDocument->executeSqliteOrder("UPDATE operation SET t_imported='Y' WHERE t_imported='P'");
            }

            //status bar
            if (!err) err = SKGError(0, i18nc("Message for successful user action", "Operations validated."));
            else err.addError(ERR_FAIL, i18nc("Error message", "Validation failed"));

            //Display error
            SKGMainPanel::displayErrorMessage(err);
        }
        return SKGError();
    } else if (iAdviceIdentifier.startsWith(QLatin1String("skgimportexportplugin_krunner_")) && m_currentBankDocument) {
        SKGError err;
        //Get file name
        QString fileName = iAdviceIdentifier.right(iAdviceIdentifier.length() - 30);
        QFile file(fileName);

        //Get accounts
        QStringList listAccounts;
        m_currentBankDocument->getDistinctValues("account", "t_name", "t_type IN ('C', 'D', 'W') and t_close='N'", listAccounts);
        if (iSolution < listAccounts.count()) {
            //Addition in an account

            if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
                err = SKGError(ERR_FAIL, i18nc("An erro message", "Open file '%1' failed", fileName));
            } else {
                QTextStream stream(&file);
                QString action = stream.readLine().trimmed();
                QDate date = SKGServices::stringToTime(stream.readLine().trimmed()).date();
                double amount = SKGServices::stringToDouble(stream.readLine().trimmed());
                QString payee = stream.readLine().trimmed();

                SKGBEGINTRANSACTION(*m_currentBankDocument, i18nc("Noun, name of the user action", "Import krunner's operation"), err);

                //Get account
                SKGAccountObject act(m_currentBankDocument);
                err = act.setName(listAccounts.at(iSolution));
                if (!err) err = act.load();

                //Get unit
                SKGUnitObject unit(m_currentBankDocument);
                if (!err) err = unit.setName(m_currentBankDocument->getPrimaryUnit().Name);
                if (!err) err = unit.load();

                //Add operation
                SKGOperationObject op;
                if (!err) err = act.addOperation(op);
                if (!err) err = op.setDate(date);
                if (!err) err = op.setUnit(unit);

                if (!payee.isEmpty()) {
                    //Get payee
                    SKGPayeeObject pa;
                    if (!err) err = SKGPayeeObject::createPayee(m_currentBankDocument, payee, pa, true);
                    if (!err) err = op.setPayee(pa);
                }
                if (!err) {
                    int pos1 = fileName.indexOf("{");
                    int pos2 = fileName.indexOf("}");
                    if (pos1 != -1 && pos2 > pos1) err = op.setImportID("KR-" % fileName.mid(pos1 + 1, pos2 - pos1 - 1));
                }
                if (!err) err = op.save();

                //Add suboperation
                SKGSubOperationObject sop;
                if (!err) err = op.addSubOperation(sop);
                if (!err) err = sop.setQuantity(-amount);
                if (!err) err = sop.save();

                //Finalize the importation
                if (!err) {
                    bool automatic_validation = skgimportexport_settings::automatic_validation();
                    bool automatic_rule = skgimportexport_settings::apply_rules();

                    SKGImportExportManager imp1(m_currentBankDocument);
                    imp1.setAutomaticValidation(automatic_validation);
                    imp1.setAutomaticApplyRules(automatic_rule);
                    err = imp1.finalizedImportedOperations();
                }

                //Close file
                file.close();
            }

            //status bar
            if (!err) {
                err = SKGError(0, i18nc("Message for successful user action", "Operations imported."));
                QFile::remove(fileName);
            } else err.addError(ERR_FAIL, i18nc("Error message", "Import failed"));
        } else {
            err = SKGError(0, i18nc("Message for successful user action", "Operations removed."));
            QFile::remove(fileName);
        }

        //Display error
        SKGMainPanel::displayErrorMessage(err);
        return SKGError();
    }
    return SKGInterfacePlugin::executeAdviceCorrection(iAdviceIdentifier, iSolution);
}

#include "skgimportexportplugin.moc"
