"use strict";
const _ = require("lodash")
const TokenRule = require("./tokenRule");
const Overload = require('./overload');
// --------------
//  SentenceRule
// --------------

module.exports = class SentenceRule {
    constructor(json, tokenRules, endTokenRules, endTokenRule, exceptions, rulesOnResults, ruleInfo) {
        this.title = "";
        this.id = 0;
        if (json.id != undefined) {
            this.id = json.id;
        }
        if (json.type) {
            this.type = json.type;
        }
        if (json.title) {
            this.title = json.title;
        }
        if (json.learningCard) {
            this.learningCard = json.learningCard;
        }
        if (json.phrase) {
            this.phrase = json.phrase;
        }
        if (json.overloads) {
            this.overloads = Overload.ConvertOverloads(json.overloads);
        }
        if (json.modifications) {
            this.modifications = json.modifications;
        }
        if (json.corrections) {
            this.modifications = json.corrections;
        }
        if (json.function) {
            this.function = json.function;
        }
        this.control = "all";
        if (json.control && (json.control == "all" || json.control == "start")) {
            this.control = json.control;
        }
        this.mode = 1;
        if (json.mode != undefined)
        {
            this.mode = json.mode;
        }
        // else{

        // }
        // this.category = "General";
        // if (json.category)
        // {
        //     this.category = json.category;
        // }
        if (json.priorityGroup) {
            this.priorityGroup = json.priorityGroup;
        }
        if (tokenRules) {
            this.tokenRules = tokenRules;
        }
        else {
            debugger;
            this.tokenRules = [];
        }
        if (endTokenRules){
            this.endTokenRules = endTokenRules;
        }
        if (endTokenRule) {
            this.endTokenRule = endTokenRule;
        }
        if (exceptions) {
            this.exceptions = exceptions;
        }
        if (ruleInfo) {
            if (ruleInfo.category) {
                this.category = ruleInfo.category;
            }
            if (ruleInfo.depth != undefined) {
                this.depth = ruleInfo.depth;
            }
        }
        if (json.depth != undefined) {
            this.depth = json.depth;
        }

        if (rulesOnResults) {
            this.rulesOnResults = rulesOnResults;
        }
    }
    static GetRulesOnDico(rulesIndices, dicoRules) {
        var rules = [];
        if (rulesIndices) {
            if (dicoRules) {
                for (var i = 0; i < rulesIndices.length; i++) {
                    var rule = dicoRules[rulesIndices[i]];
                    if (rule) {
                        rules.push(rule);
                    }
                    else {
                        debugger;
                        return null;
                    }
                }
            }
            else {
                debugger;
                return null;
            }
        }
        return rules;
    }
    static Build(ruleManager, json, dicoConditions) {
        for (var i = 0; i < json.tokenRules.length; i++) {
            TokenRule.Build(ruleManager, json.tokenRules[i], dicoConditions);
        }
    }
    static Instanciate(ruleManager, json, dicoExceptions, dicoRulesOnResults, ruleInfo) {
        var tokenRules = [];
        for (var i = 0; i < json.tokenRules.length; i++) {
            var jsonTR = json.tokenRules[i];
            var tokenRule = TokenRule.Instanciate(ruleManager, jsonTR);
            if (tokenRule) {
                tokenRules.push(tokenRule);
            }
            else {
                debugger;
                return null;
            }
        }
        let endTokenRules = null;
        if (json.endTokenRules) {
            endTokenRules = [];
            for (var i = 0; i < json.endTokenRules.length; i++) {
                var jsonTR = json.endTokenRules[i];
                var tokenRule = TokenRule.Instanciate(ruleManager, jsonTR);
                if (tokenRule) {
                    endTokenRules.push(tokenRule);
                }
                else {
                    debugger;
                    return null;
                }
            }
        }
        var endTokenRule = null;
        if (json.endTokenRule) {
            endTokenRule = TokenRule.Instanciate(ruleManager, json.endTokenRule);
            if (!endTokenRule) {
                debugger;
                return null;
            }
            if (!endTokenRule.rootCondition) {
                console.error("no supported");
                debugger;
                return null;
            }
        }
        var exceptions = SentenceRule.GetRulesOnDico(json.exceptions, dicoExceptions);
        var rulesOnResults = SentenceRule.GetRulesOnDico(json.rulesOnResults, dicoRulesOnResults);

        return new SentenceRule(json, tokenRules, endTokenRules, endTokenRule, exceptions, rulesOnResults, ruleInfo);
    }
    GetTargetTokenIndice(result, modification, tokenRule) {
        var tokenIndices = null;
        if (modification.targetTokenRuleIndice >= 0 &&
            modification.targetTokenRuleIndice < result.tokenRules.length) {
            tokenIndices = result.tokenRules[modification.targetTokenRuleIndice].tokenIndices;
        }
        else if (tokenRule) {
            tokenIndices = tokenRule.tokenIndices;
        }
        if (tokenIndices && tokenIndices.length) {
            if (modification.type == "moveBefore" ||
                modification.type == "insert") {
                return tokenIndices[0];
            }
            else if (modification.type == "moveAfter" ||
                modification.type == "insertAfter") {
                return tokenIndices[tokenIndices.length - 1];
            }
            else {
                debugger; //there is an unused targetTokenRuleIndice
            }
        }
        else {
            if (result.rule && result.rule.title) {
                console.error("Error on rule: " + result.rule.title);
            }
            console.error("tokenIndices empty or not defined");
            debugger;
        }
        return -1;
    }
    _AddModifications(ruleManager, functionAdd, sentence, result, tokenRule, modification) {
        if (modification.type == "insert" ||
            modification.type == "insertAfter") {
            var newModification = {};
            newModification.type = modification.type;
            newModification.token = modification.token;
            // if (modification.targetTokenRuleIndice != undefined) {
            newModification.targetTokenIndice = this.GetTargetTokenIndice(result, modification, tokenRule);
            if (newModification.targetTokenIndice == -1) {
                debugger;
                return 0;
            }
            // }
            // else {
            //console.error("targetTokenRuleIndice is not defined");
            //debugger;
            // }
            var suggestionIndice = 0;
            if (modification.suggestionIndice != undefined) {
                suggestionIndice = modification.suggestionIndice;
            }
            functionAdd(result, suggestionIndice, newModification);
            return 1;
        }
        if (!tokenRule) {
            console.error("tokenRule is NULL");
            debugger;
            return 0;
        }
        for (var ti = 0; ti < tokenRule.tokenIndices.length; ti++) {

            var newModification = {};
            //identify tokenIndice
            var tokenIndice = tokenRule.tokenIndices[ti];

            if (modification.type == "replaceAttValue") {
                newModification = Object.assign({}, modification, {});
                newModification.tokenIndice = tokenIndice;
            }
            else if (modification.type == "insertTextAfter") {
                newModification.type = "replaceAttValue";
                newModification.tokenIndice = tokenIndice;
                var token = sentence.tokens[tokenIndice];
                if (!token) {
                    debugger;
                    return 0;
                    // continue;
                }
                if (modification.att) {
                    newModification.att = modification.att;
                }
                else {
                    debugger;
                    continue;
                }
                if (!token[modification.att]) {
                    debugger;
                    return 0;
                    // continue;
                }
                newModification.text = token[modification.att] + modification.text;
            }
            else if (modification.type == "replaceText") {
                newModification.type = "replaceAttValue";
                newModification.tokenIndice = tokenIndice;
                var token = sentence.tokens[tokenIndice];
                if (!token) {
                    debugger;
                    return 0;
                    // continue;
                }
                if (modification.att) {
                    newModification.att = modification.att;
                }
                else {
                    debugger;
                    continue;
                }
                if (!token[modification.att]) {
                    debugger;
                    return 0;
                    // continue;
                }
                var regExp = new RegExp(modification.regExp);
                newModification.text = token[modification.att].replace(regExp, modification.text);
            }
            else if (modification.type == "removeTextAfter") {
                newModification.type = "replaceAttValue";
                newModification.tokenIndice = tokenIndice;
                var token = sentence.tokens[tokenIndice];
                if (!token) {
                    debugger;
                    return 0;
                    // continue;
                }
                if (modification.att) {
                    newModification.att = modification.att;
                }
                else {
                    debugger;
                    return 0;
                    // continue;
                }
                var text = token[modification.att];
                if (!text) {
                    debugger;
                    return 0;
                    // continue;
                }
                if (text.endsWith(modification.text)) {
                    newModification.text = text.substring(0, text.length - modification.text.length);
                }
                else if (modification.length && text.length > modification.length) {
                    newModification.text = text.substring(0, text.length - modification.length);
                }
                else {
                    debugger;
                    return 0;
                    // continue;
                }
            }
            else if (modification.type == "replaceByAttValue") {
                newModification.type = "replaceAttValue";
                newModification.tokenIndice = tokenIndice;
                var token = sentence.tokens[tokenIndice];
                if (!token) {
                    debugger;
                    return 0;
                    // continue;
                }
                if (modification.att) {
                    newModification.att = modification.att;
                }
                else {
                    debugger;
                    return 0;
                    // continue;
                }
                if (modification.targetAtt) {
                    if (modification.key && modification.dictionary) {
                        var key = token[modification.key];
                        if (key) {
                            key = key.toLowerCase()
                            var dictionary = ruleManager.dictionaries[modification.dictionary];
                            if (dictionary) {
                                const data = dictionary[key];
                                if (!data)
                                {
                                    debugger;
                                    console.error("att is not defined in dictionary key= " + key);
                                    return 0;
                                }
                                else if (!data[modification.targetAtt])
                                {
                                    console.error("targetAtt is not defined in dictionary key= " + key + " targetAtt= " + modification.targetAtt);
                                    debugger;
                                    return 0;
                                    // continue;
                                }
                                newModification.text = data[modification.targetAtt];
                            }
                            else {
                                dictionary = ruleManager.objectDictionaries[modification.dictionary];
                                if (dictionary) {
                                    var value = dictionary.GetFirstValue(key,modification.targetAtt);
                                    if (value)
                                    {
                                        newModification.text = value;
                                    }
                                    else {
                                        debugger;
                                        return 0;
                                        // continue;
                                    }
                                }
                                else {
                                    debugger;
                                    return 0;
                                    // continue;
                                }
                            }
                        }
                        else {
                            debugger;
                            return 0;
                            // continue;
                        }
                    }
                    else {
                        if (token[modification.targetAtt]) {
                            newModification.text = token[modification.targetAtt];
                        }
                        else {
                            debugger;
                            return 0;
                            // continue;
                        }
                    }
                }
                else {
                    debugger;
                }
            }
            else if (modification.type == "moveBefore" ||
                modification.type == "moveAfter") {
                newModification.type = modification.type;
                if (tokenRule.tokenIndices.length == 1) {
                    newModification.tokenIndice = tokenIndice;
                }
                else {
                    newModification.tokenIndices = tokenRule.tokenIndices;
                }
            }
            else if (modification.type == "delete") {
                newModification.type = modification.type;
                newModification.tokenIndice = tokenIndice;
            }
            else {
                if (result.rule && result.rule.title) {
                    console.error("Error on rule: " + result.rule.title);
                }
                console.error("modification type not managed type: " + modification.type);
                debugger;
                return 0;
                // continue;
            }
            // compute targetTokenIndice if necessary
            if (modification.targetTokenRuleIndice != undefined) {
                newModification.targetTokenIndice = this.GetTargetTokenIndice(result, modification);
                if (newModification.targetTokenIndice == -1) {
                    // continue;
                    return 0;
                }
                if (newModification.targetTokenIndice == newModification.tokenIndice) {
                    console.error("targetTokenIndice and tokenIndice cant be equal");
                    debugger;
                    return 0;
                }
            }
            var suggestionIndice = 0;
            if (modification.suggestionIndice != undefined) {
                suggestionIndice = modification.suggestionIndice;
            }
            functionAdd(result, suggestionIndice, newModification);
            if (modification.type == "moveBefore" ||
                modification.type == "moveAfter") {
                break;
            }
        }
        return 1;
    }
    AddModifications(ruleManager, functionAdd, sentence, result, globalModifications) {
        if (globalModifications) {
            for (var cri = 0; cri < globalModifications.length; cri++) {
                var modification = globalModifications[cri];
                var tokenRule = null;

                if (modification.tokenRuleIndice >= 0 &&
                    modification.tokenRuleIndice < result.tokenRules.length) {
                    tokenRule = result.tokenRules[modification.tokenRuleIndice];
                }
                else if (modification.type != "insertAfter" &&
                    modification.type != "insert") {
                    debugger;
                    return 0;
                }
                if (!this._AddModifications(ruleManager, functionAdd, sentence, result, tokenRule, modification)) {
                    debugger;
                    return 0;
                }
            }
        }
        for (var tri = 0; tri < result.tokenRules.length; tri++) {
            var tokenRule = result.tokenRules[tri];
            if (tokenRule.modifications) {
                for (var ci = 0; ci < tokenRule.modifications.length; ci++) {
                    var targetTokenRule = tokenRule;
                    var modification = tokenRule.modifications[ci];
                    if (modification.tokenRuleIndice != undefined) {
                        if (modification.tokenRuleIndice >= 0 &&
                            modification.tokenRuleIndice < result.tokenRules.length) {
                            targetTokenRule = result.tokenRules[modification.tokenRuleIndice];
                        }
                        else {
                            debugger;
                        }
                    }
                    else if (modification.phrase && modification.tokenTag) {
                        var token = sentence.tokens[tokenRule.tokenIndices[0]];
                        if (token[modification.phrase] &&
                            token[modification.phrase].tokenTags &&
                            token[modification.phrase].tokenTags[modification.tokenTag]) {
                            targetTokenRule = {
                                tokenIndices: token[modification.phrase].tokenTags[modification.tokenTag]
                            };
                        }
                        else {
                            continue;
                        }
                    }
                    if (!this._AddModifications(ruleManager, functionAdd, sentence, result, targetTokenRule, modification)) {
                        return 0;
                    }
                }
            }
        }
        return 1;
    }
    _ApplyOverloadModifications(ruleManager, modifications, object) {
        for (var att in modifications) {
            if (att != "token") {
                var overloadObj = Overload.Instanciate(att, modifications[att]);
                overloadObj.overload(ruleManager, object);
            }
            else {
                if (!object.token) {
                    object.token = {};
                }
                var subModifications = modifications[att];
                this._ApplyOverloadModifications(ruleManager, subModifications, object.token);
            }
        }
    }
    ApplyOverloadModifications(ruleManager, overloads, object) {
        if (overloads.modifications)
        {
            this._ApplyOverloadModifications(ruleManager, overloads.modifications, object);
        }
        if (overloads.deletions)
        {
            for (var i = 0; i < overloads.deletions.length; i++) {
                Overload.DeleteAtt(object, overloads.deletions[i]);
            }
        }
    }
    ApplyOverload(ruleManager, overload, sentence, result, globalModifications, tokenIndices) {
        var key = overload.object;
        if (!key) {
            debugger;
            return;
        }

        if (overload.object == "learningCard") {
            if (result.learningCard) {
                this.ApplyOverloadModifications(ruleManager, overload, result.learningCard);
            }
            else {
                debugger;
            }
        }
        else if (overload.object == "phrase") {
            if (result.phrase) {
                if (overload.type == "att") {
                    this.ApplyOverloadModifications(ruleManager, overload, result.phrase);
                }
                else if (overload.type == "tokenTag") {
                    if (!result.phrase.tokenTags) {
                        result.phrase.tokenTags = {};
                    }
                    if (tokenIndices &&
                        tokenIndices.length) {
                        result.phrase.tokenTags[overload.tag] = tokenIndices;
                    }
                    else {
                        debugger;
                    }
                }
                else {
                    debugger;
                }
                // var overload = overloads[key];
                // for (var att in overload) {
                //     if (att == "tokenTag")
                //     {
                //         if (!result.phrase.tokenTags)
                //         {
                //             result.phrase.tokenTags = {};
                //         }
                //         result.phrase.tokenTags[overload[att]] = true;
                //     }
                //     else{
                //         result.phrase[att] = overload[att];
                //     }
                // }
            }
            else {
                debugger;
            }
        }
        else if (overload.object == "token") {
            var lTokenIndices = [];
            if (overload.tokenRuleIndice != undefined) {
                if (overload.tokenRuleIndice >= 0 && overload.tokenRuleIndice < result.tokenRules.length) {
                    lTokenIndices = result.tokenRules[overload.tokenRuleIndice].tokenIndices;
                }
                else {
                    debugger;
                    return;
                }
            }
            else if (tokenIndices) {
                lTokenIndices = tokenIndices;
            }
            else {
                debugger;
                return;
            }
            for (var tii = 0; tii < lTokenIndices.length; tii++) {
                var token = sentence.tokens[lTokenIndices[tii]];
                if (token) {
                    this.ApplyOverloadModifications(ruleManager, overload, token);
                }
                else {
                    debugger;
                }
            }
        }
        else if (overload.object == "correction") {
            var correctionIndice = overload.correctionIndice;
            if (globalModifications &&
                correctionIndice >= 0 &&
                correctionIndice < globalModifications.length) {
                var modification = globalModifications[correctionIndice];
                this.ApplyOverloadModifications(ruleManager, overload, modification);

                // var overload = overloads[key];
                // for (var att in overload) {
                //     if (att != "token") {
                //         modification[att] = overload[att];
                //     }
                //     else {
                //         if (!modification.token) {
                //             modification.token = {};
                //         }
                //         var overloadToken = overload[att];
                //         for (var att1 in overloadToken) {
                //             var overloadObj = Overload.Instanciate(att1, overloadToken[att1]);
                //             overloadObj.overload(ruleManager, modification.token);
                //         }
                //     }
                // }
            }
            else {
                debugger;
            }
        }
        else {
            debugger;
        }
    }
    ApplyOverloads(ruleManager, overloads, endOverloads, sentence, result, globalModifications) {

        // for (var key in overloads) {
        for (var i = 0; i < overloads.length; i++) {
            var overload = overloads[i];
            this.ApplyOverload(ruleManager, overload, sentence, result, globalModifications, null);
        }
        for (var tri = 0; tri < result.tokenRules.length; tri++) {
            var tokenRule = result.tokenRules[tri];
            if (tokenRule.overloads) {
                for (var oi = 0; oi < tokenRule.overloads.length; oi++) {
                    var overload = tokenRule.overloads[oi];
                    // 
                    if (overload.tokenRuleIndice != undefined) {
                        if (overload.tokenRuleIndice >= 0 &&
                            overload.tokenRuleIndice < result.tokenRules.length) {
                            tokenRule = result.tokenRules[overload.tokenRuleIndice];
                        }
                        else {
                            debugger;
                        }
                    }
                    this.ApplyOverload(ruleManager, overload, sentence, result, globalModifications, tokenRule.tokenIndices);
                }
            }
        }
        if (result.overloads)
        {
            for (var roi= 0; roi < result.overloads.length; roi++)
            {
                var overload =  result.overloads[roi];
                this.ApplyOverload(ruleManager, overload, sentence, result, globalModifications, overload.tokenIndices);
            }
        }
        for (var i = 0; i < endOverloads.length; i++) {
            var overload = endOverloads[i];
            this.ApplyOverload(ruleManager, overload, sentence, result, globalModifications, null);
        }
    }
    SetPhrase(sentence, result) {
        if (result.phrase) {
            var firstTokenIndice = -1;
            for (var tri=0; tri < result.tokenRules.length; tri++)
            {
                var tokenRule = result.tokenRules[tri];
                if (tokenRule.tokenIndices.length)
                {
                    firstTokenIndice = tokenRule.tokenIndices[0];
                    break;
                }
            }
            if (firstTokenIndice >=0 && firstTokenIndice < sentence.tokens.length) {
                var end = firstTokenIndice + result.phrase.tokenCount;
                if (end <= sentence.tokens.length)
                {
                    var applyPhrase = true;
                    var token = sentence.tokens[firstTokenIndice];
                    if (token[result.phrase.id] )
                    {
                        console.error("Phrase already applied : "+ result.phrase.id);
                        if (token[result.phrase.id].tokenCount >= result.phrase)
                        {
                            applyPhrase = false;
                        }
                        // debugger;
                    }
                    if (applyPhrase)
                    {
                        token[result.phrase.id] = result.phrase;
                        // var start = result.tokenIndices[0];
                        for (var i = firstTokenIndice; i < end; i++) {
                            var token = sentence.tokens[i];
                            if (!token)
                            {
                                debugger;
                            }
                            if (!token.partOfPhrases) {
                                token.partOfPhrases = {};
                            }
                            token.partOfPhrases[result.phrase.id] = 1;
                        }
                    }
                }
                else {
                    debugger;
                }
            }
            else {
                debugger;
            }
        }
    }
    MatchForStartTokenIndice (params, tokenRules)
    {
        var status = 0;
        var matchedCount = 0;
        var tri = 0;
        while (tri < tokenRules.length)
        {
            params.tokenRuleIndice = tri;
            var tokenRule = tokenRules[tri];
            var tokenCount = tokenRule.match(params);
            if (tokenCount)
            {
                status += tokenCount;
                matchedCount++;
                if (tokenRule.isMaxCountReached(matchedCount))
                {
                    matchedCount=0;
                    tri++;
                }
                if (params.tokenIndice >= params.tokenEnd)
                {
                    break;
                }
            }
            else{
                if (!tokenRule.isMinCountReached(matchedCount))
                {
                    matchedCount = 0;
                    if (tri==0 && tokenRules[tri].matchIfNoToken) 
                    {
                        tri++;
                    }
                    else
                    {
                        tri = tokenRules.length;
                        status = 0;
                        break;
                    }
                }
                else{
                    matchedCount = 0;
                    tri++;
                }
            }
        }
        // remaining token rules
        for (; tri < tokenRules.length; tri++)
        {
            if (!tokenRules[tri].isMinCountReached(matchedCount) && !tokenRules[tri].matchIfNoToken)
            {
                status = 0;
                break;
            }
            matchedCount = 0; 
        }
        return status;
    }
    GetParamObject(sentence, tokenRules, startTokenIndice, tokenEnd)
    {
        var result = {
            tokenRules: [],
            tokenIndices: [],
            conflictTokenIndices: [],
            mainTokenIndices: []
        };
        for (var tri=0; tri < tokenRules.length; tri++)
        {
            result.tokenRules.push({
                tokenIndices: [],
                modifications: [],
                overloads: []
            });
        }
        var params = {
            sentence: sentence,
            tokenIndice: startTokenIndice,
            tokenEnd: tokenEnd,
            result: result
        };
        return params;
    }
    match(ruleManager, sentence, ruleType, results) {

        if (sentence.tokens.length == 0) {
            return;
        }
        let startEnd = sentence.tokens.length;
        let tokenEnd = sentence.tokens.length;
        var endTokenRuleResult = {
            overloads: [],
            modifications: []
        }
        let endResult = null;
        if (this.endTokenRule) {
            var params = this.GetParamObject(sentence, [this.endTokenRule], startTokenIndice, tokenEnd);
            var token = sentence.tokens[sentence.tokens.length - 1];
            var status = this.endTokenRule.rootCondition.match(token, params, endTokenRuleResult);
            if (status < this.endTokenRule.minCount ||
                status > this.endTokenRule.maxCount) {
                return;
            }
            startEnd--;
        }
        else if (this.endTokenRules && this.endTokenRules.length) {
            let found = false;
            // const endEnd = sentence.tokens.length - this.endTokenRules.length - 1;
            // for (var startTokenIndice = endEnd; startTokenIndice >= 0; startTokenIndice--) {
            for (var startTokenIndice = 0; startTokenIndice <sentence.tokens.length; startTokenIndice++) {
                var params = this.GetParamObject(sentence, this.endTokenRules, startTokenIndice, tokenEnd);
                // var result = params.result;
                var status = this.MatchForStartTokenIndice(params, this.endTokenRules);
                if (status) {
                    // debugger;
                    if (startTokenIndice + status === sentence.tokens.length) {
                        found = true;
                        tokenEnd -= status;
                        startEnd -= status;
                        endResult = params.result;
                        break;
                    }
                }
            }
            if (!found){
                return;
            }
        }
        if (startEnd > 1 && this.control == "start") {
            startEnd = 1;
        }

        for (var startTokenIndice = 0; startTokenIndice < startEnd; startTokenIndice++) {

            var params = this.GetParamObject(sentence, this.tokenRules, startTokenIndice, tokenEnd);
            var result = params.result;
            var status = this.MatchForStartTokenIndice(params, this.tokenRules);
            if (status) {
                if (this.exceptions && this.exceptions.length) {
                    if (result.mainTokenIndices.length) {
                        for (var ei = 0; ei < this.exceptions.length; ei++) {
                            var exception = this.exceptions[ei];
                            var exceptionResults = [];
                            exception.match(ruleManager, sentence, "exceptions", exceptionResults);
                            for (var eri = 0; eri < exceptionResults.length; eri++) {
                                var exceptionResult = exceptionResults[eri];
                                for (var mti = 0; mti < result.mainTokenIndices.length; mti++) {
                                    if (exceptionResult.mainTokenIndices.indexOf(result.mainTokenIndices[mti]) != -1) {
                                        status = 0;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    else {
                        status = 0;
                        console.error("You have forgetten to add mainToken");
                        debugger;
                    }
                }
                if (status) {
                    if (this.rulesOnResults && this.rulesOnResults.length) {
                        var localSentence = {
                            tokens: []
                        };
                        for (var ti = 0; ti < result.tokenIndices.length; ti++) {
                            localSentence.tokens.push(sentence.tokens[result.tokenIndices[ti]]);
                        }
                        for (var rri = 0; rri < this.rulesOnResults.length; rri++) {
                            var rulesOnResult = this.rulesOnResults[rri];
                            var rulesOnResultResults = [];
                            rulesOnResult.match(ruleManager, localSentence, "ruleOnResults", rulesOnResultResults);
                            for (var rrri = 0; rrri < rulesOnResultResults.length; rrri++) {
                                if (rulesOnResultResults[rrri].tokenIndices.length) {
                                    rri = this.rulesOnResults.length;
                                    status = 0;
                                    break;
                                }
                            }
                        }
                    }
                }
                if (status && this.function) {
                    if (ruleManager.functions[this.function]) {
                        status = ruleManager.functions[this.function](ruleManager, sentence, result);
                    }
                    else {
                        status = 0;
                        debugger;
                    }
                }

                if (status && this.priorityGroup) {
                    result.priorityGroup = this.priorityGroup;
                    // var key = this.priorityGroup.name;
                    // if (result.mainTokenIndices.length) {

                    //     if (!priorityGroups[key]) {
                    //         priorityGroups[key] = {};
                    //     }
                    //     var otherRuleType = ruleType == "lessons" ? "errors" : "lessons";
                    //     var removedResults = [];
                    //     for (var mti = 0; mti < result.mainTokenIndices.length; mti++) {
                    //         var ti = result.mainTokenIndices[mti];
                    //         var tiPriorityGroup = priorityGroups[key][ti];
                    //         if (!tiPriorityGroup) {
                    //             priorityGroups[key][ti] = {
                    //                 priority: this.priorityGroup.priority
                    //             };
                    //             priorityGroups[key][ti][ruleType] = [result];
                    //             priorityGroups[key][ti][otherRuleType] = [];
                    //         }
                    //         else {
                    //             if (tiPriorityGroup.priority > this.priorityGroup.priority) {
                    //                 for (var tpgri = 0; tpgri < tiPriorityGroup[ruleType].length; tpgri++) {
                    //                     var resultToRemove = tiPriorityGroup[ruleType][tpgri];
                    //                     if (removedResults.indexOf(resultToRemove) == -1) {
                    //                         var indice = results.indexOf(resultToRemove);
                    //                         if (indice != -1) {
                    //                             results.splice(indice, 1);
                    //                             removedResults.push(resultToRemove);
                    //                         }
                    //                         else {
                    //                             debugger;
                    //                         }
                    //                     }
                    //                 }
                    //                 if (otherResults) {
                    //                     for (var tpgri = 0; tpgri < tiPriorityGroup[otherRuleType].length; tpgri++) {
                    //                         var resultToRemove = tiPriorityGroup[otherRuleType][tpgri];
                    //                         if (removedResults.indexOf(resultToRemove) == -1) {
                    //                             var indice = otherResults.indexOf(resultToRemove);
                    //                             if (indice != -1) {
                    //                                 // console.log(indice);
                    //                                 otherResults.splice(indice, 1);
                    //                                 removedResults.push(resultToRemove);
                    //                             }
                    //                             else {
                    //                                 console.error(indice);
                    //                                 debugger;
                    //                             }
                    //                         }
                    //                     }
                    //                 }
                    //                 tiPriorityGroup.priority = this.priorityGroup.priority;
                    //                 tiPriorityGroup[ruleType] = [result];
                    //                 tiPriorityGroup[otherRuleType] = [];
                    //             }
                    //             else if (tiPriorityGroup.priority == this.priorityGroup.priority) {
                    //                 tiPriorityGroup[ruleType].push(result);
                    //             }
                    //             else {
                    //                 status = 0;
                    //             }
                    //         }
                    //     }
                    // }
                    // else {
                    //     console.error("You have forgetten to add mainToken");
                    //     debugger;
                    // }
                }
                if (status) {
                    result.rule = {
                        title: this.title
                    }
                    if (this.id) {
                        result.rule.id = this.id;
                    }
                    if (this.type) {
                        result.rule.type = this.type;
                    }
                    else {
                        result.rule.type = "lesson";
                    }
                    if (this.category) {
                        result.rule.category = this.category;
                    }
                    if (this.learningCard) {
                        result.learningCard = _.cloneDeep(this.learningCard);
                    }
                    if (this.phrase) {
                        result.phrase = Object.assign({}, this.phrase, {});
                        result.phrase.tokenCount = status;
                    }
                    var globalModifications = [];
                    if (this.modifications) {
                        //globalModifications = [];
                        for (var ci = 0; ci < this.modifications.length; ci++) {
                            var duplicate =  _.cloneDeep(this.modifications[ci]);
                            if (duplicate) {
                                globalModifications.push(duplicate);
                            }
                            //globalModifications.push(Object.assign({}, this.modifications[ci], {}));
                        }
                    }
                    var overloads = [];
                    if (this.overloads) {
                        overloads = _.cloneDeep(this.overloads);
                    }
                    this.ApplyOverloads(ruleManager, overloads, endTokenRuleResult.overloads, sentence, result, globalModifications);


                    if (ruleType == "errors" ||
                        ruleType == "lessons") {
                        if (ruleType == "errors") {
                            status = this.AddModifications(ruleManager, ruleManager.AddCorrection, sentence, result, globalModifications);
                        }
                        else if (ruleType == "lessons") {
                            status = this.AddModifications(ruleManager, ruleManager.AddError, sentence, result, globalModifications);
                        }

                        if (status) {
                            if (!results) {
                                debugger;
                            }
                            else {
                                if (endResult){
                                    // debugger;
                                    for (const value of endResult.conflictTokenIndices) {
                                        result.conflictTokenIndices.push(value)
                                    }
                                    for (const value of endResult.mainTokenIndices) {
                                        result.mainTokenIndices.push(value)
                                    }
                                    for (const value of endResult.tokenIndices) {
                                        result.tokenIndices.push(value)
                                    }
                                    for (const value of endResult.tokenRules) {
                                        result.tokenRules.push(value)
                                    }
                                    if (endResult.valueKeys) {
                                        for (const key in endResult.valueKeys) {
                                            if (!result.valueKeys) result.valueKeys = {}
                                            result.valueKeys[key] = endResult.valueKeys[key];
                                        }
                                    }
                                }
                                this.SetPhrase(sentence, result);
                                results.push(result);
                            }
                        }
                        else {
                            console.error("Error id= " + result.rule.id);
                            debugger;
                        }
                    }
                    else if (ruleType == "exceptions" ||
                        ruleType == "ruleOnResults") {
                        if (status) {
                            this.SetPhrase(sentence, result);
                            results.push(result);
                        }
                    }
                    else {
                        this.SetPhrase(sentence, result);
                    }
                    if (this.mode == 1)
                    {
                        startTokenIndice = params.tokenIndice - 1;
                    }
                }
            }
        }
        return results;
    }
}
