/***************************************************************************
 *   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 defines classes SKGRuleObject.
 *
 * @author Stephane MANKOWSKI / Guillaume DE BURE
 */
#include "skgruleobject.h"
#include "skgunitvalueobject.h"
#include "skgtraces.h"

#include <klocale.h>

#include <QDomDocument>

SKGRuleObject::SKGRuleObject(SKGDocument* iDocument, int iID)
    : SKGObjectBase(iDocument, "v_rule", iID)
{
}

SKGRuleObject::SKGRuleObject(const SKGRuleObject& iObject)
    : SKGObjectBase(iObject)
{
}

SKGRuleObject::SKGRuleObject(const SKGObjectBase& iObject)
{
    if (iObject.getRealTable() == "rule") {
        copyFrom(iObject);
    } else {
        *this = SKGObjectBase(iObject.getDocument(), "v_rule", iObject.getID());
    }
}

const SKGRuleObject& SKGRuleObject::operator= (const SKGObjectBase& iObject)
{
    copyFrom(iObject);
    return *this;
}

SKGRuleObject::~SKGRuleObject()
{
}

QString SKGRuleObject::getDisplayName() const
{
    return getSearchDescription();
}

SKGError SKGRuleObject::bookmark(bool iBookmark)
{
    return setAttribute("t_bookmarked", iBookmark ? "Y" : "N");

}

bool SKGRuleObject::isBookmarked() const
{
    return (getAttribute("t_bookmarked") == "Y" ? true : false);
}

SKGError SKGRuleObject::save(bool iInsertOrUpdate, bool iReloadAfterSave)
{
    //Do the save
    SKGError err = SKGObjectBase::save(iInsertOrUpdate, iReloadAfterSave);

    //Raise alarm
    if (!err && getActionType() == ALARM) err = execute();

    return err;
}

SKGError SKGRuleObject::setXMLSearchDefinition(const QString& iXml)
{
    setSearchDescription(SKGRuleObject::getDescriptionFromXML((SKGDocument*) getDocument(), iXml, false, SEARCH));
    return setAttribute("t_definition", iXml);
}

QString SKGRuleObject::getXMLSearchDefinition() const
{
    return getAttribute("t_definition");
}

SKGError SKGRuleObject::setXMLActionDefinition(const QString& iXml)
{
    setActionDescription(SKGRuleObject::getDescriptionFromXML((SKGDocument*) getDocument(), iXml, false, getActionType()));
    return setAttribute("t_action_definition", iXml);
}

QString SKGRuleObject::getXMLActionDefinition() const
{
    return getAttribute("t_action_definition");
}

SKGError SKGRuleObject::setSearchDescription(const QString& iDescription)
{
    return setAttribute("t_description", iDescription);
}

QString SKGRuleObject::getSearchDescription() const
{
    return getAttribute("t_description");
}

SKGError SKGRuleObject::setActionDescription(const QString& iDescription)
{
    return setAttribute("t_action_description", iDescription);
}

QString SKGRuleObject::getActionDescription() const
{
    return getAttribute("t_action_description");
}

SKGError SKGRuleObject::setActionType(SKGRuleObject::ActionType iType)
{
    SKGError err = setAttribute("t_action_type", (iType == SEARCH ? "S" : (iType == UPDATE ? "U" : "A")));
    return err;
}

SKGRuleObject::ActionType SKGRuleObject::getActionType() const
{
    QString typeString = getAttribute("t_action_type");
    return (typeString == "S" ? SEARCH : (typeString == "U" ? UPDATE : ALARM));
}

SKGError SKGRuleObject::setOrder(double iOrder)
{
    SKGError err;
    double order = iOrder;
    if (order == -1) {
        order = 1;
        SKGStringListList result;
        err = getDocument()->executeSelectSqliteOrder("SELECT max(f_sortorder) from rule", result);
        if (!err && result.count() == 2) order = SKGServices::stringToDouble(result.at(1).at(0)) + 1;
    }
    if (!err) err = setAttribute("f_sortorder", SKGServices::doubleToString(order));
    return err;
}

