/***************************************************************************
 *   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 for KMY import / export.
 *
 * @author Stephane MANKOWSKI / Guillaume DE BURE
 */
#include "skgimportpluginkmy.h"
#include "skgtraces.h"
#include "skgservices.h"
#include "skgbankincludes.h"
#include "skgobjectbase.h"
#include "skgimportexportmanager.h"
#include "skgpayeeobject.h"

#include <klocale.h>
#include <kfilterdev.h>
#include <kgenericfactory.h>

#include <QDomDocument>
#include <QFileInfo>
#include <qmath.h>
#include <qfileinfo.h>

QSet<QString> SKGImportPluginKmy::m_opTreated;
QMap<QString, SKGUnitObject> SKGImportPluginKmy::m_mapIdUnit;
QMap<QString, SKGAccountObject> SKGImportPluginKmy::m_mapIdAccount;
QMap<QString, SKGCategoryObject> SKGImportPluginKmy::m_mapIdCategory;
QMap<QString, SKGPayeeObject> SKGImportPluginKmy::m_mapIdPayee;

/**
 * This plugin factory.
 */
K_PLUGIN_FACTORY(SKGImportPluginKmyFactory, registerPlugin<SKGImportPluginKmy>();)
/**
 * This plugin export.
 */
K_EXPORT_PLUGIN(SKGImportPluginKmyFactory("skrooge_import_kmy", "skrooge_import_kmy"))

SKGImportPluginKmy::SKGImportPluginKmy(QObject* iImporter, const QVariantList& iArg)
    : SKGImportPlugin(iImporter)
{
    SKGTRACEIN(10, "SKGImportPluginKmy::SKGImportPluginKmy");
    Q_UNUSED(iArg);
}

SKGImportPluginKmy::~SKGImportPluginKmy()
{}

bool SKGImportPluginKmy::isImportPossible()
{
    SKGTRACEIN(10, "SKGImportPluginKmy::isImportPossible");
    return isExportPossible();
}

