"use strict";
var crypto = require("crypto");
var trci = require("./tokenRuleConditionImpl");
var trco = require("./tokenRuleConditionObjDic");

const toKeepAtts = ["overloads", "name", "corrections", "modifications"];

class TokenRuleConditionServices {
    constructor() {
    }

    static Instanciate(ruleManager, json) {
        if (json.conditionId) {
            var macro = ruleManager.conditions[json.conditionId];
            if (!macro) {
                debugger;
                return null;
            }
            if (json.type != "isNotMacro")
            {
                return new trci.TokenRuleConditionMacro(json, macro);
            }
            return new trci.TokenRuleConditionIsNotMacro(json, macro);
        }
        if (json.type == "macro"|| json.type == "isMacro" ||
            (json.type == undefined && json.macro)) {
            if (!ruleManager.macros) {
                debugger;
                return null;
            }

            var macro = ruleManager.macros[json.macro];
            if (!macro) {
                debugger;
                return null;
            }
            return new trci.TokenRuleConditionMacro(json, macro);
        }
        else if (json.type == "isNotMacro") {
            if (!ruleManager.macros) {
                debugger;
                return null;
            }
            var macro = ruleManager.macros[json.macro];
            if (!macro) {
                debugger;
                return null;
            }
            return new trci.TokenRuleConditionIsNotMacro(json, macro);
        }
        if (json.type == "att") {
            if (json.operator == "==") {
                if (json.value != undefined) {
                    return new trci.TokenRuleConditionEqual(json);
                }
                else if (json.tokenAttValue) {
                    return new trci.TokenRuleConditionEqualToOtherAttribute(json);
                }
                else if (json.dictionary) {
                    return new trci.TokenRuleDicAttEqualToTokenAtt(ruleManager, json);
                }
                else {
                    debugger;
                    return null;
                }
            }
            else if (json.operator == "!=") {
                if (json.value!= undefined) {
                    return new trci.TokenRuleConditionNotEqual(json);
                }
                else if (json.tokenAttValue) {
                    return new trci.TokenRuleConditionNotEqualToOtherAttribute(json);
                }
                else if (json.dictionary) {
                    return new trci.TokenRuleDicAttNotEqualToTokenAtt(ruleManager, json);
                }
                else {
                    debugger;
                    return null;
                }
            }
            else if (json.operator == "=~") {
                return new trci.TokenRuleConditionRegExp(json);
            }
            else if (json.operator == "!~") {
                return new trci.TokenRuleConditionNotRegExp(json);
            }
            else if (json.operator == "isIn") {
                if (!json.dictionary || ruleManager.dictionaries[json.dictionary])
                    return new trci.TokenRuleConditionIsIn(ruleManager, json);
                else {
                    return new trco.TokenRuleConditionIsInObj(ruleManager, json);
                }
            }
            else if (json.operator == "isNotIn") {
                if (!json.dictionary || ruleManager.dictionaries[json.dictionary])
                    return new trci.TokenRuleConditionIsNotIn(ruleManager, json);
                else {
                    return new trco.TokenRuleConditionIsNotInObj(ruleManager, json);
                }
            }
            else if (json.operator == "exists") {
                return new trci.TokenRuleAttConditionExists(json);
            }
            else if (json.operator == "notExists") {
                return new trci.TokenRuleAttConditionNotExists(json);
            }
            else if (json.operator == "isPhrase") {
                return new trci.TokenRuleConditionPhrase(json);
            }
            else if (json.operator == "isNotPhrase") {
                return new trci.TokenRuleConditionNotPhrase(json);
            }
            else if (json.operator == "isPartOfPhrase") {
                return new trci.TokenRuleConditionPartOfPhrase(json);
            }
            else if (json.operator == "isNotPartOfPhrase") {
                return new trci.TokenRuleConditionNotPartOfPhrase(json);
            }
            else {
                debugger;
                return null;
            }
        }
        if (json.type == "dicAtt") {
            if (!json.dictionary || ruleManager.dictionaries[json.dictionary]) {
                if (json.operator == "==") {
                    return new trci.TokenRuleDicAttConditionEqual(ruleManager, json);
                }
                else if (json.operator == "!=") {
                    return new trci.TokenRuleDicAttConditionNotEqual(ruleManager, json);
                }
                else if (json.operator == "=~") {
                    return new trci.TokenRuleDicAttConditionRegExp(ruleManager, json);
                }
                else if (json.operator == "!~") {
                    return new trci.TokenRuleDicAttConditionNotRegExp(ruleManager, json);
                }
            }
            else {
                if (json.operator == "==") {
                    return new trco.TokenRuleDicAttConditionEqualObj(ruleManager, json);
                }
                else if (json.operator == "!=") {
                    return new trco.TokenRuleDicAttConditionNotEqualObj(ruleManager, json);
                }
                else if (json.operator == "=~") {
                    return new trco.TokenRuleDicAttConditionRegExpObj(ruleManager, json);
                }
                else if (json.operator == "!~") {
                    return new trco.TokenRuleDicAttConditionNotRegExpObj(ruleManager, json);
                }
            }
        }
        else if (json.type == "and" ||
            json.type == "or") {
            var conditions = [];
            for (var ci = 0; ci < json.conditions.length; ci++) {
                var condition = TokenRuleConditionServices.Instanciate(ruleManager, json.conditions[ci]);
                if (!condition) {
                    debugger;
                    return null;
                }
                conditions.push(condition);
            }
            if (conditions.length == 0) {
                console.error("WARNING: Condition " + json.type + " without condition");
            }
            else if (conditions.length == 1) {
                console.error("WARNING: Condition " + json.type + " with only one condition");
            }
            if (json.type == "and") {
                return new trci.TokenRuleConditionAND(json, conditions);
            }
            else {
                return new trci.TokenRuleConditionOR(json, conditions);
            }
        }
        debugger;
        return null;
    }
    static _StandardBuild(json, dicoConditions)
    {
        var duplicatedCondition = Object.assign({}, json, {});
        if (duplicatedCondition.overloads) {
            delete duplicatedCondition.overloads;
        }
        if (duplicatedCondition.modifications) {
            delete duplicatedCondition.modifications;
        }
        if (duplicatedCondition.corrections) {
            delete duplicatedCondition.corrections;
        }
        var conditionId = crypto.createHmac('sha256', JSON.stringify(duplicatedCondition)).digest('hex');
        if (conditionId != "") {
            if (!dicoConditions[conditionId]) {
                dicoConditions[conditionId] = duplicatedCondition;
            }
            else {
                //console.log("already added: " + conditionId);
            }
            for (var key in json) {
                if (toKeepAtts.indexOf(key) === -1 && json[key]) {
                    delete json[key];
                }
            }
            json.conditionId = conditionId;
        }
        else {
            debugger;
        }
    }
    static Build(ruleManager, json, dicoConditions) {
        var containsOverloads = false;
        if (json.overloads || json.modifications|| json.corrections) {
            containsOverloads = true;
        }
        // macro
        if (json.macro) {
            var macro = ruleManager.macros[json.macro];
            // if (json.type=="isNotMacro")
            // {
            //     debugger;
            // }
            if (!macro) {
                debugger;
            }
            else if (macro.conditionId && macro.conditionId != "") {
                var conditionId = macro.conditionId;
                if (!dicoConditions[conditionId]) {
                    var duplicatedCondition = Object.assign({}, macro, {});
                    if (duplicatedCondition.conditionId) {
                        delete duplicatedCondition.conditionId;
                    }
                    dicoConditions[conditionId] = duplicatedCondition;
                }
                else {
                    //console.log("already added: " + conditionId);
                }
                if (json.macro) delete json.macro;
                json.conditionId = conditionId;
                if (json.type == "isNotMacro") {
                    this._StandardBuild(json, dicoConditions);
                    // var duplicatedCondition = Object.assign({}, json, {});
                    // var conditionId = crypto.createHmac('sha256', JSON.stringify(duplicatedCondition)).digest('hex');
                    // if (conditionId != "") {
                    //     if (!dicoConditions[conditionId]) {
                    //         dicoConditions[conditionId] = duplicatedCondition;
                    //     }
                    //     else {
                    //         //console.log("already added: " + conditionId);
                    //     }
                    //     json.conditionId = conditionId;
                    // }
                    // else {
                    //     debugger;
                    // }
                }
            }
            else {
                debugger;
            }
        }
        // and / or
        else if (json.type == "and" ||
            json.type == "or") {
            for (var ci = 0; ci < json.conditions.length; ci++) {
                if (TokenRuleConditionServices.Build(ruleManager, json.conditions[ci], dicoConditions)) {
                    containsOverloads = true;
                }
            }
            if (!containsOverloads) {
                var duplicatedCondition = Object.assign({}, json, {});
                duplicatedCondition.conditions = [];
                for (var ci = 0; ci < json.conditions.length; ci++) {
                    if (json.conditions[ci].conditionId) {
                        var subConditions = {
                            conditionId: json.conditions[ci].conditionId
                        };
                        duplicatedCondition.conditions.push(subConditions);
                    }
                    else {
                        debugger;
                    }
                }
                // if (duplicatedCondition.conditions.length > 1) {
                //     duplicatedCondition.conditions.sort(function (a, b) {
                //         if (a.conditionId < b.conditionId)
                //             return -1;
                //         else if (a.conditionId > b.conditionId)
                //             return 1;
                //         return 0;
                //     });
                // }
                // else if (duplicatedCondition.conditions.length == 1) {
                //     debugger;
                // }
                if (duplicatedCondition.conditions.length >= 1) {
                    var conditionId = crypto.createHmac('sha256', JSON.stringify(duplicatedCondition)).digest('hex');
                    if (conditionId != "") {
                        if (!dicoConditions[conditionId]) {
                            dicoConditions[conditionId] = duplicatedCondition;
                        }
                        else {
                            //console.log("already added: " + conditionId);
                        }
                        json.conditionId = conditionId;
                    }
                    else {
                        debugger;
                    }
                }
                else {
                    debugger;
                }
            }
        }
        // standard
        else {
           this._StandardBuild(json, dicoConditions);
        }
        return containsOverloads;
    }
}
module.exports = TokenRuleConditionServices;