QString SKGRuleObject::getSelectSqlOrder(const QString& iAdditionalCondition) const
{
    QString wc = iAdditionalCondition;
    QString wc2 = SKGRuleObject::getDescriptionFromXML((SKGDocument*) getDocument(), getXMLSearchDefinition(), true, SEARCH);
    if (!wc2.isEmpty()) {
        if (wc.isEmpty()) wc = wc2;
        else wc = '(' % wc % ") AND (" % wc2 % ')';
    }
    if (wc.isEmpty()) wc = "1=1";
    wc = "d_date!='0000-00-00' AND (" % wc % ')';
    return wc;
}

SKGRuleObject::SKGAlarmInfo SKGRuleObject::getAlarmInfo() const
{
    SKGTRACEIN(10, "SKGRuleObject::getAlarmInfo");
    SKGRuleObject::SKGAlarmInfo alarm;
    if (getActionType() == SKGRuleObject::ALARM) {
        //Alarm mode
        QString wc = getSelectSqlOrder();
        if (wc.isEmpty()) wc = "1=1";

        SKGDocument* doc = (SKGDocument*) getDocument();

        QStringList list = SKGRuleObject::getFromXML(doc, getXMLActionDefinition(), true, ALARM, false);
        if (list.count()) {
            QString sql = list.at(0);
            sql.replace("#WC#", wc);

            SKGStringListList result;
            doc->executeSelectSqliteOrder(sql, result);
            if (result.count() == 2) {
                QStringList r = result.at(1);
                alarm.Message = r.at(3);
                alarm.Amount = SKGServices::stringToDouble(r.at(1));
                alarm.Limit = SKGServices::stringToDouble(r.at(2));
            }
        }
    }
    return alarm;
}

SKGError SKGRuleObject::execute(ProcessMode iMode)
{
    SKGError err;
    if (getActionType() == SKGRuleObject::UPDATE) {
        //Update mode
        QString addSql;
        if (iMode == IMPORTED) addSql = "t_imported!='N'";
        else if (iMode == IMPORTEDNOTVALIDATE) addSql = "t_imported='P'";
        else if (iMode == IMPORTING) addSql = "t_imported='T'";

        QString wc = getSelectSqlOrder(addSql);
        if (wc.isEmpty()) wc = "1=1";

        SKGDocument* doc = (SKGDocument*) getDocument();
        if (doc) {
            QStringList list = SKGRuleObject::getFromXML(doc, getXMLActionDefinition(), true, UPDATE, true);  //SQL + SET clause
            int nb = list.count();
            err = doc->beginTransaction("#INTERNAL#" % i18nc("Progression step", "Apply rule"), nb);
            if (!err) {
                //All sql orders must be executed to be sure than i_tmp is reset
                SKGError err2;
                for (int i = 0; i < nb; ++i) {
                    QString sql = list.at(i);
                    sql.replace("#WC#", wc);
                    err2 = doc->executeSqliteOrder(sql);
                    if (!err2) err2 = doc->stepForward(i + 1);
                    if (err2 && !err) err = err2;
                }
            }

            if (!err) {
                SKGStringListList result;
                err = doc->executeSelectSqliteOrder("SELECT changes()", result);
                if (!err && result.count() == 2) {
                    int nb = SKGServices::stringToInt(result.at(1).at(0));
                    if (nb) doc->sendMessage(i18np("1 operation modified by %2", "%1 operations modified by %2", nb, getAttribute("i_ORDER")));
                }
            }

            if (!err) err = doc->endTransaction(true);
            else doc->endTransaction(false);
        }
    } else if (getActionType() == SKGRuleObject::ALARM) {
        //Alarm mode
        QString wc = getSelectSqlOrder();
        if (wc.isEmpty()) wc = "1=1";

        SKGDocument* doc = (SKGDocument*) getDocument();
        if (doc) {
            QStringList list = SKGRuleObject::getFromXML(doc, getXMLActionDefinition(), true, ALARM, false);
            if (list.count()) {
                QString sql = list.at(0);
                sql.replace("#WC#", wc);

                SKGStringListList result;
                err = doc->executeSelectSqliteOrder(sql, result);
                if (!err && result.count() == 2) {
                    //Is alarm raised ?
                    if (result.at(1).at(0) == "1") doc->sendMessage(result.at(1).at(3));
                }
            }
        }
    }
    if (err) err.addError(ERR_FAIL, i18nc("Error message", "Rule %1 failed", getAttribute("i_ORDER")));
    return err;
}