SKGError SKGImportPluginKmy::importFile()
{
    if (!m_importer) return SKGError(ERR_ABORT, i18nc("Error message", "Invalid parameters"));

    SKGError err;
    SKGTRACEINRC(2, "SKGImportPluginKmy::importFile", err);

    //Initialisation
    m_mapIdUnit.clear();
    m_mapIdAccount.clear();
    m_mapIdCategory.clear();
    m_mapIdPayee.clear();

    //Open file
    QIODevice* file = KFilterDev::deviceForFile(m_importer->getLocalFileName(), "application/x-gzip");
    if (!file->open(QIODevice::ReadOnly)) err.setReturnCode(ERR_INVALIDARG).setMessage(i18nc("Error message",  "Open file '%1' failed", m_importer->getFileName().prettyUrl()));
    else {
        QDomDocument doc;

        //Set the file without uncompression
        QString errorMsg;
        int errorLine = 0;
        int errorCol = 0;
        bool contentOK = doc.setContent(file->readAll(), &errorMsg, &errorLine, &errorCol);
        file->close();

        if (!contentOK)err.setReturnCode(ERR_ABORT).setMessage(i18nc("Error message",  "%1-%2: '%3'", errorLine, errorCol, errorMsg)).addError(ERR_INVALIDARG, i18nc("Error message",  "Invalid XML content in file '%1'", m_importer->getFileName().prettyUrl()));
        else {
            //Get root
            QDomElement docElem = doc.documentElement();
            err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import %1 file", "KMY"), 8);

            //Step 1-Get units
            QDomElement securities = docElem.firstChildElement("SECURITIES");
            if (!err && !securities.isNull()) {
                SKGTRACEINRC(10, "SKGImportExportManager::importKMY-SECURITIES", err);
                QDomNodeList securityList = securities.elementsByTagName("SECURITY");
                int nb = securityList.count();
                err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import units"), nb);
                for (int i = 0; !err && i < nb; ++i) {
                    QDomElement security = securityList.at(i).toElement();
                    QString unitName = security.attribute("name");

                    //We try a creation
                    SKGUnitObject unitObj(m_importer->getDocument());
                    SKGUnitObject::createCurrencyUnit(m_importer->getDocument(), unitName, unitObj);

                    if (!err && !unitObj.getID()) {
                        //Creation of unit
                        err = unitObj.setName(unitName);
                        QString symbol = security.attribute("symbol");
                        if (symbol.isEmpty()) symbol = unitName;
                        if (!err) err = unitObj.setSymbol(symbol);
                        if (!err) err = unitObj.setCountry(security.attribute("trading-market"));
                        if (!err) err = unitObj.setType(SKGUnitObject::SHARE);
                        if (!err) {
                            //Set pairs
                            QDomNodeList pairList = security.elementsByTagName("PAIR");
                            int nb2 = pairList.count();
                            for (int j = 0; !err && j < nb2; ++j) {
                                QDomElement pair = pairList.at(j).toElement();
                                if (pair.attribute("key").toLower() == "kmm-security-id") err = unitObj.setInternetCode(pair.attribute("value"));
                            }
                        }
                        if (!err) err = unitObj.save();
                    }

                    m_mapIdUnit[security.attribute("id")] = unitObj;

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

                if (!err) err = m_importer->getDocument()->endTransaction(true); else  m_importer->getDocument()->endTransaction(false);
            }
            if (!err) err = m_importer->getDocument()->stepForward(1);

            //Step 2-Get units prices
            QDomElement prices = docElem.firstChildElement("PRICES");
            if (!err && !prices.isNull()) {
                SKGTRACEINRC(10, "SKGImportExportManager::importKMY-PRICES", err);
                QDomNodeList pricepairList = prices.elementsByTagName("PRICEPAIR");
                int nb = pricepairList.count();
                err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import units"), nb);
                for (int i = 0; !err && i < nb; ++i) {
                    QDomElement pricepair = pricepairList.at(i).toElement();

                    SKGUnitObject unitObj = m_mapIdUnit[pricepair.attribute("from")];
                    if (unitObj.getID()) {
                        //Unit is existing
                        QDomNodeList pricesList = pricepair.elementsByTagName("PRICE");
                        int nb2 = pricesList.count();
                        for (int j = 0; !err && j < nb2; ++j) {
                            QDomElement price = pricesList.at(j).toElement();

                            SKGUnitValueObject unitValObj;
                            err = unitObj.addUnitValue(unitValObj);
                            if (!err) err = unitValObj.setDate(QDate::fromString(price.attribute("date"), "yyyy-MM-dd"));
                            if (!err) {
                                double q = 0;
                                QStringList vals = SKGServices::splitCSVLine(price.attribute("price"), '/');
                                if (vals.count() == 1) q = SKGServices::stringToDouble(vals.at(0));
                                else if (vals.count() == 2) q = SKGServices::stringToDouble(vals.at(0)) / SKGServices::stringToDouble(vals.at(1));

                                err = unitValObj.setQuantity(q);
                            }
                            if (!err) err = unitValObj.save(true, false);    //Save only without reload
                        }
                    }

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

                if (!err) err = m_importer->getDocument()->endTransaction(true); else  m_importer->getDocument()->endTransaction(false);
            }
            if (!err) err = m_importer->getDocument()->stepForward(2);

            //Step 3-Create banks
            QMap<QString, SKGBankObject> mapIdBank;
            QDomElement institutions = docElem.firstChildElement("INSTITUTIONS");
            if (!err && !institutions.isNull()) {
                SKGTRACEINRC(10, "SKGImportExportManager::importKMY-INSTITUTIONS", err);
                QDomNodeList institutionList = institutions.elementsByTagName("INSTITUTION");
                int nb = institutionList.count();
                for (int i = 0; !err && i < nb; ++i) {
                    //Get bank object
                    QDomElement bank = institutionList.at(i).toElement();
                    SKGBankObject bankObject(m_importer->getDocument());
                    err = bankObject.setName(bank.attribute("name"));
                    if (!err) err = bankObject.setNumber(bank.attribute("sortcode"));
                    if (!err) err = bankObject.save();
                    mapIdBank[bank.attribute("id")] = bankObject;
                }
            }
            if (!err) err = m_importer->getDocument()->stepForward(3);

            //Step 4-Create account and categories
            //Create bank and temporary account for kmymoney import
            SKGAccountObject kmymoneyTemporaryAccount(m_importer->getDocument());
            SKGBankObject bank(m_importer->getDocument());
            if (!err) err = m_importer->getDocument()->addOrModifyAccount("KMYMONEY-TEMPORARY-ACCOUNT", "", "KMYMONEY");
            if (!err) err = bank.setName("KMYMONEY");
            if (!err) err = bank.load();
            if (!err) err = kmymoneyTemporaryAccount.setName("KMYMONEY-TEMPORARY-ACCOUNT");
            if (!err) err = kmymoneyTemporaryAccount.load();

            QDomElement accounts = docElem.firstChildElement("ACCOUNTS");
            if (!err && !accounts.isNull()) {
                SKGTRACEINRC(10, "SKGImportExportManager::importKMY-ACCOUNTS", err);
                QDomNodeList accountList = accounts.elementsByTagName("ACCOUNT");
                int nb = accountList.count();
                err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import accounts"), nb);
                for (int i = 0; !err && i < nb; ++i) {
                    //Get account object
                    QDomElement account = accountList.at(i).toElement();
                    QString type = account.attribute("type");
                    if (type == "15") {
                        //Actions: the real account is the parent
                        m_mapIdAccount[account.attribute("id")] = m_mapIdAccount[account.attribute("parentaccount")];
                        m_mapIdUnit[account.attribute("id")] = m_mapIdUnit[account.attribute("currency")];
                    } else if (type != "12" && type != "13" && type != "16") {
                        //Get the bank
                        QString bankId = account.attribute("institution");
                        SKGBankObject bankObj = (bankId.isEmpty() ? bank : mapIdBank[account.attribute("institution")]);

                        //Creation of the account
                        SKGAccountObject accountObj;
                        if (!err) err = bankObj.addAccount(accountObj);
                        if (!err) err = accountObj.setName(account.attribute("name"));
                        if (!err) err = accountObj.setNumber(account.attribute("number"));
                        if (!err) err = accountObj.setComment(account.attribute("description"));
                        if (!err) {
                            QString type = account.attribute("type");
                            SKGAccountObject::AccountType typeA = (type == "4" ? SKGAccountObject::CREDITCARD : (type == "7" ? SKGAccountObject::INVESTMENT : (type == "9" ? SKGAccountObject::ASSETS : (type == "3" ? SKGAccountObject::WALLET : (type == "10" ? SKGAccountObject::LOAN : SKGAccountObject::CURRENT)))));

                            err = accountObj.setType(typeA);
                        }
                        if (!err) {
                            //Set pairs
                            QDomNodeList pairList = account.elementsByTagName("PAIR");
                            int nb2 = pairList.count();
                            for (int j = 0; !err && j < nb2; ++j) {
                                QDomElement pair = pairList.at(j).toElement();
                                if (pair.attribute("key").toLower() == "mm-closed" && pair.attribute("value").toLower() == "yes") err = accountObj.setClosed(true);
                                else if (pair.attribute("key").toLower() == "preferredaccount" && pair.attribute("value").toLower() == "yes") err = accountObj.bookmark(true);
                            }
                        }
                        if (!err) err = accountObj.save();

                        m_mapIdAccount[account.attribute("id")] = accountObj;
                    } else if (type != "16") {
                        //Create category
                        SKGCategoryObject cat = m_mapIdCategory[account.attribute("id")];
                        if (cat.getID()) {
                            //Already existing ==> we must set the right name
                            err = cat.setName(account.attribute("name"));
                            if (!err) err = cat.save();
                            m_mapIdCategory[account.attribute("id")] = cat;
                        } else {
                            //We must create it
                            cat = SKGCategoryObject(m_importer->getDocument());
                            err = cat.setName(account.attribute("name"));
                            if (!err) err = cat.save();
                            m_mapIdCategory[account.attribute("id")] = cat;
                        }

                        //Create sub categories
                        QDomNodeList subaccountList = account.elementsByTagName("SUBACCOUNT");
                        int nb2 = subaccountList.count();
                        for (int j = 0; !err && j < nb2; ++j) {
                            QDomElement subaccount = subaccountList.at(j).toElement();

                            //Is child already existing ?
                            SKGCategoryObject cat2 = m_mapIdCategory[subaccount.attribute("id")];
                            if (cat2.getID()) {
                                //Yes ==> reparent
                                err = cat2.setParentCategory(cat);
                                if (!err) err = cat2.save(true, false);
                            } else {
                                //No ==> create
                                if (!err) err = cat.addCategory(cat2);
                                if (!err) err = cat2.setName(subaccount.attribute("id"));
                                if (!err) err = cat2.save();
                                m_mapIdCategory[subaccount.attribute("id")] = cat2;
                            }
                        }
                    }

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

                if (!err) err = m_importer->getDocument()->endTransaction(true); else  m_importer->getDocument()->endTransaction(false);
            }
            if (!err) err = m_importer->getDocument()->stepForward(4);

            //Step 5-Read payees
            QMap<QString, SKGPayeeObject> mapIdPayee;
            QDomElement payees = docElem.firstChildElement("PAYEES");
            if (!err && !payees.isNull()) {
                SKGTRACEINRC(10, "SKGImportExportManager::importKMY-PAYEES", err);
                QDomNodeList payeeList = payees.elementsByTagName("PAYEE");
                int nb = payeeList.count();
                for (int i = 0; !err && i < nb; ++i) {
                    //Get account object
                    QDomElement payee = payeeList.at(i).toElement();
                    QDomElement address = payee.firstChildElement("ADDRESS");
                    SKGPayeeObject payeeObject;
                    err = SKGPayeeObject::createPayee(m_importer->getDocument(), payee.attribute("name"), payeeObject);
                    if (!err) {
                        QString add = address.attribute("street") % ' ' % address.attribute("postcode") % ' ' % address.attribute("city") % ' ' % address.attribute("state") % ' ' % address.attribute("telephone");
                        add.replace("  ", " ");
                        err = payeeObject.setAddress(add.trimmed());
                        if (!err) err = payeeObject.save();
                    }
                    if (!err) mapIdPayee[payee.attribute("id")] = payeeObject;
                }
            }
            if (!err) err = m_importer->getDocument()->stepForward(5);

            //Step 6-Create operations
            if (!err) {
                SKGTRACEINRC(10, "SKGImportExportManager::importKMY-TRANSACTIONS", err);
                QDomNodeList transactionList = docElem.elementsByTagName("TRANSACTION");
                int nb = transactionList.count();
                err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import operations"), nb);
                for (int i = 0; !err && i < nb; ++i) {
                    //Get operation object
                    QDomElement operation = transactionList.at(i).toElement();

                    SKGOperationObject operationObj;
                    err = kmymoneyTemporaryAccount.addOperation(operationObj, true);
                    if (!err) err = operationObj.setDate(QDate::fromString(operation.attribute("postdate"), "yyyy-MM-dd"));
                    if (!err) err = operationObj.setComment(operation.attribute("memo"));
                    if (!err) err = operationObj.setImported(true);
                    if (!err) err = operationObj.setImportID("KMY-" % operation.attribute("id"));
                    if (!err) {
                        QString unitName = operation.attribute("commodity");
                        if (unitName.isEmpty()) unitName = "??";
                        SKGUnitObject unit(m_importer->getDocument());
                        err = unit.setName(unitName);
                        if (!err) err = unit.setSymbol(unitName);
                        if (!err) {
                            if (unit.exist())  err = unit.load();
                            else  err = unit.save();

                            if (!err) err = operationObj.setUnit(unit);
                        }
                    }
                    if (!err) err = operationObj.save(false, false);

                    //Is it a schedule ?
                    if (!err) {
                        QDomElement recu = operation.parentNode().toElement();
                        if (recu.tagName() == "SCHEDULED_TX") {
                            //Yes ==> creation of the schedule
                            if (!err) err = operationObj.load();
                            if (!err) err = operationObj.setTemplate(true);
                            if (!err) err = operationObj.save(true, false);

                            //Yes ==> creation of the schedule
                            SKGRecurrentOperationObject recuObj;
                            if (!err) err = operationObj.addRecurrentOperation(recuObj);
                            QDate firstDate = QDate::fromString(recu.attribute("startDate"), "yyyy-MM-dd");
                            if (!err) err = recuObj.setDate(firstDate);
                            if (!err) err = recuObj.autoWriteEnabled(recu.attribute("autoEnter") == "1");
                            if (!err) err = recuObj.setAutoWriteDays(0);

                            int occu = SKGServices::stringToInt(recu.attribute("occurenceMultiplier"));
                            QString occuType = recu.attribute("occurence");  // krazy:exclude=spelling
                            SKGRecurrentOperationObject::PeriodUnit period;
                            if (occuType == "32") period = SKGRecurrentOperationObject::MONTH;
                            else if (occuType == "1") {
                                period = SKGRecurrentOperationObject::DAY;
                                if (!err) err = recuObj.timeLimit(true);
                                if (!err) err = recuObj.setTimeLimit(1);
                            } else if (occuType == "2") period = SKGRecurrentOperationObject::DAY;
                            else if (occuType == "4") period = SKGRecurrentOperationObject::WEEK;
                            else if (occuType == "18") {
                                period = SKGRecurrentOperationObject::WEEK;
                                occu *= 2;
                            } else period = SKGRecurrentOperationObject::YEAR;


                            if (!err) err = recuObj.setPeriodIncrement(occu);
                            if (!err) err = recuObj.setPeriodUnit(period);

                            if (!err) {
                                QString endDate = recu.attribute("endDate");
                                if (!endDate.isEmpty()) {
                                    if (!err) err = recuObj.timeLimit(true);
                                    if (!err) err = recuObj.setTimeLimit(QDate::fromString(recu.attribute("endDate"), "yyyy-MM-dd"));
                                }
                            }

                            if (!err) err = recuObj.save(true, false);
                        }
                    }

                    //Get splits
                    bool parentSet = false;
                    double quantity = 0;
                    QDomElement splits = operation.firstChildElement("SPLITS");

                    QList<QDomNode> suboperationsList;
                    int nbSuboperations = 0;
                    {
                        QDomNodeList suboperationsListTmp = splits.elementsByTagName("SPLIT");
                        nbSuboperations = suboperationsListTmp.count();

                        for (int j = 0; !err && j < nbSuboperations; ++j) {
                            QDomElement suboperation = suboperationsListTmp.at(j).toElement();
                            if (m_mapIdCategory.contains(suboperation.attribute("account"))) {
                                suboperationsList.push_front(suboperation);
                            } else {
                                suboperationsList.push_back(suboperation);
                            }
                        }
                    }

                    SKGSubOperationObject suboperationObj;
                    for (int j = 0; !err && j < nbSuboperations; ++j) {
                        QDomElement suboperation = suboperationsList.at(j).toElement();

                        //Set operation attributes
                        if (!err) err = operationObj.setPayee(mapIdPayee[suboperation.attribute("payee")]);
                        if (!err && operationObj.getComment().isEmpty()) err = operationObj.setComment(suboperation.attribute("memo"));
                        if (!err) err = operationObj.setNumber(SKGServices::stringToInt(suboperation.attribute("number")));

                        //Set state
                        if (operationObj.getStatus() == SKGOperationObject::NONE) {
                            QString val = suboperation.attribute("reconcileflag");
                            if (!err) err = operationObj.setStatus(val == "1" ? SKGOperationObject::POINTED : val == "2" ? SKGOperationObject::CHECKED : SKGOperationObject::NONE);
                        }
                        if (!err) err = operationObj.save();

                        if (m_mapIdCategory.contains(suboperation.attribute("account"))) {
                            //It is a split on category
                            SKGCategoryObject cat = m_mapIdCategory[suboperation.attribute("account")];

                            double q = 0;
                            QStringList vals = SKGServices::splitCSVLine(suboperation.attribute("shares"), '/');
                            if (vals.count() == 1) q = -SKGServices::stringToDouble(vals.at(0));
                            else if (vals.count() == 2) q = -SKGServices::stringToDouble(vals.at(0)) / SKGServices::stringToDouble(vals.at(1));

                            if (!err && (!suboperationObj.getID() || suboperationObj.getQuantity() != q)) err = operationObj.addSubOperation(suboperationObj);
                            if (!err) err = suboperationObj.setQuantity(q);
                            if (!err) err = suboperationObj.setCategory(cat);
                            if (!err) err = suboperationObj.setComment(suboperation.attribute("memo"));
                            if (!err) err = suboperationObj.save(true, false);
                        } else if (!m_mapIdAccount.contains(suboperation.attribute("account"))) {
                            //Set as initial balance
                            if (!err) err = operationObj.setAttribute("d_date", "0000-00-00");
                            if (!err) err = operationObj.setStatus(SKGOperationObject::CHECKED);
                            if (!err) err = operationObj.save(true, false);
                        } else {
                            //It is a transfer of account
                            SKGAccountObject act = m_mapIdAccount[suboperation.attribute("account")];

                            if (parentSet) {
                                //If the parent is already set, it means that is a transfer
                                SKGOperationObject operationObj2;
                                if (!err) err = act.addOperation(operationObj2, true);
                                if (!err) err = operationObj2.setTemplate(operationObj.isTemplate());
                                if (!err) err = operationObj2.setDate(operationObj.getDate());
                                if (!err) err = operationObj2.setNumber(operationObj.getNumber());
                                if (!err) err = operationObj2.setComment(operationObj.getComment());
                                SKGPayeeObject payeeObject;
                                operationObj2.getPayee(payeeObject);
                                if (!err) err = operationObj2.setPayee(payeeObject);
                                if (!err) {
                                    QString val = suboperation.attribute("reconcileflag");
                                    err = operationObj2.setStatus(val == "1" ? SKGOperationObject::POINTED : val == "2" ? SKGOperationObject::CHECKED : SKGOperationObject::NONE);
                                }
                                if (!err) err = operationObj2.setImported(true);
                                if (!err) err = operationObj2.setImportID(operationObj.getImportID());

                                if (m_mapIdUnit.contains(suboperation.attribute("account"))) {
                                    if (!err) err = operationObj2.setUnit(m_mapIdUnit[suboperation.attribute("account")]);
                                } else {
                                    SKGUnitObject unit;
                                    if (!err) err = operationObj.getUnit(unit);
                                    if (!err) err = operationObj2.setUnit(unit);
                                }
                                if (!err) err = operationObj2.save();
                                if (!err) err = operationObj2.setGroupOperation(operationObj);
                                if (!err) err = operationObj2.save();

                                //Create sub operation on operationObj2
                                SKGSubOperationObject suboperationObj2;
                                if (!err) err = operationObj2.addSubOperation(suboperationObj2);
                                if (!err) {
                                    //We must take the quality of the split having an action
                                    QStringList vals = SKGServices::splitCSVLine(suboperation.attribute("shares"), '/');
                                    if (vals.count() == 1) quantity = SKGServices::stringToDouble(vals.at(0));
                                    else if (vals.count() == 2) quantity = SKGServices::stringToDouble(vals.at(0)) / SKGServices::stringToDouble(vals.at(1));
                                    err = suboperationObj2.setQuantity(quantity);
                                }
                                if (!err) err = suboperationObj2.setComment(suboperation.attribute("memo"));
                                if (!err) err = suboperationObj2.save(true, false);
                            } else {
                                //We set the parent
                                if (!err) err = operationObj.setParentAccount(act, true);
                                if (!err) err = operationObj.save();

                                //Compute quantity
                                QStringList vals = SKGServices::splitCSVLine(suboperation.attribute("shares"), '/');
                                if (vals.count() == 1) quantity = SKGServices::stringToDouble(vals.at(0));
                                else if (vals.count() == 2) quantity = SKGServices::stringToDouble(vals.at(0)) / SKGServices::stringToDouble(vals.at(1));

                                //Create sub operation on operationObj
                                quantity -= SKGServices::stringToDouble(operationObj.getAttribute("f_QUANTITY"));
                                if (quantity != 0) {
                                    if (!err) err = operationObj.addSubOperation(suboperationObj);
                                    if (!err) err = suboperationObj.setQuantity(quantity);
                                    if (!err) err = suboperationObj.setComment(suboperation.attribute("memo"));
                                    if (!err) err = suboperationObj.save(true, false);
                                }

                                parentSet = true;
                            }
                        }
                    }

                    if (!err && i % 500 == 0) err = m_importer->getDocument()->executeSqliteOrder("ANALYZE");

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

                if (!err) err = m_importer->getDocument()->endTransaction(true); else  m_importer->getDocument()->endTransaction(false);
            }
            if (!err) err = m_importer->getDocument()->stepForward(6);

            //Step 7-Get budgets
            QDomElement budgets = docElem.firstChildElement("BUDGETS");
            if (!err && !budgets.isNull()) {
                SKGTRACEINRC(10, "SKGImportExportManager::importKMY-BUDGETS", err);
                //Build cache of categories
                QMap<int, bool> catExpense;
                {
                    SKGStringListList list;
                    err = m_importer->getDocument()->executeSelectSqliteOrder("SELECT id, t_TYPEEXPENSE FROM v_category_display", list);
                    int nb = list.count();
                    for (int i = 1; i < nb; ++i) {
                        catExpense[SKGServices::stringToInt(list.at(i).at(0))] = (list.at(i).at(0) == "-");
                    }
                }

                QDomNodeList budgetList = budgets.elementsByTagName("BUDGET");
                int nb = budgetList.count();
                if (!err) err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import budgets"), nb);
                for (int i = 0; !err && i < nb; ++i) {
                    QDomElement budget = budgetList.at(i).toElement();
                    QDomNodeList accountList = budget.elementsByTagName("ACCOUNT");
                    int nb2 = accountList.count();
                    for (int j = 0; !err && j < nb2; ++j) {
                        QDomElement account = accountList.at(j).toElement();
                        SKGCategoryObject cat = m_mapIdCategory[account.attribute("id")];
                        QString budgetlevel = account.attribute("budgetlevel");

                        QDomNodeList periodList = account.elementsByTagName("PERIOD");
                        int nb3 = periodList.count();
                        for (int k = 0; !err && k < nb3; ++k) {
                            QDomElement period = periodList.at(k).toElement();

                            double q = 0;
                            QStringList vals = SKGServices::splitCSVLine(period.attribute("amount"), '/');
                            if (vals.count() == 1) q = SKGServices::stringToDouble(vals.at(0));
                            else if (vals.count() == 2) q = SKGServices::stringToDouble(vals.at(0)) / SKGServices::stringToDouble(vals.at(1));

                            //Are we able to find to sign with the category ?
                            if (catExpense[cat.getID()]) q = -q;

                            QStringList dates = SKGServices::splitCSVLine(period.attribute("start"), '-');
                            if (dates.count() == 3) {
                                //We try a creation
                                for (int m = 1; !err && m <= (budgetlevel == "monthly" ? 12 : 1); ++m) {
                                    SKGBudgetObject budget(m_importer->getDocument());
                                    err = budget.setCategory(cat);
                                    if (!err) err = budget.setBudgetedAmount(q);
                                    if (!err) err = budget.setYear(SKGServices::stringToDouble(dates.at(0)));
                                    if (!err) err = budget.setMonth(budgetlevel == "monthbymonth" ? SKGServices::stringToDouble(dates.at(1)) :
                                                                        budgetlevel == "yearly" ? 0 : m);
                                    if (!err) err = budget.save(true, false);
                                }
                            }
                        }
                    }

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

                if (!err) err = m_importer->getDocument()->endTransaction(true); else  m_importer->getDocument()->endTransaction(false);
            }
            if (!err) err = m_importer->getDocument()->stepForward(7);

            //Step 8-Remove useless account and temporary account
            {
                if (!err) err = kmymoneyTemporaryAccount.remove(false, true);
                if (!err) err = m_importer->getDocument()->executeSqliteOrder("DELETE FROM account WHERE rd_bank_id=" % SKGServices::intToString(bank.getID()) % " AND (SELECT COUNT(1) FROM operation WHERE operation.rd_account_id=account.id)=0");
            }
            if (!err) err = m_importer->getDocument()->stepForward(8);

            if (!err) err = m_importer->getDocument()->endTransaction(true); else  m_importer->getDocument()->endTransaction(false);

            if (!err) err = m_importer->getDocument()->executeSqliteOrder("ANALYZE");
        }
    }

    delete file;

    //Clean
    m_mapIdUnit.clear();
    m_mapIdAccount.clear();
    m_mapIdCategory.clear();
    m_mapIdPayee.clear();

    return err;
}

bool SKGImportPluginKmy::isExportPossible()
{
    SKGTRACEIN(10, "SKGImportPluginCsv::isExportPossible");
    return (!m_importer ? true : m_importer->getFileNameExtension() == "KMY");
}

SKGError SKGImportPluginKmy::exportFile()
{
    //Initialisation
    m_opTreated.clear();

    if (!m_importer) return SKGError(ERR_ABORT, i18nc("Error message", "Invalid parameters"));
    SKGError err;
    SKGTRACEINRC(2, "SKGImportPluginKmy::exportFile", err);

    //Open file
    QIODevice* file = KFilterDev::deviceForFile(m_importer->getLocalFileName(false), "application/x-gzip");
    if (!file->open(QIODevice::WriteOnly))err.setReturnCode(ERR_INVALIDARG).setMessage(i18nc("Error message",  "Save file '%1' failed", m_importer->getFileName().prettyUrl()));
    else {
        QDomDocument doc("KMYMONEY-FILE");
        QDomComment comment = doc.createComment("Generated by libskgbankmodeler");
        doc.appendChild(comment);

        QDomElement root = doc.createElement("KMYMONEY-FILE");
        doc.appendChild(root);
        {
            err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export %1 file", "KMY"), 8);
            if (!err) {
                //Step 1-<FILEINFO>
                QDomElement fileindo = doc.createElement("FILEINFO");
                root.appendChild(fileindo);

                {
                    //<CREATION_DATE>
                    QDomElement creation_date = doc.createElement("CREATION_DATE");
                    fileindo.appendChild(creation_date);
                    creation_date.setAttribute("date", SKGServices::dateToSqlString(QDateTime::currentDateTime()));

                    //<LAST_MODIFIED_DATE>
                    QDomElement last_modified_date = doc.createElement("LAST_MODIFIED_DATE");
                    fileindo.appendChild(last_modified_date);
                    last_modified_date.setAttribute("date", SKGServices::dateToSqlString(QDateTime::currentDateTime()));

                    //<VERSION>
                    QDomElement version = doc.createElement("VERSION");
                    fileindo.appendChild(version);
                    version.setAttribute("id", "1");

                    //<FIXVERSION>
                    QDomElement fixversion = doc.createElement("FIXVERSION");
                    fileindo.appendChild(fixversion);
                    fixversion.setAttribute("id", "2");
                }

                //<USER>
                QDomElement user = doc.createElement("USER");
                root.appendChild(user);
                user.setAttribute("email", "");
                user.setAttribute("name", "");
                {
                    //ADDRESS
                    QDomElement address = doc.createElement("ADDRESS");
                    user.appendChild(address);
                    address.setAttribute("street", "");
                    address.setAttribute("zipcode", "");
                    address.setAttribute("county", "");
                    address.setAttribute("city", "");
                    address.setAttribute("telephone", "");
                }
                if (!err) err = m_importer->getDocument()->stepForward(1);

                ////Step 2-<INSTITUTIONS>
                QDomElement institutions = doc.createElement("INSTITUTIONS");
                root.appendChild(institutions);

                SKGObjectBase::SKGListSKGObjectBase objects;
                if (!err) err = m_importer->getDocument()->getObjects("bank", "EXISTS(SELECT 1 FROM account WHERE account.rd_bank_id=bank.id)", objects);
                int nb = objects.count();
                institutions.setAttribute("count", SKGServices::intToString(nb));
                if (!err) {
                    err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export banks"), nb);
                    for (int i = 0; !err && i < nb; ++i) {
                        SKGBankObject obj(objects.at(i));
                        QDomElement institution = doc.createElement("INSTITUTION");
                        institutions.appendChild(institution);

                        institution.setAttribute("id", obj.getUniqueID());
                        institution.setAttribute("name", obj.getName());
                        institution.setAttribute("sortcode", obj.getNumber());
                        institution.setAttribute("manager", "");

                        QDomElement address = doc.createElement("ADDRESS");
                        institution.appendChild(address);

                        address.setAttribute("street", "");
                        address.setAttribute("zip", "");
                        address.setAttribute("city", "");
                        address.setAttribute("telephone", "");

                        QDomElement accountids = doc.createElement("ACCOUNTIDS");
                        institution.appendChild(accountids);

                        SKGObjectBase::SKGListSKGObjectBase accounts;
                        err = obj.getAccounts(accounts);
                        int nb2 = accounts.count();
                        for (int j = 0; !err && j < nb2; ++j) {
                            QDomElement accountid = doc.createElement("ACCOUNTID");
                            accountids.appendChild(accountid);

                            accountid.setAttribute("id", accounts.at(j).getUniqueID());
                        }
                        if (!err) err = m_importer->getDocument()->stepForward(i + 1);
                    }

                    if (!err) err = m_importer->getDocument()->endTransaction(true); else  m_importer->getDocument()->endTransaction(false);
                }
                if (!err) err = m_importer->getDocument()->stepForward(2);

                //Step 3-<PAYEES>
                QDomElement payees = doc.createElement("PAYEES");
                root.appendChild(payees);

                SKGObjectBase::SKGListSKGObjectBase listPayees;
                if (!err) err = m_importer->getDocument()->getObjects("payee", "", listPayees);
                nb = listPayees.count();
                payees.setAttribute("count", SKGServices::intToString(nb));
                if (!err) {
                    err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export payees"), nb);
                    for (int i = 0; !err && i < nb; ++i) {
                        SKGPayeeObject payeeObject(listPayees.at(i));
                        QDomElement payee = doc.createElement("PAYEE");
                        payees.appendChild(payee);

                        payee.setAttribute("matchingenabled", "0");
                        payee.setAttribute("id", payeeObject.getUniqueID());
                        payee.setAttribute("name", payeeObject.getName());
                        payee.setAttribute("email", "");
                        payee.setAttribute("reference", "");

                        QDomElement address = doc.createElement("ADDRESS");
                        payee.appendChild(address);

                        address.setAttribute("street", payeeObject.getAddress());
                        address.setAttribute("postcode", "");
                        address.setAttribute("zip", "");
                        address.setAttribute("city", "");
                        address.setAttribute("telephone", "");
                        address.setAttribute("state", "");

                        m_mapIdPayee[SKGServices::intToString(i + 1)] = payeeObject;

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

                    if (!err) err = m_importer->getDocument()->endTransaction(true); else  m_importer->getDocument()->endTransaction(false);
                }
                if (!err) err = m_importer->getDocument()->stepForward(3);

                //Step 4-<ACCOUNTS>
                QDomElement accounts = doc.createElement("ACCOUNTS");
                root.appendChild(accounts);

                //Std accounts
                QString stdUnit = m_importer->getDocument()->getPrimaryUnit().Name;
                stdUnit = SKGUnitObject::getInternationalCode(stdUnit);
                if (stdUnit.isEmpty()) stdUnit = "EUR";

                QDomElement accountAsset;
                QDomElement accountIncome;
                QDomElement accountExpense;
                {
                    QDomElement account = doc.createElement("ACCOUNT");
                    accounts.appendChild(account);

                    account.setAttribute("id", "AStd::Equity");
                    account.setAttribute("name", "Equity");
                    account.setAttribute("number", "");
                    account.setAttribute("type", "16");
                    account.setAttribute("institution", "");
                    account.setAttribute("parentaccount", "");
                    account.setAttribute("lastmodified", "");
                    account.setAttribute("lastreconciled", "");
                    account.setAttribute("opened", "");
                    account.setAttribute("currency", stdUnit);
                    account.setAttribute("description", "");

                    QDomElement subaccounts = doc.createElement("SUBACCOUNTS");
                    account.appendChild(subaccounts);
                }

                {
                    QDomElement account = doc.createElement("ACCOUNT");
                    accounts.appendChild(account);

                    account.setAttribute("id", "AStd::Asset");
                    account.setAttribute("name", "Asset");
                    account.setAttribute("number", "");
                    account.setAttribute("type", "9");
                    account.setAttribute("institution", "");
                    account.setAttribute("parentaccount", "");
                    account.setAttribute("lastmodified", "");
                    account.setAttribute("lastreconciled", "");
                    account.setAttribute("opened", "");
                    account.setAttribute("currency", stdUnit);
                    account.setAttribute("description", "");

                    QDomElement subaccounts = doc.createElement("SUBACCOUNTS");
                    account.appendChild(subaccounts);
                    accountAsset = subaccounts;
                }

                {
                    QDomElement account = doc.createElement("ACCOUNT");
                    accounts.appendChild(account);

                    account.setAttribute("id", "AStd::Liability");
                    account.setAttribute("name", "Liability");
                    account.setAttribute("number", "");
                    account.setAttribute("type", "10");
                    account.setAttribute("institution", "");
                    account.setAttribute("parentaccount", "");
                    account.setAttribute("lastmodified", "");
                    account.setAttribute("lastreconciled", "");
                    account.setAttribute("opened", "");
                    account.setAttribute("currency", stdUnit);
                    account.setAttribute("description", "");

                    QDomElement subaccounts = doc.createElement("SUBACCOUNTS");
                    account.appendChild(subaccounts);
                }

                {
                    QDomElement account = doc.createElement("ACCOUNT");
                    accounts.appendChild(account);

                    account.setAttribute("id", "AStd::Income");
                    account.setAttribute("name", "Income");
                    account.setAttribute("number", "");
                    account.setAttribute("type", "12");
                    account.setAttribute("institution", "");
                    account.setAttribute("parentaccount", "");
                    account.setAttribute("lastmodified", "");
                    account.setAttribute("lastreconciled", "");
                    account.setAttribute("opened", "");
                    account.setAttribute("currency", stdUnit);
                    account.setAttribute("description", "");

                    QDomElement subaccounts = doc.createElement("SUBACCOUNTS");
                    account.appendChild(subaccounts);
                    accountIncome = subaccounts;
                }

                {
                    QDomElement account = doc.createElement("ACCOUNT");
                    accounts.appendChild(account);

                    account.setAttribute("id", "AStd::Expense");
                    account.setAttribute("name", "Expense");
                    account.setAttribute("number", "");
                    account.setAttribute("type", "13");
                    account.setAttribute("institution", "");
                    account.setAttribute("parentaccount", "");
                    account.setAttribute("lastmodified", "");
                    account.setAttribute("lastreconciled", "");
                    account.setAttribute("opened", "");
                    account.setAttribute("currency", stdUnit);
                    account.setAttribute("description", "");

                    QDomElement subaccounts = doc.createElement("SUBACCOUNTS");
                    account.appendChild(subaccounts);
                    accountExpense = subaccounts;
                }

                if (!err) err = m_importer->getDocument()->getObjects("account", "", objects);
                nb = objects.count();
                if (!err) {
                    err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export accounts"), nb);
                    for (int i = 0; !err && i < nb; ++i) {
                        SKGAccountObject obj(objects.at(i));
                        QDomElement account = doc.createElement("ACCOUNT");
                        accounts.appendChild(account);

                        account.setAttribute("id", obj.getUniqueID());
                        account.setAttribute("name", obj.getName());
                        account.setAttribute("number", obj.getNumber());
                        account.setAttribute("type", obj.getType() == SKGAccountObject::CREDITCARD ? "4" : (obj.getType() == SKGAccountObject::INVESTMENT ? "7" : (obj.getType() == SKGAccountObject::ASSETS ? "9" : (obj.getType() == SKGAccountObject::WALLET ? "3" : (obj.getType() == SKGAccountObject::LOAN ? "10" : "1")))));

                        SKGBankObject bank;
                        err = obj.getBank(bank);
                        account.setAttribute("institution", bank.getUniqueID());

                        account.setAttribute("parentaccount", "AStd::Asset");
                        account.setAttribute("lastmodified", "");
                        account.setAttribute("lastreconciled", "");
                        account.setAttribute("opened", "");
                        SKGUnitObject unit;
                        obj.getUnit(unit);
                        QString unitS = SKGUnitObject::getInternationalCode(unit.getName());
                        if (unitS.isEmpty()) unitS = "EUR";
                        account.setAttribute("currency", unitS);
                        account.setAttribute("description", "");

                        //Bookmarked account
                        QDomElement keyvaluepairs = doc.createElement("KEYVALUEPAIRS");
                        account.appendChild(keyvaluepairs);
                        if (obj.isBookmarked()) {
                            QDomElement pair = doc.createElement("PAIR");
                            keyvaluepairs.appendChild(pair);
                            pair.setAttribute("key", "PreferredAccount");
                            pair.setAttribute("value", "Yes");
                        }
                        //Closed account
                        if (obj.isClosed()) {
                            QDomElement pair = doc.createElement("PAIR");
                            keyvaluepairs.appendChild(pair);
                            pair.setAttribute("key", "mm-closed");
                            pair.setAttribute("value", "yes");
                        }

                        //Add it in asset
                        QDomElement subaccount = doc.createElement("SUBACCOUNT");
                        accountAsset.appendChild(subaccount);
                        subaccount.setAttribute("id", obj.getUniqueID());

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

                    if (!err) err = m_importer->getDocument()->endTransaction(true); else  m_importer->getDocument()->endTransaction(false);
                }
                if (!err) err = m_importer->getDocument()->stepForward(4);

                //Step 5
                if (!err) err = m_importer->getDocument()->getObjects("category", "", objects);
                accounts.setAttribute("count", SKGServices::intToString(5 + nb + objects.count()));
                nb = objects.count();
                if (!err) {
                    err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export categories"), nb);
                    for (int i = 0; !err && i < nb; ++i) {
                        SKGCategoryObject obj(objects.at(i));
                        QDomElement account = doc.createElement("ACCOUNT");
                        accounts.appendChild(account);

                        account.setAttribute("id", obj.getUniqueID());
                        account.setAttribute("name", obj.getName());
                        account.setAttribute("number", "");
                        account.setAttribute("type", obj.getCurrentAmount() < 0 ? "13" : "12");

                        account.setAttribute("institution", "");

                        SKGCategoryObject parent;
                        obj.getParentCategory(parent);

                        QString parentId = (parent.getID() ? parent.getUniqueID() : (obj.getCurrentAmount() < 0 ? "AStd::Expense" : "AStd::Income"));
                        if (parentId == "AStd::Expense") {
                            QDomElement subaccount = doc.createElement("SUBACCOUNT");
                            accountExpense.appendChild(subaccount);
                            subaccount.setAttribute("id", obj.getUniqueID());
                        } else if (parentId == "AStd::Income") {
                            QDomElement subaccount = doc.createElement("SUBACCOUNT");
                            accountIncome.appendChild(subaccount);
                            subaccount.setAttribute("id", obj.getUniqueID());
                        }

                        account.setAttribute("parentaccount", parentId);
                        account.setAttribute("lastmodified", "");
                        account.setAttribute("lastreconciled", "");
                        account.setAttribute("opened", "");
                        account.setAttribute("currency", stdUnit);
                        account.setAttribute("description", "");

                        QDomElement subaccounts = doc.createElement("SUBACCOUNTS");
                        account.appendChild(subaccounts);

                        SKGObjectBase::SKGListSKGObjectBase categories;
                        if (!err) err = obj.getCategories(categories);
                        int nb2 = categories.count();
                        for (int j = 0; !err && j < nb2; ++j) {
                            QDomElement subaccount = doc.createElement("SUBACCOUNT");
                            subaccounts.appendChild(subaccount);

                            subaccount.setAttribute("id", categories.at(j).getUniqueID());
                        }
                        if (!err) err = m_importer->getDocument()->stepForward(i + 1);
                    }

                    if (!err) err = m_importer->getDocument()->endTransaction(true); else  m_importer->getDocument()->endTransaction(false);
                }
                if (!err) err = m_importer->getDocument()->stepForward(5);

                //Step 6-<TRANSACTIONS>
                QDomElement transactions = doc.createElement("TRANSACTIONS");
                root.appendChild(transactions);

                if (!err) err = m_importer->getDocument()->getObjects("v_operation", "t_template='N'", objects);
                nb = objects.count();
                transactions.setAttribute("count", SKGServices::intToString(nb));
                if (!err) {
                    err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export operations"), nb);
                    for (int i = 0; !err && i < nb; ++i) {
                        SKGOperationObject op(objects.at(i));
                        err = exportOperation(op, doc, transactions);
                        if (!err) err = m_importer->getDocument()->stepForward(i + 1);
                    }

                    if (!err) err = m_importer->getDocument()->endTransaction(true); else  m_importer->getDocument()->endTransaction(false);
                }

                //<KEYVALUEPAIRS>
                QDomElement keyvaluepairs = doc.createElement("KEYVALUEPAIRS");
                root.appendChild(keyvaluepairs);
                {
                    QDomElement pair = doc.createElement("PAIR");
                    keyvaluepairs.appendChild(pair);
                    pair.setAttribute("key", "kmm-baseCurrency");
                    pair.setAttribute("value", stdUnit);
                }

                //Step 6-<SCHEDULES>
                QDomElement schedules = doc.createElement("SCHEDULES");
                root.appendChild(schedules);

                if (!err) err = m_importer->getDocument()->getObjects("recurrentoperation", "", objects);
                nb = objects.count();
                schedules.setAttribute("count", SKGServices::intToString(nb));
                if (!err) {
                    err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export scheduled operations"), nb);
                    for (int i = 0; !err && i < nb; ++i) {
                        SKGRecurrentOperationObject obj(objects.at(i));
                        SKGOperationObject op;
                        err = obj.getParentOperation(op);
                        if (!err) {
                            QDomElement scheduled_tx = doc.createElement("SCHEDULED_TX");
                            schedules.appendChild(scheduled_tx);

                            scheduled_tx.setAttribute("id", obj.getUniqueID());
                            scheduled_tx.setAttribute("name", obj.getUniqueID());
                            scheduled_tx.setAttribute("startDate", obj.getAttribute("d_date"));
                            scheduled_tx.setAttribute("lastPayment", obj.getAttribute("d_date"));
                            bool autoEnter = false;
                            obj.autoWriteEnabled(autoEnter);
                            scheduled_tx.setAttribute("autoEnter", autoEnter  ? "1" : "0");

                            QString occuType;
                            int occu = obj.getPeriodIncrement();
                            SKGRecurrentOperationObject::PeriodUnit punit = obj.getPeriodUnit();
                            if (punit == SKGRecurrentOperationObject::MONTH) occuType = "32";
                            else if (punit == SKGRecurrentOperationObject::WEEK) occuType = '4';
                            else if (punit == SKGRecurrentOperationObject::DAY) occuType = '2';
                            else occuType = "16384";

                            scheduled_tx.setAttribute("occurenceMultiplier", SKGServices::intToString(occu));
                            scheduled_tx.setAttribute("occurence", occuType);    // krazy:exclude=spelling
                            scheduled_tx.setAttribute("weekendOption", "0");
                            scheduled_tx.setAttribute("paymentType", "1");
                            QChar type = '1';
                            SKGOperationObject op2;
                            if (op.isTransfer(op)) type = '4';
                            else if (op.getCurrentAmount() > 0) type = '2';
                            scheduled_tx.setAttribute("type", type);
                            scheduled_tx.setAttribute("fixed", "1");

                            QString endDate;
                            if (obj.hasTimeLimit()) {
                                QDate firstDate = obj.getDate();

                                //We must compute the date
                                int p = occu * (obj.getTimeLimit() - 1);
                                if (punit == SKGRecurrentOperationObject::DAY) firstDate = firstDate.addDays(p);
                                else if (punit == SKGRecurrentOperationObject::MONTH) firstDate = firstDate.addMonths(p);
                                else if (punit == SKGRecurrentOperationObject::YEAR) firstDate = firstDate.addYears(p);

                                endDate = firstDate.toString("yyyy-MM-dd");
                            }
                            scheduled_tx.setAttribute("endDate", endDate);

                            err = exportOperation(op, doc, scheduled_tx);
                        }
                        if (!err) err = m_importer->getDocument()->stepForward(i + 1);
                    }

                    if (!err) err = m_importer->getDocument()->endTransaction(true); else  m_importer->getDocument()->endTransaction(false);
                }
                if (!err) err = m_importer->getDocument()->stepForward(6);

                //Step 7-<BUDGETS>
                QDomElement budgets = doc.createElement("BUDGETS");
                root.appendChild(budgets);

                if (!err) err = m_importer->getDocument()->getObjects("budget", "1=1 ORDER BY i_year, i_month", objects);
                nb = objects.count();
                int nbBudgets = 0;
                int currentYear = 0;
                QDomElement budget;

                QMap<QString, QDomElement> mapCatAccount;
                if (!err) {
                    err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export budgets"), nb);
                    for (int i = 0; !err && i < nb; ++i) {
                        SKGBudgetObject obj(objects.at(i));
                        SKGCategoryObject cat;
                        obj.getCategory(cat);
                        QString catId = cat.getUniqueID();
                        int year = obj.getYear();
                        QString yearString = SKGServices::intToString(year);
                        int month = obj.getMonth();
                        QString monthString = SKGServices::intToString(month);
                        if (monthString.isEmpty()) monthString = '0' % monthString;
                        if (currentYear != year) {
                            budget = doc.createElement("BUDGET");
                            budgets.appendChild(budget);
                            budget.setAttribute("version", "2");
                            budget.setAttribute("id", yearString);
                            budget.setAttribute("start", yearString % "-01-01");
                            budget.setAttribute("name", yearString);

                            currentYear = year;
                            mapCatAccount.clear();
                            ++nbBudgets;
                        }

                        QDomElement account = mapCatAccount[catId];
                        if (account.isNull()) {
                            account = doc.createElement("ACCOUNT");
                            budget.appendChild(account);
                            account.setAttribute("budgetsubaccounts", "0");
                            account.setAttribute("id", catId);
                            mapCatAccount[catId] = account;
                        }
                        account.setAttribute("budgetlevel", obj.getMonth() == 0 ? "yearly" : "monthbymonth");

                        QDomElement period = doc.createElement("PERIOD");
                        account.appendChild(period);
                        period.setAttribute("amount", SKGImportPluginKmy::kmyValue(qAbs(obj.getBudgetedAmount())));
                        period.setAttribute("start", yearString % '-' % (obj.getMonth() == 0 ? "01" : monthString) % "-01");

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

                    if (!err) err = m_importer->getDocument()->endTransaction(true); else  m_importer->getDocument()->endTransaction(false);
                }
                budgets.setAttribute("count", SKGServices::intToString(nbBudgets));
                if (!err) err = m_importer->getDocument()->stepForward(7);

                //Step 8-<SECURITIES>
                QDomElement securities = doc.createElement("SECURITIES");
                root.appendChild(securities);

                if (!err) err = m_importer->getDocument()->getObjects("unit", "t_type='S'", objects);
                nb = objects.count();
                securities.setAttribute("count", SKGServices::intToString(nb));
                securities.setAttribute("count", SKGServices::intToString(nb));
                if (!err) {
                    err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export units"), nb);
                    for (int i = 0; !err && i < nb; ++i) {
                        SKGUnitObject obj(objects.at(i));
                        QDomElement security = doc.createElement("SECURITY");
                        securities.appendChild(security);

                        SKGUnitObject parent;
                        obj.getUnit(parent);
                        QString unitP = SKGUnitObject::getInternationalCode(parent.getName());
                        if (unitP.isEmpty()) unitP = stdUnit;

                        security.setAttribute("id", obj.getName());
                        security.setAttribute("trading-currency", unitP);
                        security.setAttribute("saf", "100000");
                        security.setAttribute("symbol", obj.getSymbol());
                        security.setAttribute("trading-market", obj.getCountry());
                        security.setAttribute("type", "4");
                        security.setAttribute("name", obj.getName());

                        QString internetCode = obj.getInternetCode();
                        if (!internetCode.isEmpty()) {
                            QDomElement keyvaluepairs = doc.createElement("KEYVALUEPAIRS");
                            security.appendChild(keyvaluepairs);

                            QDomElement pair1 = doc.createElement("PAIR");
                            keyvaluepairs.appendChild(pair1);
                            pair1.setAttribute("key", "kmm-online-source");
                            pair1.setAttribute("value", "Yahoo");

                            QDomElement pair2 = doc.createElement("PAIR");
                            keyvaluepairs.appendChild(pair2);
                            pair2.setAttribute("key", "kmm-security-id");
                            pair2.setAttribute("value", internetCode);
                        }
                        if (!err) err = m_importer->getDocument()->stepForward(i + 1);
                    }

                    if (!err) err = m_importer->getDocument()->endTransaction(true); else  m_importer->getDocument()->endTransaction(false);
                }

                //<CURRENCIES>
                QDomElement currencies = doc.createElement("CURRENCIES");
                root.appendChild(currencies);
                QStringList units = SKGUnitObject::getListofKnownCurrencies(false);
                nb = units.count();
                int nbreal = 0;
                for (int i = 0; i < nb; ++i) {
                    SKGServices::SKGUnitInfo info = SKGUnitObject::getUnitInfo(units.at(i));
                    if (info.Name != info.Symbol) {
                        QDomElement currency = doc.createElement("CURRENCY");
                        currencies.appendChild(currency);
                        currency.setAttribute("saf", "100");
                        currency.setAttribute("symbol", info.Symbol);
                        currency.setAttribute("type", "3");
                        currency.setAttribute("id", SKGUnitObject::getInternationalCode(info.Name));
                        currency.setAttribute("name", info.Name);
                        currency.setAttribute("ppu", "100");
                        currency.setAttribute("scf", "100");

                        ++nbreal;
                    }
                }
                currencies.setAttribute("count", SKGServices::intToString(nbreal));

                //<PRICES>
                QDomElement prices = doc.createElement("PRICES");
                root.appendChild(prices);
                if (!err) err = m_importer->getDocument()->getObjects("unit", "t_type='S'", objects);
                nb = objects.count();
                prices.setAttribute("count", SKGServices::intToString(nb));
                if (!err) {
                    err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Export step", "Export units"), nb);
                    for (int i = 0; !err && i < nb; ++i) {
                        SKGUnitObject obj(objects.at(i));
                        QDomElement pricepair = doc.createElement("PRICEPAIR");
                        prices.appendChild(pricepair);

                        QString unitP = SKGUnitObject::getInternationalCode(obj.getName());
                        if (unitP.isEmpty()) unitP = stdUnit;

                        pricepair.setAttribute("from", obj.getName());
                        pricepair.setAttribute("to", unitP);

                        SKGObjectBase::SKGListSKGObjectBase unitValues;
                        err = obj.getUnitValues(unitValues);
                        int nb2 = unitValues.count();
                        for (int j = 0; !err && j < nb2; ++j) {
                            QDomElement price = doc.createElement("PRICE");
                            pricepair.appendChild(price);

                            SKGUnitValueObject unitval(unitValues.at(j));
                            price.setAttribute("price", SKGImportPluginKmy::kmyValue(unitval.getQuantity()));
                            price.setAttribute("source", "Utilisateur");
                            price.setAttribute("date", SKGServices::dateToSqlString(QDateTime(unitval.getDate())));
                        }

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

                    if (!err) err = m_importer->getDocument()->endTransaction(true); else  m_importer->getDocument()->endTransaction(false);
                }

                //<REPORTS>
                QDomElement reports = doc.createElement("REPORTS");
                root.appendChild(reports);
                reports.setAttribute("count", "0");

                //Save file
                if (!err) file->write(doc.toString().toUtf8());
                if (!err) err = m_importer->getDocument()->stepForward(8);
            }

            if (!err) err = m_importer->getDocument()->endTransaction(true); else  m_importer->getDocument()->endTransaction(false);
        }

        file->close();
    }

    delete file;

    //Clean
    m_opTreated.clear();

    return err;
}

SKGError SKGImportPluginKmy::exportOperation(const SKGOperationObject& iOperation, QDomDocument& iDoc, QDomElement& iTransaction)
{
    SKGError err;
    SKGTRACEINRC(2, "SKGImportPluginKmy::exportOperation", err);
    if (!m_opTreated.contains(iOperation.getUniqueID())) {
        QDomElement transaction = iDoc.createElement("TRANSACTION");
        iTransaction.appendChild(transaction);

        SKGUnitObject unit;
        iOperation.getUnit(unit);

        QString date = iOperation.getAttribute("d_date");
        transaction.setAttribute("id", iOperation.getUniqueID());
        transaction.setAttribute("entrydate", date);
        transaction.setAttribute("postdate", date);
        transaction.setAttribute("memo", iOperation.getComment());
        transaction.setAttribute("commodity", SKGUnitObject::getInternationalCode(unit.getName()));

        QString reconcileflag = (iOperation.getStatus() == SKGOperationObject::POINTED ? "1" : (iOperation.getStatus() == SKGOperationObject::CHECKED ? "2" : "0"));

        SKGAccountObject act;
        if (!err) err = iOperation.getParentAccount(act);

        QDomElement splits = iDoc.createElement("SPLITS");
        transaction.appendChild(splits);

        QDomElement split = iDoc.createElement("SPLIT");
        splits.appendChild(split);

        SKGPayeeObject payeeObject;
        iOperation.getPayee(payeeObject);
        QString payeeId = (payeeObject.getID() ? payeeObject.getUniqueID() : "");

        //Split for account
        split.setAttribute("payee", payeeId);
        split.setAttribute("reconciledate", "");
        split.setAttribute("id", iOperation.getUniqueID());
        QString shape = SKGImportPluginKmy::kmyValue(SKGServices::stringToDouble(iOperation.getAttribute("f_QUANTITY")));
        split.setAttribute("shares", shape);
        split.setAttribute("action", "");
        split.setAttribute("bankid", "");
        split.setAttribute("number", SKGServices::intToString(iOperation.getNumber()));
        split.setAttribute("reconcileflag", reconcileflag);
        split.setAttribute("memo", iOperation.getComment());
        QString originalAmount = iOperation.getProperty("SKG_OP_ORIGINAL_AMOUNT");
        if (!originalAmount.isEmpty()) shape = SKGImportPluginKmy::kmyValue(SKGServices::stringToDouble(originalAmount));
        split.setAttribute("value", shape);
        split.setAttribute("account", act.getUniqueID());

        SKGOperationObject obj2;
        if (!err && iOperation.isTransfer(obj2)) {
            //It is a transfert
            QString reconcileflag = (obj2.getStatus() == SKGOperationObject::POINTED ? "1" : (obj2.getStatus() == SKGOperationObject::CHECKED ? "2" : "0"));

            SKGAccountObject act2;
            if (!err) err = obj2.getParentAccount(act2);

            QDomElement split = iDoc.createElement("SPLIT");
            splits.appendChild(split);

            //Split for account
            split.setAttribute("payee", payeeId);
            split.setAttribute("reconciledate", "");
            split.setAttribute("id", obj2.getUniqueID());
            QString shape = SKGImportPluginKmy::kmyValue(SKGServices::stringToDouble(obj2.getAttribute("f_QUANTITY")));
            split.setAttribute("shares", shape);
            split.setAttribute("action", "");
            split.setAttribute("bankid", "");
            split.setAttribute("number", SKGServices::intToString(obj2.getNumber()));
            split.setAttribute("reconcileflag", reconcileflag);
            split.setAttribute("memo", obj2.getComment());
            split.setAttribute("value", shape);
            split.setAttribute("account", act2.getUniqueID());

            m_opTreated.insert(obj2.getUniqueID());
        } else {
            SKGObjectBase::SKGListSKGObjectBase subops;
            if (!err) err = iOperation.getSubOperations(subops);
            int nb2 = subops.count();
            for (int j = 0; !err && j < nb2; ++j) {
                QDomElement split = iDoc.createElement("SPLIT");
                splits.appendChild(split);

                SKGSubOperationObject subop(subops.at(j));
                SKGCategoryObject cat;
                subop.getCategory(cat);
                split.setAttribute("payee", payeeId);
                split.setAttribute("reconciledate", "");
                split.setAttribute("id", subop.getUniqueID());
                QString shape = SKGImportPluginKmy::kmyValue(-subop.getQuantity());
                split.setAttribute("shares", shape);
                split.setAttribute("action", "");
                split.setAttribute("bankid", "");
                split.setAttribute("number", SKGServices::intToString(iOperation.getNumber()));
                split.setAttribute("reconcileflag", reconcileflag);
                split.setAttribute("memo", subop.getComment());
                split.setAttribute("value", shape);
                split.setAttribute("account", date == "0000-00-00" ? "AStd::Equity" : (cat.getID() ? cat.getUniqueID() : ""));
            }
        }

        m_opTreated.insert(iOperation.getUniqueID());
    }
    return err;
}

QString SKGImportPluginKmy::kmyValue(double iValue)
{
    QString output;
    for (int i = 0; output.isEmpty() && i < 11; ++i) {
        QString d = SKGServices::doubleToString(pow(10, i) * iValue);
        if (d.indexOf('.') == -1) output = d % '/' % SKGServices::intToString(qPow(10, i));
    }
    return output;
}


QString SKGImportPluginKmy::getMimeTypeFilter() const
{
    return "*.kmy|" % i18nc("A file format", "KMyMoney document");
}

#include "skgimportpluginkmy.moc"
