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

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

#include <QDomDocument>
#include <QFileInfo>
#include <cmath>

#ifdef Q_OS_WIN
#define isnan(a) _isnan(a)
#define isinf(a) !_finite(a)
#else
using std::isnan;
using std::isinf;
#endif

/**
 * This plugin factory.
 */
K_PLUGIN_FACTORY(SKGImportPluginGncFactory, registerPlugin<SKGImportPluginGnc>();)
/**
 * This plugin export.
 */
K_EXPORT_PLUGIN(SKGImportPluginGncFactory("skrooge_import_gnc", "skrooge_import_gnc"))

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

SKGImportPluginGnc::~SKGImportPluginGnc()
{
}

bool SKGImportPluginGnc::isImportPossible()
{
    SKGTRACEIN(10, "SKGImportPluginCsv::isImportPossible");
    if (!m_importer) return true;
    QString extension = QFileInfo(m_importer->getFileName()).suffix().toUpper();
    return (extension == "UNCOMPRESSED" || extension == "GNUCASH" || extension == "GNC");
}

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

    //Open file
    QIODevice* file = KFilterDev::deviceForFile(m_importer->getLocalFileName(), "application/x-gzip");
    if (!file->open(QIODevice::ReadOnly)) {
        err.setReturnCode(ERR_INVALIDARG);
        err.setMessage(i18nc("Error message",  "Open file '%1' failed", m_importer->getFileName()));
    } 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);
            err.setMessage(i18nc("Error message",  "%1-%2: '%3'", errorLine, errorCol, errorMsg));

            err.addError(ERR_INVALIDARG, i18nc("Error message",  "Invalid XML content in file '%1'", m_importer->getFileName()));
        } else {
            //Get root
            QDomElement docElem = doc.documentElement();

            ////Get book
            QDomElement book = docElem.firstChildElement("gnc:book");
            if (book.isNull()) {
                book = docElem;
            }
            if (book.isNull()) {
                err = SKGError(ERR_INVALIDARG, i18nc("Error message",  "Invalid XML content in file '%1'", m_importer->getFileName()));
            } else {
                QMap<QString, SKGUnitObject> mapUnitIdUnit;
                err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import %1 file", "GNC"), 6);
                if (!err) {
                    //Step 1-Get units
                    SKGUnitObject defaultUnit;
                    {
                        QDomNodeList unitList = book.elementsByTagName("gnc:commodity");
                        int nbUnit = unitList.count();
                        err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import units"), nbUnit);
                        for (int i = 0; !err && i < nbUnit; ++i) {
                            QDomElement unit = unitList.at(i).toElement();
                            QDomElement unitName = unit.firstChildElement("cmdty:id");
                            QDomElement unitSpace = unit.firstChildElement("cmdty:space");
                            if (!unitName.isNull() && !unitSpace.isNull()) {
                                SKGUnitObject unitObj(m_importer->getDocument());
                                if (unitSpace.text() == "ISO4217") {
                                    //We try a creation
                                    SKGUnitObject::createCurrencyUnit(m_importer->getDocument(), unitName.text(), unitObj);
                                }

                                if (!err && !unitObj.exist()) {
                                    //Creation of unit
                                    err = unitObj.setName(unitName.text());
                                    if (!err) err = unitObj.setSymbol(unitName.text());
                                    if (!err) err = unitObj.setType(SKGUnitObject::SHARE);
                                    if (!err) err = unitObj.save();
                                }

                                if (!err && !defaultUnit.exist()) defaultUnit = unitObj;

                                mapUnitIdUnit[unitName.text()] = 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 accounts and categories
                    SKGAccountObject gnucashTemporaryAccount(m_importer->getDocument());
                    QMap<QString, QString> mapIdName;
                    QMap<QString, QChar> mapIdType;
                    QMap<QString, SKGUnitObject> mapIdUnit;
                    QMap<QString, SKGAccountObject> mapIdAccount;
                    QMap<QString, SKGCategoryObject> mapIdCategory;

                    //Create bank and temporary account for gnucash import
                    SKGBankObject bank(m_importer->getDocument());
                    if (!err) err = m_importer->getDocument()->addOrModifyAccount("GNUCASH-TEMPORARY-ACCOUNT", "", "GNUCASH");
                    if (!err) err = bank.setName("GNUCASH");
                    if (!err) err = bank.load();
                    if (!err) err = gnucashTemporaryAccount.setName("GNUCASH-TEMPORARY-ACCOUNT");
                    if (!err) err = gnucashTemporaryAccount.load();

                    {
                        //Create accounts
                        QDomNodeList accountList = book.elementsByTagName("gnc:account");
                        int nbAccount = accountList.count();
                        if (!err) err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import banks and accounts"), nbAccount);
                        for (int i = 0; !err && i < nbAccount; ++i) {
                            QDomElement account = accountList.at(i).toElement();
                            QDomElement parent = account.parentNode().toElement();
                            if (parent.tagName() != "gnc:template-transactions") {
                                QDomElement accountId = account.firstChildElement("act:id");
                                QDomElement accountName = account.firstChildElement("act:name");
                                QDomElement accountType = account.firstChildElement("act:type");
                                QDomElement accountCode = account.firstChildElement("act:code");

                                QString realAccountName = accountName.text();

                                if (!accountId.isNull() && !accountType.isNull() && !realAccountName.isEmpty()) {
                                    QString type = accountType.text();
                                    if (type == "INCOME" || type == "EXPENSE") {
                                        //It is a category
                                        QString fullName = realAccountName;

                                        QDomElement accountParent = account.firstChildElement("act:parent");
                                        if (!err && !accountParent.isNull() && mapIdType[accountParent.text()] == 'C')
                                            fullName = mapIdName[accountParent.text()] % OBJECTSEPARATOR % fullName;

                                        SKGCategoryObject catObj;
                                        err = SKGCategoryObject::createPathCategory(m_importer->getDocument(), fullName, catObj);

                                        mapIdCategory[accountId.text()] = catObj;
                                        mapIdType[accountId.text()] = 'C'; //Memorize an account
                                    } else if (type == "BANK" || type == "STOCK" || type == "ASSET" || type == "LIABILITY" || type == "RECEIVABLE" || type == "CREDITCARD" || type == "CASH") {
                                        //It is a real account
                                        SKGAccountObject act(m_importer->getDocument());
                                        err = bank.addAccount(act);
                                        if (!err) err = act.setName(realAccountName);
                                        int index = 1;
                                        while (!err && act.exist()) {
                                            index++;
                                            realAccountName = accountName.text() % " (" % SKGServices::intToString(index) % ')';
                                            err = act.setName(realAccountName);
                                        }
                                        if (!err && accountCode.isNull()) err = act.setNumber(accountCode.text());
                                        if (!err) err = act.setType(type == "ASSET" ? SKGAccountObject::ASSETS : type == "STOCK" ? SKGAccountObject::INVESTMENT : type == "CASH" ? SKGAccountObject::WALLET : type == "LIABILITY" ? SKGAccountObject::LOAN : SKGAccountObject::CURRENT);
                                        if (!err) err = act.save();

                                        mapIdAccount[accountId.text()] = act;
                                        mapIdType[accountId.text()] = 'A'; //Memorize an account

                                        QDomNodeList accountUnits = account.elementsByTagName("cmdty:id");
                                        if (!err && accountUnits.count()) mapIdUnit[accountId.text()] = mapUnitIdUnit[accountUnits.at(0).toElement().text()];
                                    } else if (type == "EQUITY") {
                                        mapIdType[accountId.text()] = 'E'; //Memorize an account
                                    } else {
                                        mapIdType[accountId.text()] = ' '; //Memorize an account
                                    }


                                    mapIdName[accountId.text()] = realAccountName;
                                }
                            }

                            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- Get operations
                    QMap<QString, SKGOperationObject> mapIdScheduledOperation;
                    {
                        QDomNodeList operationsList = book.elementsByTagName("gnc:transaction");
                        int nbOperations = operationsList.count();
                        if (!err) err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import operations"), nbOperations);
                        for (int i = 0; !err && i < nbOperations; ++i) {
                            QDomElement operation = operationsList.at(i).toElement();

                            QDomElement operationId = operation.firstChildElement("trn:id");
                            QDomElement operationDate = operation.firstChildElement("trn:date-posted");
                            QDomElement operationNumber = operation.firstChildElement("trn:num");
                            QDomElement operationPayee = operation.firstChildElement("trn:description");
                            QDomElement operationSlots = operation.firstChildElement("trn:slots");

                            SKGOperationObject operationObj;
                            err = gnucashTemporaryAccount.addOperation(operationObj);
                            if (!err && !operationDate.isNull()) {
                                //Format 2007-01-13 00:00:00 +0100
                                err = operationObj.setDate(QDate::fromString(operationDate.text().left(10), "yyyy-MM-dd"));
                            }
                            if (!err && !operationNumber.isNull()) err = operationObj.setNumber(SKGServices::stringToInt(operationNumber.text()));
                            if (!err && !operationPayee.isNull()) {
                                SKGPayeeObject payeeObject;
                                err = SKGPayeeObject::createPayee(m_importer->getDocument(), operationPayee.text(), payeeObject);
                                if (!err) err = operationObj.setPayee(payeeObject);
                            }
                            if (!err) err = operationObj.setImported(true);
                            if (!err) err = operationObj.setImportID("GNC-" % operationId.text());
                            if (!err) err = operationObj.setUnit(defaultUnit);

                            if (!err) {
                                QDomElement parent = operation.parentNode().toElement();
                                err = operationObj.setTemplate(parent.tagName() == "gnc:template-transactions");
                            }
                            if (!operationSlots.isNull()) {
                                QDomNodeList slotList = operationSlots.elementsByTagName("slot");
                                int nbSlots = slotList.count();
                                for (int k = 0; !err && k < nbSlots; ++k) {
                                    QDomElement slot = slotList.at(k).toElement();

                                    QDomElement key = slot.firstChildElement("slot:key");
                                    QDomElement value = slot.firstChildElement("slot:value");
                                    if (!key.isNull() && !value.isNull()) {
                                        if (key.text() == "notes") {
                                            err = operationObj.setComment(value.text());
                                        }
                                    }
                                }
                            }
                            if (!err) err = operationObj.save();

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

                            QList<SubOpInfo> suboperationsList;
                            int nbSuboperations = 0;
                            {
                                QDomNodeList suboperationsListTmp = splits.elementsByTagName("trn:split");
                                nbSuboperations = suboperationsListTmp.count();

                                int nbRealSuboperations = 0;
                                for (int j = 0; !err && j < nbSuboperations; ++j) {
                                    SubOpInfo info;
                                    info.subOp = suboperationsListTmp.at(j).toElement();
                                    info.account = info.subOp.firstChildElement("split:account");
                                    info.value = 0;
                                    QStringList vals = SKGServices::splitCSVLine(info.subOp.firstChildElement("split:quantity").text(), '/');
                                    if (vals.count() == 1) info.value = SKGServices::stringToDouble(vals.at(0));
                                    else if (vals.count() == 2) info.value = SKGServices::stringToDouble(vals.at(0)) / SKGServices::stringToDouble(vals.at(1));

                                    QDomElement suboperationSlots = info.subOp.firstChildElement("split:slots");
                                    if (!suboperationSlots.isNull()) {
                                        QDomNodeList slotList = suboperationSlots.elementsByTagName("slot");
                                        int nbSlots = slotList.count();
                                        for (int k = 0; !err && k < nbSlots; ++k) {
                                            QDomElement slot = slotList.at(k).toElement();

                                            QDomElement key = slot.firstChildElement("slot:key");
                                            QDomElement value = slot.firstChildElement("slot:value");
                                            if (!key.isNull() && !value.isNull()) {
                                                if (key.text() == "sched-xaction") {
                                                    //This is a scheduled operation
                                                    QDomNodeList scheduledSlotList = value.elementsByTagName("slot");
                                                    int nbscheduledSlotList = scheduledSlotList.count();
                                                    for (int k2 = 0; !err && k2 < nbscheduledSlotList; ++k2) {
                                                        QDomElement slot = scheduledSlotList.at(k2).toElement();

                                                        QDomElement key = slot.firstChildElement("slot:key");
                                                        QDomElement value = slot.firstChildElement("slot:value");
                                                        if (!key.isNull() && !value.isNull()) {
                                                            if (key.text() == "account") {
                                                                mapIdScheduledOperation[info.account.text()] = operationObj;
                                                                info.account = value;
                                                            } else if (key.text() == "debit-formula" && !value.text().isEmpty()) {
                                                                QStringList vals = SKGServices::splitCSVLine(value.text(), '/');
                                                                if (vals.count() == 1) info.value = SKGServices::stringToDouble(vals.at(0));
                                                                else if (vals.count() == 2) info.value = SKGServices::stringToDouble(vals.at(0)) / SKGServices::stringToDouble(vals.at(1));
                                                            } else if (key.text() == "credit-formula" && !value.text().isEmpty()) {
                                                                QStringList vals = SKGServices::splitCSVLine(value.text(), '/');
                                                                if (vals.count() == 1) info.value = -SKGServices::stringToDouble(vals.at(0));
                                                                else if (vals.count() == 2) info.value = -SKGServices::stringToDouble(vals.at(0)) / SKGServices::stringToDouble(vals.at(1));
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }

                                    if (!isnan(info.value)) {
                                        QChar accountType = mapIdType[info.account.text()];
                                        if (accountType == 'C') {
                                            suboperationsList.push_front(info);
                                        } else {
                                            suboperationsList.push_back(info);
                                        }

                                        ++nbRealSuboperations;
                                    }
                                }
                                nbSuboperations = nbRealSuboperations;
                            }

                            SKGSubOperationObject suboperationObj;
                            for (int j = 0; !err && j < nbSuboperations; ++j) {
                                SubOpInfo suboperationInfo = suboperationsList.at(j);
                                QDomElement suboperation = suboperationInfo.subOp.toElement();
                                QDomElement suboperationReconciled = suboperation.firstChildElement("split:reconciled-state");
                                QDomElement suboperationMemo = suboperation.firstChildElement("split:memo");
                                QDomElement suboperationAction = suboperation.firstChildElement("split:action");

                                //Set operation attribute
                                if (!suboperationReconciled.isNull() && operationObj.getStatus() == SKGOperationObject::NONE) {
                                    QString val = suboperationReconciled.text();
                                    if (!err) err = operationObj.setStatus(val == "c" ? SKGOperationObject::POINTED : val == "y" ? SKGOperationObject::CHECKED : SKGOperationObject::NONE);
                                }
                                if (!err && !suboperationMemo.isNull() && operationObj.getComment().isEmpty()) err = operationObj.setComment(suboperationMemo.text());
                                if (!err && !suboperationAction.isNull() && operationObj.getMode().isEmpty()) err = operationObj.setMode(suboperationAction.text());
                                if (!err) err = operationObj.save();

                                QChar accountType = mapIdType[suboperationInfo.account.text()];
                                if (accountType == 'C') {
                                    //It is a split on category
                                    SKGCategoryObject cat = mapIdCategory[suboperationInfo.account.text()];

                                    double q = -suboperationInfo.value;
                                    if (!err && (!suboperationObj.exist() || suboperationObj.getQuantity() != q)) err = operationObj.addSubOperation(suboperationObj);
                                    if (!err) err = suboperationObj.setQuantity(q);
                                    if (!err) err = suboperationObj.setCategory(cat);
                                    if (!err && !suboperationMemo.isNull()) err = suboperationObj.setComment(suboperationMemo.text());
                                    if (!err) err = suboperationObj.save();
                                } else if (accountType == 'E') {
                                    //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();
                                } else if (accountType == 'A') {
                                    //It is a transfer of account
                                    SKGAccountObject act(m_importer->getDocument());
                                    if (!err) err = act.setName(mapIdName[suboperationInfo.account.text()]);
                                    if (!err) err = act.load();

                                    //Set Unit
                                    SKGUnitObject unitName = mapIdUnit[suboperationInfo.account.text()];

                                    if (parentSet) {
                                        //If the parent is already set, it means that is a transfer
                                        SKGOperationObject operationObj2;
                                        if (!err) err = act.addOperation(operationObj2);
                                        if (!err) err = operationObj2.setDate(operationObj.getDate());
                                        if (!err) err = operationObj2.setNumber(operationObj.getNumber());
                                        if (!err) err = operationObj2.setMode(operationObj.getMode());
                                        if (!err && !suboperationMemo.isNull()) err = operationObj2.setComment(suboperationMemo.text());
                                        SKGPayeeObject payeeObject;
                                        operationObj.getPayee(payeeObject);
                                        if (!err) err = operationObj2.setPayee(payeeObject);
                                        if (!err) {
                                            QString val = suboperationReconciled.text();
                                            err = operationObj2.setStatus(val == "c" ? SKGOperationObject::POINTED : val == "y" ? SKGOperationObject::CHECKED : SKGOperationObject::NONE);
                                        }
                                        if (!err) err = operationObj2.setImported(true);
                                        if (!err) err = operationObj2.setImportID(operationObj.getImportID());
                                        if (!err) err = operationObj2.setTemplate(operationObj.isTemplate());
                                        if (!err && unitName.exist()) err = operationObj2.setUnit(unitName);
                                        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
                                            quantity = suboperationInfo.value;
                                            err = suboperationObj2.setQuantity(suboperationInfo.value);
                                        }
                                        if (!err && !suboperationMemo.isNull()) err = suboperationObj2.setComment(suboperationMemo.text());
                                        if (!err) err = suboperationObj2.save();
                                    } else {
                                        //We set the parent
                                        if (!err) err = operationObj.setParentAccount(act);
                                        if (!err && unitName.exist()) err = operationObj.setUnit(unitName);
                                        if (!err) err = operationObj.save();

                                        //Compute quantity
                                        quantity = suboperationInfo.value;

                                        //Create sub operation on operationObj
                                        quantity -= SKGServices::stringToDouble(operationObj.getAttribute("f_QUANTITY"));
                                        if (fabs(quantity) > 10e-9) {
                                            if (!err) err = operationObj.addSubOperation(suboperationObj);
                                            if (!err) err = suboperationObj.setQuantity(quantity);
                                            if (!err && !suboperationMemo.isNull()) err = suboperationObj.setComment(suboperationMemo.text());
                                            if (!err) err = suboperationObj.save();
                                        }

                                        parentSet = true;
                                    }
                                }
                            }

                            if (!err && i % 100 == 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(3);

                    //Step 4-Get scheduled
                    {
                        //Create scheduled
                        QDomNodeList scheduleList = book.elementsByTagName("gnc:schedxaction");
                        int nbSchedule = scheduleList.count();
                        if (!err) err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import scheduled operations"), nbSchedule);
                        for (int i = 0; !err && i < nbSchedule; ++i) {
                            QDomElement schedule = scheduleList.at(i).toElement();
                            QDomElement scheduleAutoCreate = schedule.firstChildElement("sx:autoCreate");
                            QDomElement scheduleAutoCreateNotify = schedule.firstChildElement("sx:autoCreateNotify");
                            QDomElement scheduleAdvanceCreateDays = schedule.firstChildElement("sx:advanceCreateDays");
                            QDomElement scheduleAdvanceRemindDays = schedule.firstChildElement("sx:advanceRemindDays");
                            QDomElement scheduleOccur = schedule.firstChildElement("sx:num-occur");
                            QDomElement scheduleEnable = schedule.firstChildElement("sx:enabled");
                            QDomElement scheduleLast = schedule.firstChildElement("sx:last");
                            if (scheduleLast.isNull()) scheduleLast = schedule.firstChildElement("sx:start");

                            QDomElement scheduleMult;
                            QDomElement schedulePeriod;
                            QDomElement scheduleDate;
                            QDomNodeList scheduleScheduleList = schedule.elementsByTagName("gnc:recurrence");
                            if (scheduleScheduleList.count()) {
                                QDomElement scheduleSchedule = scheduleScheduleList.at(0).toElement();
                                scheduleMult = scheduleSchedule.firstChildElement("recurrence:mult");
                                schedulePeriod = scheduleSchedule.firstChildElement("recurrence:period_type");

                                scheduleDate = scheduleLast.firstChildElement("gdate");
                            }

                            QDomElement scheduleTempl = schedule.firstChildElement("sx:templ-acct");
                            if (!scheduleTempl.isNull()) {
                                SKGOperationObject operation = mapIdScheduledOperation[scheduleTempl.text()];
                                SKGRecurrentOperationObject recuOperation;
                                err = operation.addRecurrentOperation(recuOperation);
                                if (!err && !scheduleOccur.isNull()) {
                                    err = recuOperation.timeLimit(true);
                                    if (!err) err = recuOperation.setTimeLimit(SKGServices::stringToInt(scheduleOccur.text()));
                                }
                                if (!err && !scheduleAutoCreate.isNull()) err = recuOperation.autoWriteEnabled(scheduleAutoCreate.text() == "y");
                                if (!err && !scheduleAdvanceCreateDays.isNull()) err = recuOperation.setAutoWriteDays(SKGServices::stringToInt(scheduleAdvanceCreateDays.text()));
                                if (!err && !scheduleAutoCreateNotify.isNull()) err = recuOperation.warnEnabled(scheduleAutoCreateNotify.text() == "y");
                                if (!err && !scheduleAdvanceRemindDays.isNull()) err = recuOperation.setWarnDays(SKGServices::stringToInt(scheduleAdvanceRemindDays.text()));

                                if (!err && !scheduleMult.isNull() && !schedulePeriod.isNull()) {
                                    int p = SKGServices::stringToInt(scheduleMult.text());
                                    SKGRecurrentOperationObject::PeriodUnit punit = SKGRecurrentOperationObject::DAY;
                                    if (schedulePeriod.text() == "month") punit = SKGRecurrentOperationObject::MONTH;
                                    else if (schedulePeriod.text() == "week") punit = SKGRecurrentOperationObject::WEEK;

                                    err = recuOperation.setPeriodIncrement(p);
                                    if (!err) err = recuOperation.setPeriodUnit(punit);
                                }

                                if (!err && !scheduleDate.isNull()) err = recuOperation.setDate(QDate::fromString(scheduleDate.text().left(10), "yyyy-MM-dd"));
                                if (!err) err = recuOperation.setDate(recuOperation.getNextDate());
                                if (!err && !scheduleEnable.isNull() && scheduleEnable.text() == "n") {
                                    err = recuOperation.autoWriteEnabled(false);
                                    if (!err) err = recuOperation.setWarnDays(false);
                                }

                                if (!err) err = recuOperation.save();
                            }

                            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-Get unit values
                    {
                        //Create unit values
                        QDomElement pricedb = book.firstChildElement("gnc:pricedb");
                        if (!pricedb.isNull()) {
                            QDomNodeList priceList = pricedb.elementsByTagName("price");
                            int nbPrice = priceList.count();
                            if (!err) err = m_importer->getDocument()->beginTransaction("#INTERNAL#" % i18nc("Import step", "Import units"), nbPrice);
                            for (int i = 0; !err && i < nbPrice; ++i) {
                                QDomElement price = priceList.at(i).toElement();

                                QDomNodeList priceIdList = price.elementsByTagName("cmdty:id");
                                QDomNodeList priceDateList = price.elementsByTagName("ts:date");
                                QDomElement priceValue = price.firstChildElement("price:value");

                                if (priceIdList.count() && priceDateList.count() && !priceValue.isNull()) {
                                    QString unitName = priceIdList.at(0).toElement().text();
                                    QDate unitDate = QDate::fromString(priceDateList.at(0).toElement().text().left(10), "yyyy-MM-dd");

                                    double val = 0;
                                    QStringList vals = SKGServices::splitCSVLine(priceValue.text(), '/');
                                    if (vals.count() == 1) val = SKGServices::stringToDouble(vals.at(0));
                                    else if (vals.count() == 2) val = SKGServices::stringToDouble(vals.at(0)) / SKGServices::stringToDouble(vals.at(1));

                                    err = m_importer->getDocument()->addOrModifyUnitValue(unitName, unitDate, val);

                                }

                                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-Remove useless account and temporary account
                    {
                        if (!err) err = gnucashTemporaryAccount.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(6);
                    }
                }

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

    delete file;
    return err;
}

QString SKGImportPluginGnc::getMimeTypeFilter() const
{
    return "*.uncompressed *.gnucash *.gnc|" % i18nc("A file format", "GnuCash document");
}

#include "skgimportplugingnc.moc"