double SKGRuleObject::getOrder() const
{
    return SKGServices::stringToDouble(getAttribute("f_sortorder"));
}

QString SKGRuleObject::getDisplayForOperator(const QString& iOperator, const QString& iParam1, const QString& iParam2, const QString& iAtt2)
{
    QString output = iOperator;
    if (output == "#ATT# LIKE '%#V1S#%'")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "contains '#V1S#'").replace("#V1S#", iParam1);
    else if (output == "#ATT# LIKE '#V1S#%'")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "starts with '#V1S#'").replace("#V1S#", iParam1);
    else if (output == "#ATT# LIKE '%#V1S#'")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "ends with '#V1S#'").replace("#V1S#", iParam1);
    else if (output == "#ATT#=''")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "is empty");
    else if (output == "#ATT#!=''")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "is not empty");

    else if (output == "#ATT#=#V1#")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "=#V1#").replace("#V1#", iParam1);
    else if (output == "#ATT#!=#V1#")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "!=#V1#").replace("#V1#", iParam1);
    else if (output == "#ATT#>#V1#")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", ">#V1#").replace("#V1#", iParam1);
    else if (output == "#ATT#<#V1#")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "<#V1#").replace("#V1#", iParam1);
    else if (output == "#ATT#>=#V1#")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", ">=#V1#").replace("#V1#", iParam1);
    else if (output == "#ATT#<=#V1#")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "<=#V1#").replace("#V1#", iParam1);

    else if (output == "#ATT#='#V1S#'")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "='#V1S#'").replace("#V1S#", iParam1);
    else if (output == "#ATT#!='#V1S#'")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "!='#V1S#'").replace("#V1S#", iParam1);
    else if (output == "#ATT#>'#V1S#'")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", ">'#V1S#'").replace("#V1S#", iParam1);
    else if (output == "#ATT#<'#V1S#'")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "<'#V1S#'").replace("#V1S#", iParam1);
    else if (output == "#ATT#>='#V1S#'")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", ">='#V1S#'").replace("#V1S#", iParam1);
    else if (output == "#ATT#<='#V1S#'")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "<='#V1S#'").replace("#V1S#", iParam1);

    else if (output == "#ATT#>=#V1# AND #ATT#<=#V2#")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "is between #V1# and #V2#").replace("#V1#", iParam1).replace("#V2#", iParam2);
    else if (output == "#ATT#>='#V1S#' AND #ATT#<='#V2S#'")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "is between '#V1S#' and '#V2S#'").replace("#V1S#", iParam1).replace("#V2S#", iParam2);
    else if (output == "#ATT#=lower(#ATT#)")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "is set to lower");
    else if (output == "#ATT#=upper(#ATT#)")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "is set to upper");
    else if (output == "#ATT#!=lower(#ATT#)")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "is not lower");
    else if (output == "#ATT#!=upper(#ATT#)")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "is not upper");

    else if (output == "#ATT#=replace(#ATT2#,'#V1S#','#V2S#')")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "=#ATT2# with '#V1S#' replaced by '#V2S#'").replace("#V1S#", iParam1).replace("#V2S#", iParam2).replace("#ATT2#", iAtt2);
    else if (output == "#ATT#=substr(#ATT2#,'#V1#','#V2#')")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "=substring of #ATT2# from #V1# to #V2#").replace("#V1#", iParam1).replace("#V2#", iParam2).replace("#ATT2#", iAtt2);
    else if (output == "#ATT#=#ATT2#")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "=#ATT2#").replace("#ATT2#", iAtt2);

    else if (output == "STRFTIME('%Y-%m',#ATT#)=STRFTIME('%Y-%m',date('now'))")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "is in current month");
    else if (output == "STRFTIME('%Y-%m',#ATT#)=STRFTIME('%Y-%m',date('now','start of month','-1 month'))")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "is in previous month");
    else if (output == "STRFTIME('%Y',#ATT#)=STRFTIME('%Y',date('now'))")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "is in current year");
    else if (output == "STRFTIME('%Y',#ATT#)=STRFTIME('%Y',date('now','start of month','-1 year'))")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "is in previous year");
    else if (output == "#ATT#>date('now','-30 day') AND #ATT#<=date('now')")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "is in last 30 days");
    else if (output == "#ATT#>date('now','-3 month') AND #ATT#<=date('now')")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "is in last 3 months");
    else if (output == "#ATT#>date('now','-6 month') AND #ATT#<=date('now')")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "is in last 6 months");
    else if (output == "#ATT#>date('now','-12 month') AND #ATT#<=date('now')")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "is in last 12 months");
    else if (output == "#ATT#>date('now','-2 year') AND #ATT#<=date('now')")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "is in last 2 years");
    else if (output == "#ATT#>date('now','-3 year') AND #ATT#<=date('now')")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "is in last 3 years");
    else if (output == "#ATT#>date('now','-5 year') AND #ATT#<=date('now')")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "is in last 5 years");
    else if (output == "ABS(TOTAL(#ATT#))#OP##V1#,ABS(TOTAL(#ATT#)), #V1#, '#V2S#'")
        output = i18nc("Description of a condition. Do not translate key words (#V1S#, #V1#, ...)", "If total(#ATT#)#OP##V1# then send '#V2S#'").replace("#V1#", iParam1).replace("#V2S#", iParam2).replace("#OP#", iAtt2);

    return output;
}

QStringList SKGRuleObject::getListOfOperators(SKGServices::AttributeType iAttributeType, SKGRuleObject::ActionType iType)
{
    QStringList output;
    if (iType == UPDATE) {
        //Mode update
        if (iAttributeType == SKGServices::TEXT) {
            output.push_back("#ATT#='#V1S#'");
            output.push_back("#ATT#=lower(#ATT#)");
            output.push_back("#ATT#=upper(#ATT#)");
            output.push_back("#ATT#=replace(#ATT2#,'#V1S#','#V2S#')");
        } else if (iAttributeType == SKGServices::INTEGER || iAttributeType == SKGServices::FLOAT) {
            output.push_back("#ATT#=#V1#");
        } else if (iAttributeType == SKGServices::DATE || iAttributeType == SKGServices::BOOL || iAttributeType == SKGServices::TRISTATE) {
            output.push_back("#ATT#='#V1S#'");
        }

        if (iAttributeType != SKGServices::BOOL && iAttributeType != SKGServices::TRISTATE) {
            output.push_back("#ATT#=substr(#ATT2#,'#V1#','#V2#')");
            output.push_back("#ATT#=#ATT2#");
        }
    } else if (iType == SEARCH) {
        //Mode query
        if (iAttributeType == SKGServices::TEXT) {
            output.push_back("#ATT# LIKE '%#V1S#%'");
            output.push_back("#ATT# LIKE '#V1S#%'");
            output.push_back("#ATT# LIKE '%#V1S#'");
            output.push_back("#ATT#=''");
            output.push_back("#ATT#!=''");
            output.push_back("#ATT#!=lower(#ATT#)");
            output.push_back("#ATT#!=upper(#ATT#)");
        }

        if (iAttributeType == SKGServices::INTEGER || iAttributeType == SKGServices::FLOAT) {
            output.push_back("#ATT#=#V1#");
            output.push_back("#ATT#!=#V1#");
            output.push_back("#ATT#>#V1#");
            output.push_back("#ATT#<#V1#");
            output.push_back("#ATT#>=#V1#");
            output.push_back("#ATT#<=#V1#");
            output.push_back("#ATT#>=#V1# AND #ATT#<=#V2#");
        }

        if (iAttributeType == SKGServices::BOOL || iAttributeType == SKGServices::TRISTATE || iAttributeType == SKGServices::TEXT || iAttributeType == SKGServices::DATE) {
            output.push_back("#ATT#='#V1S#'");
        }

        if (iAttributeType == SKGServices::TRISTATE || iAttributeType == SKGServices::TEXT || iAttributeType == SKGServices::DATE) {
            output.push_back("#ATT#!='#V1S#'");
        }

        if (iAttributeType == SKGServices::TEXT || iAttributeType == SKGServices::DATE) {
            output.push_back("#ATT#>'#V1S#'");
            output.push_back("#ATT#<'#V1S#'");
            output.push_back("#ATT#>='#V1S#'");
            output.push_back("#ATT#<='#V1S#'");
            output.push_back("#ATT#>='#V1S#' AND #ATT#<='#V2S#'");
        }

        if (iAttributeType == SKGServices::DATE) {
            output.push_back("STRFTIME('%Y-%m',#ATT#)=STRFTIME('%Y-%m',date('now'))");
            output.push_back("STRFTIME('%Y-%m',#ATT#)=STRFTIME('%Y-%m',date('now','start of month','-1 month'))");
            output.push_back("STRFTIME('%Y',#ATT#)=STRFTIME('%Y',date('now'))");
            output.push_back("STRFTIME('%Y',#ATT#)=STRFTIME('%Y',date('now','start of month','-1 year'))");
            output.push_back("#ATT#>date('now','-30 day') AND #ATT#<=date('now')");
            output.push_back("#ATT#>date('now','-3 month') AND #ATT#<=date('now')");
            output.push_back("#ATT#>date('now','-6 month') AND #ATT#<=date('now')");
            output.push_back("#ATT#>date('now','-12 month') AND #ATT#<=date('now')");
            output.push_back("#ATT#>date('now','-2 year') AND #ATT#<=date('now')");
            output.push_back("#ATT#>date('now','-3 year') AND #ATT#<=date('now')");
            output.push_back("#ATT#>date('now','-5 year') AND #ATT#<=date('now')");
        }
    } else if (iType == ALARM) {
        output.push_back("ABS(TOTAL(#ATT#))#OP##V1#,ABS(TOTAL(#ATT#)), #V1#, '#V2S#'");
    }
    return output;
}

QStringList SKGRuleObject::getFromXML(SKGDocument* iDocument, const QString& iXML, bool iSQL, SKGRuleObject::ActionType iType, bool iFullUpdate)
{
    QStringList output;
    if (iFullUpdate) {
        //Add markers
        output.push_back("UPDATE suboperation set i_tmp=1 WHERE id IN (SELECT i_SUBOPID FROM v_operation_prop WHERE #WC#)");
        output.push_back("UPDATE operation set i_tmp=1 WHERE id IN (SELECT id FROM v_operation_prop WHERE #WC#)");
        output.push_back("UPDATE parameters set i_tmp=1 WHERE id IN (SELECT i_PROPPID FROM v_operation_prop WHERE #WC#)");
    }

    QDomDocument doc("SKGML");
    doc.setContent(iXML);
    QDomElement root = doc.documentElement();

    QDomNode l = root.firstChild();
    while (!l.isNull()) {
        QDomElement elementl = l.toElement();
        if (!elementl.isNull()) {
            QString lineDescription;

            QDomNode n = elementl.firstChild();
            bool parenthesisNeeded = false;
            while (!n.isNull()) {
                QDomElement element = n.toElement();
                if (!element.isNull()) {
                    //Build element description
                    QString elementDescription;
                    QString attribute = element.attribute("attribute");
                    QString propName;
                    if (iSQL) {
                        attribute = SKGServices::stringToSqlString(attribute);
                        if (attribute.startsWith(QLatin1String("p_"))) {
                            //Case property
                            propName = attribute.right(attribute.length() - 2);
                            if (iType == SEARCH) {
                                attribute = "i_PROPPNAME='" % SKGServices::stringToSqlString(propName) % "' AND i_PROPVALUE";
                            } else {
                                attribute = "t_value";
                            }
                        }

                        QString part = element.attribute("operator");
                        part = part.replace("#V1#", SKGServices::stringToSqlString(element.attribute("value")));
                        part = part.replace("#V1S#", SKGServices::stringToSqlString(element.attribute("value")));
                        part = part.replace("#V2#", SKGServices::stringToSqlString(element.attribute("value2")));
                        part = part.replace("#V2S#", SKGServices::stringToSqlString(element.attribute("value2")));
                        part = part.replace("#OP#", SKGServices::stringToSqlString(element.attribute("operator2")));

                        elementDescription += part;
                    } else {
                        attribute = "operation." % attribute;
                        if (iDocument) attribute = iDocument->getDisplay(attribute);

                        if (iType != ALARM) {
                            elementDescription = attribute;
                            elementDescription += ' ';
                        }

                        QString tmp = element.attribute("att2s");
                        if (tmp.isEmpty()) tmp = element.attribute("operator2");
                        QString part = SKGRuleObject::getDisplayForOperator(element.attribute("operator"),
                                       element.attribute("value"),
                                       element.attribute("value2"),
                                       tmp);

                        elementDescription += part;
                    }

                    elementDescription = elementDescription.replace("#ATT#", attribute);

                    //Att2
                    QString attribute2 = element.attribute("att2");
                    if (iSQL) {
                        attribute2 = SKGServices::stringToSqlString(attribute2);
                        if (attribute2.startsWith(QLatin1String("p_"))) {
                            QString propertyName = attribute2.right(attribute2.length() - 2);
                            attribute2 = "IFNULL((SELECT v_operation_prop.i_PROPVALUE FROM v_operation_prop WHERE v_operation_prop.id=operation.id AND v_operation_prop.i_PROPPNAME='" % SKGServices::stringToSqlString(propertyName) % "'),'')";
                        } else {
                            attribute2 = "(SELECT " % attribute2 % " FROM v_operation_consolidated WHERE v_operation_consolidated.id=operation.id)";
                        }
                    }
                    elementDescription = elementDescription.replace("#ATT2#", attribute2);

                    //Add it to line description
                    if (iSQL) {
                        if (iType == UPDATE) {
                            if (!iFullUpdate) {
                                output.push_back(elementDescription);
                            } else {
                                QString sqlOrder;
                                if (attribute == "t_REALCATEGORY") {
                                    elementDescription.replace(attribute, "t_fullname");

                                    QString parentcat;
                                    QString cat = element.attribute("value");
                                    bool stop = false;
                                    while (!stop) {
                                        int posSeparator = cat.indexOf(OBJECTSEPARATOR);
                                        if (posSeparator == -1) {
                                            if (parentcat.isEmpty())
                                                output.push_back("INSERT OR IGNORE INTO category (t_name, rd_category_id) VALUES ('" % SKGServices::stringToSqlString(cat) % "', 0)");
                                            else output.push_back("INSERT OR IGNORE INTO category (t_name, rd_category_id) VALUES ('" % SKGServices::stringToSqlString(cat) % "',(SELECT id FROM category WHERE t_fullname='" % SKGServices::stringToSqlString(parentcat) % "'))");
                                            stop = true;
                                        } else {
                                            //Get first and second parts of the branch
                                            QString first = cat.mid(0, posSeparator);
                                            QString second = cat.mid(posSeparator + QString(OBJECTSEPARATOR).length(), cat.length() - posSeparator - QString(OBJECTSEPARATOR).length());
                                            if (parentcat.isEmpty())
                                                output.push_back("INSERT OR IGNORE INTO category (t_name, rd_category_id) VALUES ('" % SKGServices::stringToSqlString(first) % "', 0)");
                                            else output.push_back("INSERT OR IGNORE INTO category (t_name, rd_category_id) VALUES ('" % SKGServices::stringToSqlString(first) % "',(SELECT id FROM category WHERE t_fullname='" % SKGServices::stringToSqlString(parentcat) % "'))");

                                            if (parentcat.isEmpty()) parentcat = first;
                                            else parentcat = parentcat % OBJECTSEPARATOR % first;
                                            cat = second;
                                        }
                                    }
                                    output.push_back("UPDATE suboperation set r_category_id=(SELECT id FROM category WHERE " % elementDescription % ") WHERE i_tmp=1");
                                } else if (attribute == "t_REALCOMMENT") {
                                    elementDescription.replace(attribute, "t_comment");
                                    output.push_back("UPDATE suboperation set " % elementDescription % " WHERE i_tmp=1 AND NOT(" % elementDescription % ')');
                                } else if (attribute == "t_ACCOUNT") {
                                    elementDescription.replace(attribute, "t_name");
                                    output.push_back("INSERT OR IGNORE INTO account (t_name, rd_bank_id) VALUES ('" % SKGServices::stringToSqlString(element.attribute("value")) % "', (SELECT MIN(id) FROM bank))");
                                    output.push_back("UPDATE operation set rd_account_id=(SELECT id FROM account WHERE " % elementDescription % ") WHERE i_tmp=1");
                                } else if (attribute == "t_PAYEE") {
                                    elementDescription.replace(attribute, "t_name");
                                    output.push_back("INSERT OR IGNORE INTO payee (t_name) VALUES ('" % SKGServices::stringToSqlString(element.attribute("value")) % "')");
                                    output.push_back("UPDATE operation set r_payee_id=(SELECT id FROM payee WHERE " % elementDescription % ") WHERE i_tmp=1");
                                } else if (attribute == "t_REALREFUND") {
                                    elementDescription.replace(attribute, "t_name");
                                    output.push_back("INSERT OR IGNORE INTO refund (t_name) VALUES ('" % SKGServices::stringToSqlString(element.attribute("value")) % "')");
                                    output.push_back("UPDATE suboperation set r_refund_id=(SELECT id FROM refund WHERE " % elementDescription % ") WHERE i_tmp=1");
                                } else if (element.attribute("attribute").startsWith(QLatin1String("p_"))) {
                                    output.push_back("INSERT OR IGNORE INTO parameters (t_uuid_parent, t_name, i_tmp) SELECT o.id||'-operation', '" % SKGServices::stringToSqlString(propName) % "', 1 FROM operation o WHERE o.i_tmp=1");
                                    output.push_back("UPDATE parameters set " % elementDescription % " WHERE i_tmp=1 AND t_name='" % SKGServices::stringToSqlString(propName) % "' AND NOT(" % elementDescription % ')');
                                    output.push_back("DELETE FROM parameters WHERE i_tmp=1 AND t_name='" % SKGServices::stringToSqlString(propName) % "' AND t_value=''");
                                } else {
                                    output.push_back("UPDATE operation set " % elementDescription % " WHERE i_tmp=1 AND NOT(" % elementDescription % ')');
                                }
                            }
                        } else if (iType == ALARM) {
                            output.push_back("SELECT " % elementDescription % " FROM v_operation_consolidated WHERE #WC#");
                        }
                    }

                    if (!lineDescription.isEmpty()) {
                        lineDescription += (iType == UPDATE ? " , " : (iSQL ? " AND " : i18nc("logical operator in a search query", " and ")));
                        parenthesisNeeded = true;
                    }
                    lineDescription += elementDescription;
                }
                n = n.nextSibling();
            }

            if (!(iType != SEARCH && iSQL) && !lineDescription.isEmpty()) {
                if (iType == SEARCH && parenthesisNeeded) lineDescription = '(' % lineDescription % ')';
                output.push_back(lineDescription);
            }
        }
        l = l.nextSibling();
    }

    if (iFullUpdate) {
        //Remove markers
        output.push_back("UPDATE suboperation set i_tmp=0 WHERE i_tmp=1");
        output.push_back("UPDATE operation set i_tmp=0 WHERE i_tmp=1");
        output.push_back("UPDATE parameters set i_tmp=0 WHERE i_tmp=1");
    }
    return output;
}

QString SKGRuleObject::getDescriptionFromXML(SKGDocument* iDocument, const QString& iXML, bool iSQL, SKGRuleObject::ActionType iType)
{
    QString output;

    QStringList list = getFromXML(iDocument, iXML, iSQL, iType);
    int nb = list.count();
    for (int i = 0; i < nb; ++i) {
        output.append(list[i]);
        if (i < nb - 1) output.append(iType != SEARCH ? " , " : (iSQL ? " OR " : i18nc("logical operator in a search query", " or ")));
    }
    return output;
}
#include "skgruleobject.moc"
