"use strict";
const ModificationToken = require("./ModificationToken");
module.exports = class ModificationTokenServices {
    constructor(ruleType) {
        this.Initialize();
        this.ruleType = "errors";
        this.action = "corrections";
        if (ruleType) {
            this.ruleType = ruleType;
        }
        if (this.ruleType == "lessons") {
            this.action = "errors";
        }
        //lessons.errors.suggestions[i].modifications
        //errors.corrections.suggestions[i].corrections/modifications
    }

    Initialize() {
        this.iterationCount = 0;
        this.analysisSet = [];
        //
        this.InitializeAnalysisResults();
    }
    InitializeAnalysisResults() {
        this.sentenceAnalysisResults = [];
        this.sentenceCorrectionTokens = [];
        this.validatedCorrections = {};
        this.sentenceIndice = 0;
        this.identRuleIndice = -1;
    }
    GetSet(sentenceAnalysisResult) {
        return sentenceAnalysisResult[this.ruleType];
    }
    NextSuggestions() {
        let result = {
            restartAnalysis: false
        };
        var sentenceValidatedCorrections = this.validatedCorrections[this.sentenceIndice];
        // if manual correction stop to re-analyse text
        if (sentenceValidatedCorrections && sentenceValidatedCorrections.length) {
            if (sentenceValidatedCorrections[sentenceValidatedCorrections.length - 1].manualCorrection) {
                result.manualCorrection = true;
                result.restartAnalysis = true;
                // result.identifiedRule = 
                return result;
            }
        }
        // 
        var identifiedRule = null;
        this.identRuleIndice++;

        while (!identifiedRule && this.sentenceIndice < this.sentenceAnalysisResults.length) {
            var sentenceAnalysisResult = this.sentenceAnalysisResults[this.sentenceIndice];
            var identifiedRules = this.GetSet(sentenceAnalysisResult);
            if (!identifiedRules || this.identRuleIndice >= identifiedRules.length) {
                this.identRuleIndice = 0;
                this.sentenceIndice++;
                if (this.sentenceIndice >= this.sentenceAnalysisResults.length) {
                    break;
                }
            }
            else {
                identifiedRule = identifiedRules[this.identRuleIndice];
                result.restartAnalysis = false;
                // if (identifiedRule && identifiedRule[this.action]) {
                if (identifiedRule) {
                    if (identifiedRule.conflicts) {
                        var sentenceValidatedCorrections = this.validatedCorrections[this.sentenceIndice];
                        if (sentenceValidatedCorrections) {
                            for (var svci = 0; svci < sentenceValidatedCorrections.length; svci++) {
                                if (identifiedRule.conflicts.indexOf(sentenceValidatedCorrections[svci].identRuleIndice) != -1) {
                                    identifiedRule = null;
                                    this.identRuleIndice++;
                                    // result.NextSuggestionsInConflict = true;
                                    result.restartAnalysis = true;
                                    return result;
                                }
                            }
                        }
                    }
                }
                else {
                    identifiedRule = null;
                    this.identRuleIndice++;
                }
            }
        }
        result.identifiedRule = identifiedRule;
        return result;
    }
    GetDicoModifiedTokenIndices(sentenceAnalysisResult) {
        var modifiedTokenIndices = {};
        var errors = this.GetSet(sentenceAnalysisResult);
        if (errors) {
            for (var ei = 0; ei < errors.length; ei++) {
                var identifiedRule = errors[ei];
                var actions = identifiedRule[this.action];
                if (actions &&
                    actions.suggestions &&
                    actions.suggestions.length) {
                    var modifications = actions.suggestions[0].corrections ||
                        actions.suggestions[0].modifications;
                    for (var ci = 0; ci < modifications.length; ci++) {
                        var modification = modifications[ci];
                        if (modification.tokenIndice != undefined) {
                            modifiedTokenIndices[modification.tokenIndice] = true;
                        }
                        if (modification.tokenIndices != undefined) {
                            for (var ti = 0; ti < modification.tokenIndices.length; ti++) {
                                modifiedTokenIndices[modification.tokenIndices[ti]] = true;
                            }
                        }
                    }
                }
            }
        }
        return modifiedTokenIndices;
    }
    CreateSentenceCorrectionTokens(sentenceAnalysisResult, prefixId) {
        var modifiedTokenIndices = this.GetDicoModifiedTokenIndices(sentenceAnalysisResult);

        var correctionTokens = {};
        var prevCT = null;
        var sentence = sentenceAnalysisResult.sentence;
        for (var ti = 0; ti < sentence.tokens.length; ti++) {
            var token = sentence.tokens[ti];
            var containError = modifiedTokenIndices[ti];
            var correctionToken = new ModificationToken(token, ti, containError);
            if (prefixId) {
                correctionToken.SetId(prefixId + "-" + ti);
            }
            if (prevCT) {
                correctionToken.prev = prevCT;
                prevCT.next = correctionToken;
            }
            correctionTokens[ti] = correctionToken;
            prevCT = correctionToken;
        }
        return correctionTokens;
    }

    CreateSentenceCorrectionTokens1(asi, sentenceIndice, prevCorrectionTokens) {
        if (asi < 1 || asi >= this.analysisSet.length) {
            debugger;
            return null;
        }
        if (!prevCorrectionTokens) {
            debugger;
            return null;
        }

        var sentenceAnalysisResult = this.analysisSet[asi].sentenceAnalysisResults[sentenceIndice];
        var modifiedTokenIndices = this.GetDicoModifiedTokenIndices(sentenceAnalysisResult);

        var ct = this.GetFirstCorrectionToken(prevCorrectionTokens);

        var correctionTokens = {};
        var sentence = sentenceAnalysisResult.sentence;
        var usedCts = [];
        for (var ti = 0; ti < sentence.tokens.length; ti++) {
            var token = sentence.tokens[ti];
            if (!ct || ct.GetModifiedWord() != token.word) {
                debugger;
                return null;
            }
            if (ct.id) {
                token.ctId = ct.id;
            }
            else {
                debugger;
            }
            var containError = modifiedTokenIndices[ti];
            if (containError) {
                ct.containError = true;
            }
            correctionTokens[ti] = ct;
            ct = ct.NextActive(usedCts);
        }
        return correctionTokens;
    }
    CreateSentenceCorrectionTokens2(asi, sentenceIndice, prevCorrectionTokens) {
        if (asi < 1 || asi >= this.analysisSet.length) {
            debugger;
            return null;
        }
        if (!prevCorrectionTokens) {
            debugger;
            return null;
        }
        var sentenceAnalysisResult = this.analysisSet[asi].sentenceAnalysisResults[sentenceIndice];
        var modifiedTokenIndices = this.GetDicoModifiedTokenIndices(sentenceAnalysisResult);

        var ct = this.GetFirstCorrectionToken(prevCorrectionTokens);
        var dicoCts = {};
        var usedCts = [];
        while (ct) {
            usedCts.push(ct);
            if (ct.id) {
                dicoCts[ct.id] = ct;
            }
            else {
                debugger;
            }
            ct = ct.Next(usedCts);
        }

        var correctionTokens = {};
        var sentence = sentenceAnalysisResult.sentence;
        for (var ti = 0; ti < sentence.tokens.length; ti++) {
            var token = sentence.tokens[ti];
            if (!token.ctId) {
                debugger;
                return null;
            }
            var ct = dicoCts[token.ctId];
            var containError = modifiedTokenIndices[ti];
            if (!ct) {
                if (token.ctId[0] == "0") {
                    debugger;
                    return null;
                }
                else {
                    ct = new ModificationToken(token, ti, containError);
                    ct.fake = true;
                }
            }
            else {
                if (containError) {
                    ct.containError = true;
                }
            }
            correctionTokens[ti] = ct;
        }
        return correctionTokens;
    }

    ApplyTokenCorrection(correctionTokens, modification, options) {
        if (correctionTokens) {
            if (modification.type == "insert" ||
                modification.type == "insertAfter") {
                if (modification.targetTokenIndice != undefined) {
                    var correctionToken = correctionTokens[modification.targetTokenIndice];
                    if (correctionToken) {
                        if (!correctionToken.fake) {
                            if (modification.type == "insert") {
                                correctionToken.InsertNewToken(modification.token, options);
                            }
                            else {
                                correctionToken.InsertNewAfterToken(modification.token, options);
                            }
                        }
                        else {
                            console.error("correctionToken fake found");
                            debugger;
                        }
                    }
                    else {
                        debugger;
                    }
                }
            }
            else {
                var correctionToken = null;
                if (modification.tokenIndice != undefined) {
                    correctionToken = correctionTokens[modification.tokenIndice];
                }
                else if (modification.tokenIndices != undefined &&
                    modification.tokenIndices.length) {
                    correctionToken = correctionTokens[modification.tokenIndices[0]];
                }
                if (correctionToken) {
                    if (!correctionToken.fake) {
                        if (modification.type == "delete") {
                            correctionToken.SetDelete(options);
                        }
                        else if (modification.type == "replaceAttValue") {

                            if (modification.tokenIndices != undefined) {
                                var replace = true;
                                for (var tii = 1; tii < modification.tokenIndices.length; tii++) {
                                    var ct = correctionTokens[modification.tokenIndices[tii]];
                                    if (!ct) {
                                        debugger;
                                        replace = false;
                                        break;
                                    }
                                    else if (ct.fake) {
                                        replace = false;
                                        console.log("correctionToken fake found");
                                        break;
                                    }
                                }
                                if (replace) {
                                    var correctionTokenEnd = correctionTokens[modification.tokenIndices[modification.tokenIndices.length - 1]];
                                    correctionToken.ReplaceAttValue(modification, correctionTokenEnd, options);
                                }
                            }
                            else {
                                correctionToken.ReplaceAttValue(modification, undefined, options);
                            }
                        }
                        else if (modification.targetTokenIndice != undefined) {
                            var targetCorrectionToken = correctionTokens[modification.targetTokenIndice];
                            if (targetCorrectionToken) {
                                if (!targetCorrectionToken.fake) {
                                    var correctionTokenEnd = correctionToken;
                                    var move = true;
                                    if (modification.tokenIndices != undefined) {
                                        for (var tii = 1; tii < modification.tokenIndices.length; tii++) {
                                            var ct = correctionTokens[modification.tokenIndices[tii]];
                                            if (!ct) {
                                                debugger;
                                                move = false;
                                                break;
                                            }
                                            else if (ct.fake) {
                                                move = false;
                                                console.log("correctionToken fake found");
                                                break;
                                            }
                                        }
                                        correctionTokenEnd = correctionTokens[modification.tokenIndices[modification.tokenIndices.length - 1]];
                                    }
                                    //moveBefore/moveAfter
                                    if (move) {
                                        if (modification.type == "moveBefore") {
                                            targetCorrectionToken.MoveBefore(correctionToken, correctionTokenEnd, options);
                                        }
                                        else if (modification.type == "moveAfter") {
                                            targetCorrectionToken.MoveAfter(correctionToken, correctionTokenEnd, options);
                                        }
                                        else {
                                            debugger;
                                        }
                                    }
                                }
                                else {
                                    console.error("correctionToken fake found");
                                    debugger;
                                }
                            }
                            else {
                                debugger;
                            }
                        }
                        else {
                            debugger;
                        }
                    }
                    else {
                        console.log("correctionToken fake found");
                    }
                }
                else {
                    debugger;
                }
            }
        }
    }
    GetCorrectedText() {
        this.CheckSpaceBefore();
        this.CheckCases();
        let text = "";
        for (var si = 0; si < this.sentenceCorrectionTokens.length; si++) {
            let validatedCorrections = this.validatedCorrections[si];
            if (validatedCorrections && validatedCorrections.length && validatedCorrections[validatedCorrections.length - 1].manualCorrection) {
                text += validatedCorrections[validatedCorrections.length - 1].manualCorrection;
            }
            else {
                let correctionTokens = this.sentenceCorrectionTokens[si];
                text += this.GetCorrectedSentence(correctionTokens);
            }
        }
        return text;
    }
    GetCorrectedTextBySentences() {
        var results = {
            sentences: []
        }
        this.CheckSpaceBefore();
        this.CheckCases();
        // var text = "";
        for (var si = 0; si < this.sentenceCorrectionTokens.length; si++) {
            var sentenceAnalysisResult = this.sentenceAnalysisResults[si];
            var correctionTokens = this.sentenceCorrectionTokens[si];
            var sentence = this.GetCorrectedSentence(correctionTokens);
            var result = {
                text: sentence
            };
            if (sentenceAnalysisResult.context) {
                result.context = sentenceAnalysisResult.context;
            }
            results.sentences.push(result);
        }
        return results;
    }
    GetFirstCorrectionToken(correctionTokens) {
        var ct = null;
        for (var key in correctionTokens) {
            var correctionToken = correctionTokens[key];
            if (correctionToken.status) {
                ct = correctionToken;
                break;
            }
        }
        if (!ct) {
            return null;
        }
        var currentCt = ct;
        while (currentCt.prev) {
            currentCt = currentCt.prev;
            if (currentCt.status) {
                ct = currentCt;
            }
        }
        return ct;
    }
    GetCorrectedSentence(correctionTokens) {
        var text = "";
        if (correctionTokens) {
            var usedCts = [];
            var ct = this.GetFirstCorrectionToken(correctionTokens);
            if (ct) {
                while (ct) {
                    var spaceBefore = ct.GetModifiedSpaceBefore();
                    for (var sai = 0; sai < spaceBefore; sai++) {
                        text += " ";
                    }
                    text += ct.GetModifiedWord();
                    ct = ct.NextActive(usedCts);
                }
            }
            else {
                debugger;
            }
        }
        else {
            debugger;
        }
        return text;
    }

    GetOriginalNLP() {
        var nlpResult = {
            "sentences": []
        };
        for (var si = 0; si < this.sentenceCorrectionTokens.length; si++) {
            var nlpSentence = {
                tokens: []
            };
            var correctionTokens = this.sentenceCorrectionTokens[si];
            var usedCts = [];
            var ct = this.GetFirstCorrectionToken(correctionTokens);
            if (ct) {
                while (ct) {
                    nlpSentence.tokens.push(ct.GetLightOriginalToken());
                    ct = ct.NextActive(usedCts);
                }
            }
            else {
                debugger;
            }
            nlpResult.sentences.push(nlpSentence);
        }
        return nlpResult;
    }
    GetModifiedNLP() {
        var nlpResult = {
            "sentences": []
        };
        for (var si = 0; si < this.sentenceCorrectionTokens.length; si++) {
            var nlpSentence = {
                tokens: []
            };
            var correctionTokens = this.sentenceCorrectionTokens[si];
            var usedCts = [];
            var ct = this.GetFirstCorrectionToken(correctionTokens);
            if (ct) {
                while (ct) {
                    nlpSentence.tokens.push(ct.GetLightModifiedToken());
                    ct = ct.NextActive(usedCts);
                }
            }
            else {
                debugger;
            }
            nlpResult.sentences.push(nlpSentence);
        }
        return nlpResult;
    }

    GetCorrectedSentenceAsHtml(correctionTokens, toModifiedTokens) {
        var text = "";
        if (correctionTokens) {
            var usedCts = [];
            var ct = this.GetFirstCorrectionToken(correctionTokens);
            if (ct) {
                while (ct) {
                    usedCts.push(ct);
                    var className = "";
                    if (ct.modified == 1) {
                        className = "correctionAuto-button-color2-text";
                    }
                    else if (toModifiedTokens &&
                        ct.tokenIndice != undefined &&
                        toModifiedTokens.indexOf(ct.tokenIndice) != -1) {
                        className = "correctionAuto-wrong";
                    }
                    else if (ct.containError) {
                        className = "messageText-mistake";
                    }
                    if (className != "") {
                        var spaceBefore = ct.GetModifiedSpaceBefore();
                        if (spaceBefore) {
                            var space = "";
                            for (var sai = 0; sai < spaceBefore; sai++) {
                                space += " ";
                            }
                            text += "<span>" + space + "</span>";
                        }
                        text += "<span class='" + className + "'>" + ct.GetModifiedWord() + "</span>";
                    }
                    else {
                        text += "<span>";
                        var spaceBefore = ct.GetModifiedSpaceBefore();
                        if (spaceBefore) {
                            for (var sai = 0; sai < spaceBefore; sai++) {
                                text += " ";
                            }
                        }
                        text += ct.GetModifiedWord();
                        text += "</span>";
                    }
                    ct = ct.NextActive(usedCts);
                }
            }
            else {
                debugger;
            }
        }
        else {
            debugger;
        }
        return text;
    }

    SetSentenceAnalysisResults(sentenceAnalysisResults) {
        this.iterationCount++;
        // var dicoPrevNextTokens = null;
        if (this.sentenceAnalysisResults.length) {
            // dicoPrevNextTokens = this.LinkWithPrevResults(sentenceAnalysisResults);
            // if (!dicoPrevNextTokens.length)
            // {
            //     debugger;
            // }
            //
            this.analysisSet.push({
                sentenceAnalysisResults: this.sentenceAnalysisResults,
                sentenceCorrectionTokens: this.sentenceCorrectionTokens,
                validatedCorrections: this.validatedCorrections
            });
            if (this.sentenceAnalysisResults.length == sentenceAnalysisResults.length) {
                for (var i = 0; i < this.sentenceAnalysisResults.length; i++) {
                    if (this.sentenceAnalysisResults[i].context) {
                        if (sentenceAnalysisResults[i].context) {
                            debugger;
                        }
                        sentenceAnalysisResults[i].context = this.sentenceAnalysisResults[i].context;
                    }
                }
            }
            else {
                debugger;
            }
        }
        //
        this.InitializeAnalysisResults();
        this.sentenceAnalysisResults = sentenceAnalysisResults;
        this.GenerateCorrectionTokens();
    }
    GetSentenceAnalysisResults() {
        return this.sentenceAnalysisResults;
    }
    InitializeSuggestions() {
        this.sentenceIndice = 0;
        this.identRuleIndice = -1;
    }
    GenerateCorrectionTokens() {
        this.validatedCorrections = {};
        this.sentenceCorrectionTokens = [];
        for (var i = 0; i < this.sentenceAnalysisResults.length; i++) {
            var sentenceAnalysisResult = this.sentenceAnalysisResults[i];
            this.sentenceCorrectionTokens.push(this.CreateSentenceCorrectionTokens(sentenceAnalysisResult));
        }
    }
    GetLearningCards(identifiedRule) {
        var learningCards = [];
        if (!identifiedRule) {
            debugger;
            return learningCards;
        }
        var keys = [];
        if (identifiedRule.learningCard &&
            identifiedRule.learningCard.title &&
            identifiedRule.learningCard.lessonNumber) {
            var title = identifiedRule.learningCard.title.replace(/\s/g, "-");
            var key = title + "-" + identifiedRule.learningCard.lessonNumber;
            key = key.toLowerCase();
            keys.push(key);
            learningCards.push({
                key: key,
                title: title,
                lessonNumber: identifiedRule.learningCard.lessonNumber
            });

        }
        var actions = identifiedRule[this.action];
        if (!actions) {
            return learningCards;
        }
        if (actions.suggestions) {
            var suggestions = actions.suggestions;
            for (var sui = 0; sui < suggestions.length; sui++) {
                var suggestion = suggestions[sui];
                if (suggestion.learningCard &&
                    suggestion.learningCard.title &&
                    suggestion.learningCard.lessonNumber) {
                    var title = suggestion.learningCard.title.replace(/\s/g, "-");
                    var key = title + "-" + suggestion.learningCard.lessonNumber;
                    key = key.toLowerCase();
                    if (keys.indexOf(key) == -1) {
                        learningCards.push({
                            key: key,
                            title: title,
                            lessonNumber: suggestion.learningCard.lessonNumber
                        });
                        keys.push(key);
                    }
                }
            }
        }
        return learningCards;
    }
    GetLCKey(learningCard) {
        var key = "";
        if (learningCard &&
            learningCard.title &&
            learningCard.lessonNumber) {
            var title = learningCard.title.replace(/\s/g, "-");
            key = title + "-" + learningCard.lessonNumber;
            key = key.toLowerCase();
        }
        return key;
    }
    GetLCSuggestions(identifiedRule, suggestions) {
        var lcSuggestions = [];
        var key = this.GetLCKey(identifiedRule.learningCard);

        lcSuggestions.push({
            key: key,
            learningCard: identifiedRule.learningCard,
            suggestions: []
        });
        if (!suggestions) {
            return lcSuggestions;
        }
        for (var sui = 0; sui < suggestions.length; sui++) {
            var suggestion = suggestions[sui];

            var key = this.GetLCKey(suggestion.learningCard);
            if (key) {
                var lcIndice = 0;
                for (var lcIndice = 1; lcIndice < lcSuggestions.length; lcIndice++) {
                    if (lcSuggestions[lcIndice].key == key) {
                        lcSuggestions[lcIndice].suggestions.push(suggestion);
                        break;
                    }
                }
                if (lcIndice == lcSuggestions.length) {
                    var lcSuggestion = {
                        key: key,
                        learningCard: suggestion.learningCard,
                        suggestions: [suggestion]
                    }
                    lcSuggestions.push(lcSuggestion);
                }
            }
            else {
                lcSuggestions[0].suggestions.push(suggestion);
            }

        }
        return lcSuggestions;
    }
    DisplayLightCorrectionSuggestions(identifiedRule, learningCards) {
        if (!identifiedRule) {
            debugger;
            return "";
        }
        var actions = identifiedRule[this.action];
        if (!actions) {
            debugger;
            return "";
        }
        var htmls = {
            found: false,
            wrongText: "",
            suggestions: ""
            // style: ""
        };
        var marginTop = "";
        var keyLCs = {};
        if (learningCards) {
            for (var lci = 0; lci < learningCards.length; lci++) {
                keyLCs[learningCards[lci].key] = lci;
            }
        }

        if (actions.suggestions) {
            var sentenceAnalysisResult = this.sentenceAnalysisResults[this.sentenceIndice];
            var sentenceValidatedCorrections = this.validatedCorrections[this.sentenceIndice];
            var suggestions = actions.suggestions;

            var lcSuggestions = this.GetLCSuggestions(identifiedRule, suggestions);

            // var lcmarginTop = "style='width:100%; padding:6px; text-align:left;";
            var first = 1;
            for (var lcsi = 0; lcsi < lcSuggestions.length; lcsi++) {
                if (!lcSuggestions[lcsi].suggestions.length) {
                    continue;
                }
                htmls.suggestions += "<div id='CorrectionAutoLightSuggestion_0' class='correctionAutoLight-suggestion";
                if (first) {
                    htmls.suggestions += " correctionAutoLight-top";
                }
                first = 0;
                htmls.suggestions += "'>";
                var key = lcSuggestions[lcsi].key;
                var indice = keyLCs[key];
                if (learningCards && indice != undefined) {
                    var learningCard = learningCards[indice];
                    htmls.suggestions += "<div class='correctionAutoLight-lc'>" + learningCard.title + "</div>";
                    // htmls.suggestions += "  <p style='font-family: Avenir-Heavy;'>" + learningCard.title + "</p>";
                    // htmls.suggestions += "  <span style='font-size: 80%;'> (" + learningCard.description + ")</span>";
                    // htmls.suggestions += "  <span class='correctionAuto-button-help'> " + knowMoreText + "</span>";
                    // htmls.suggestions += "</div>";

                }
                else {
                    var learningCard = lcSuggestions[lcsi].learningCard;
                    if (learningCard) {
                        htmls.suggestions += "<div class='correctionAutoLight-lc'>" + learningCard.title + " " + learningCard.lessonNumber + "</div>";
                    }
                }

                for (var sui = 0; sui < lcSuggestions[lcsi].suggestions.length; sui++) {
                    var marginTop = "";
                    var suggestion = lcSuggestions[lcsi].suggestions[sui];
                    var tokenModifications = suggestion.corrections || suggestion.modifications;
                    if (tokenModifications) {
                        var correctionTokens = this.CreateSentenceCorrectionTokens(sentenceAnalysisResult);

                        this.ApplyValidatedCorrections(sentenceAnalysisResult, sentenceValidatedCorrections, correctionTokens);
                        if (sui == 0) {
                            htmls.wrongText = this.ShowCorrections(correctionTokens, tokenModifications);
                            // $("#CorrectionAutoWrongText").html();
                        }
                        this.ApplyCorrections(correctionTokens, tokenModifications, {});
                        var suggestionText = this.GetCorrectedSentenceAsHtml(correctionTokens);
                        if (!sui) {
                            htmls.suggestions += "<div class='correctionAutoLight-suggestion-text'>" + suggestionText + "</div>";
                            htmls.suggestions += "</div>";
                        }
                        else {
                            htmls.suggestions += "<div id='CorrectionAutoLightSuggestion_" + sui + "' class='correctionAutoLight-suggestion correctionAutoLight-suggestion-text' " + marginTop + ">" + suggestionText + "</div>";
                        }
                        // if (marginTop == "") {
                        //     marginTop = " style='margin-top: 6px;'";
                        // }
                        htmls.found = true;
                    }
                }
            }
        }
        return htmls;
    }
    DisplayCorrectionSuggestions(identifiedRule, learningCards, knowMoreText) {
        if (!identifiedRule) {
            debugger;
            return "";
        }
        var htmls = {
            found: false,
            wrongText: "",
            suggestions: ""
            // style: ""
        };
        var marginTop = "";
        var keyLCs = {};
        if (learningCards) {
            for (var lci = 0; lci < learningCards.length; lci++) {
                keyLCs[learningCards[lci].key] = lci;
            }
        }
        var sentenceAnalysisResult = this.sentenceAnalysisResults[this.sentenceIndice];
        var sentenceValidatedCorrections = this.validatedCorrections[this.sentenceIndice];
        var actions = identifiedRule[this.action];
        if (actions && actions.suggestions) {

            var suggestions = actions.suggestions;

            var lcSuggestions = this.GetLCSuggestions(identifiedRule, suggestions);

            var lcmarginTop = "style='width:95%; margin:auto; text-align:left;";
            for (var lcsi = 0; lcsi < lcSuggestions.length; lcsi++) {
                if (lcSuggestions.length > 1) {
                    var key = lcSuggestions[lcsi].key;
                    var indice = keyLCs[key];
                    if (learningCards && indice != undefined) {
                        var learningCard = learningCards[indice];
                        htmls.suggestions += "<div id='CorrectionAutoSuggestionHelp_" + key + "'" + lcmarginTop + "'>";
                        htmls.suggestions += "  <span style='font-family: Avenir-Heavy;'>" + learningCard.title + "</span>";
                        htmls.suggestions += "  <span style='font-size: 80%;'> (" + learningCard.description + ")</span>";
                        htmls.suggestions += "  <span class='correctionAuto-button-help'> " + knowMoreText + "</span>";
                        htmls.suggestions += "</div>";

                    }
                    else {
                        var learningCard = lcSuggestions[lcsi].learningCard;
                        if (learningCard) {
                            htmls.suggestions += "<div" + lcmarginTop + "' style='font-family: Avenir-Heavy;'>" + learningCard.title + " " + learningCard.lessonNumber + "</div>";
                        }
                    }
                    if (lcsi == 0) {
                        lcmarginTop += " margin-top: 24px;";
                    }
                }
                var marginTop = "";
                for (var sui = 0; sui < lcSuggestions[lcsi].suggestions.length; sui++) {

                    var suggestion = lcSuggestions[lcsi].suggestions[sui];
                    var tokenModifications = suggestion.corrections || suggestion.modifications;
                    if (tokenModifications) {
                        var correctionTokens = this.CreateSentenceCorrectionTokens(sentenceAnalysisResult);

                        this.ApplyValidatedCorrections(sentenceAnalysisResult, sentenceValidatedCorrections, correctionTokens);
                        if (sui == 0) {
                            htmls.wrongText = this.ShowCorrections(correctionTokens, tokenModifications);
                            htmls.text = this.GetCorrectedSentence(correctionTokens);
                            // $("#CorrectionAutoWrongText").html();
                        }
                        this.ApplyCorrections(correctionTokens, tokenModifications, {});
                        var suggestionText = this.GetCorrectedSentenceAsHtml(correctionTokens);
                        htmls.suggestions += "<button id='CorrectionAutoSuggestion_" + sui + "' class='correctionAuto-button correctionAuto-button-color2'" + marginTop + ">" + suggestionText + "</button>";
                        if (marginTop == "") {
                            marginTop = " style='margin-top: 12px;'";
                        }
                        htmls.found = true;
                    }
                }
            }
        }
        else {
            var correctionTokens = this.CreateSentenceCorrectionTokens(sentenceAnalysisResult);
            this.ApplyValidatedCorrections(sentenceAnalysisResult, sentenceValidatedCorrections, correctionTokens);
            htmls.wrongText = this.ShowCorrections(correctionTokens);
            htmls.text = this.GetCorrectedSentence(correctionTokens);
        }
        return htmls;
    }


    GetAllSuggestionAsHtml(mistakeClassName, correctionClassName, sentenceIndice, correctionIndice) {
        var html = "";
        // var mistakeClass = "messageText-mistake";
        var mistakeStyle = "text-decoration: underline;-webkit-text-decoration-color: #FF5F70;text-decoration-color: #FF5F70;";
        var correctionClass = "addedChain";
        if (mistakeClassName) {
            mistakeClass = mistakeClassName;
        }
        if (correctionClassName) {
            correctionClass = correctionClassName;
        }

        if (this.sentenceAnalysisResults && this.sentenceAnalysisResults.length) {
            var sStart = 0;
            var sEnd = this.sentenceAnalysisResults.length;
            if (sentenceIndice != undefined) {
                if (sentenceIndice >= 0 && sentenceIndice < this.sentenceAnalysisResults.length) {
                    sStart = sentenceIndice;
                    sEnd = sentenceIndice + 1;
                }
            }
            for (var i = sStart; i < sEnd; i++) {
                var sentenceAnalysisResult = this.sentenceAnalysisResults[i];
                var sentence = sentenceAnalysisResult.sentence;
                var correctedTokenIndices = {};
                var errors = sentenceAnalysisResult.results || sentenceAnalysisResult.errors;

                if (errors) {
                    var found = false;
                    var rStart = 0;
                    var rEnd = errors.length;
                    if (correctionIndice != undefined) {
                        if (correctionIndice >= 0 && correctionIndice < errors.length) {
                            rStart = correctionIndice;
                            rEnd = correctionIndice + 1;
                        }
                    }
                    for (var ri = rStart; ri < rEnd; ri++) {
                        var error = errors[ri];
                        if (error.corrections &&
                            error.corrections.suggestions &&
                            error.corrections.suggestions.length) {
                            var corrections = error.corrections.suggestions[0].corrections;
                            for (var ci = 0; ci < corrections.length; ci++) {
                                var correction = corrections[ci];
                                if (correction.tokenIndice != undefined) {
                                    correctedTokenIndices[correction.tokenIndice] = true;
                                    found = true;
                                }
                                if (correction.tokenIndices != undefined) {
                                    for (var ti = 0; ti < correction.tokenIndices.length; ti++) {
                                        correctedTokenIndices[correction.tokenIndices[ti]] = true;

                                    }
                                    found = true;
                                }
                                if (correction.targetTokenIndice != undefined) {
                                    correctedTokenIndices[correction.targetTokenIndice] = true;
                                    found = true;
                                }
                            }
                        }
                    }
                    if (found) {
                        html += "<div id='sentence-analysis_" + i + "' class='sentence-analysis'>";
                        html += "<div>";
                        for (var ti = 0; ti < sentence.tokens.length; ti++) {
                            var token = sentence.tokens[ti];
                            var space = "";
                            for (var spi = 0; spi < token.spaceBefore; spi++) {
                                space += " ";
                            }
                            if (correctedTokenIndices[ti]) {
                                if (space != "") {
                                    html += "<span>" + space + "</span>";
                                }
                                //html += "<span class='" + mistakeClass + "'>" + token.word + "</span>";
                                html += "<span style='" + mistakeStyle + "'>" + token.word + "</span>";
                            }
                            else {
                                html += "<span>" + space + token.word + "</span>";
                            }
                        }
                        html += "</div>";
                        html += "<div style='text-align:right;'>";
                        html += "<button class='blue' id='correct-sentence_" + i + "'>Start correction</button>";
                        html += "</div>";
                        html += "</div>";
                    }
                }
            }
        }
        return html;
    }
    GetAllSuggestionAsHtml2(mistakeClassName, correctionClassName, sentenceIndice, correctionIndice) {
        var html = "";
        // var mistakeClass = "messageText-mistake";
        var mistakeStyle = "text-decoration: underline;-webkit-text-decoration-color: #FF5F70;text-decoration-color: #FF5F70;";
        var correctionClass = "addedChain";
        if (mistakeClassName) {
            mistakeClass = mistakeClassName;
        }
        if (correctionClassName) {
            correctionClass = correctionClassName;
        }

        if (this.sentenceAnalysisResults && this.sentenceAnalysisResults.length) {
            var sStart = 0;
            var sEnd = this.sentenceAnalysisResults.length;
            if (sentenceIndice != undefined) {
                if (sentenceIndice >= 0 && sentenceIndice < this.sentenceAnalysisResults.length) {
                    sStart = sentenceIndice;
                    sEnd = sentenceIndice + 1;
                }
            }
            for (var i = sStart; i < sEnd; i++) {
                var sentenceAnalysisResult = this.sentenceAnalysisResults[i];
                var sentence = sentenceAnalysisResult.sentence;
                var correctedTokenIndices = {};
                var errors = sentenceAnalysisResult.results || sentenceAnalysisResult.errors;

                if (errors) {
                    var found = false;
                    var rStart = 0;
                    var rEnd = errors.length;
                    if (correctionIndice != undefined) {
                        if (correctionIndice >= 0 && correctionIndice < errors.length) {
                            rStart = correctionIndice;
                            rEnd = correctionIndice + 1;
                        }
                    }
                    for (var ri = rStart; ri < rEnd; ri++) {
                        var error = errors[ri];
                        if (error.corrections &&
                            error.corrections.suggestions &&
                            error.corrections.suggestions.length) {
                            var corrections = error.corrections.suggestions[0].corrections;
                            for (var ci = 0; ci < corrections.length; ci++) {
                                var correction = corrections[ci];
                                if (correction.tokenIndice != undefined) {
                                    correctedTokenIndices[correction.tokenIndice] = true;
                                    found = true;
                                }
                                if (correction.tokenIndices != undefined) {
                                    for (var ti = 0; ti < correction.tokenIndices.length; ti++) {
                                        correctedTokenIndices[correction.tokenIndices[ti]] = true;

                                    }
                                    found = true;
                                }
                                if (correction.targetTokenIndice != undefined) {
                                    correctedTokenIndices[correction.targetTokenIndice] = true;
                                    found = true;
                                }
                            }
                        }
                    }
                    if (found) {
                        // html += "<div id='sentence-analysis_" + i + "' class='sentence-analysis'>";
                        // html += "<div>";
                        for (var ti = 0; ti < sentence.tokens.length; ti++) {
                            var token = sentence.tokens[ti];
                            var space = "";
                            for (var spi = 0; spi < token.spaceBefore; spi++) {
                                space += " ";
                            }
                            if (correctedTokenIndices[ti]) {
                                if (space != "") {
                                    html += "<span>" + space + "</span>";
                                }
                                //html += "<span class='" + mistakeClass + "'>" + token.word + "</span>";
                                html += "<span style='" + mistakeStyle + "'>" + token.word + "</span>";
                            }
                            else {
                                html += "<span>" + space + token.word + "</span>";
                            }
                        }
                        // html += "</div>";
                        // html += "<div style='text-align:right;'>";
                        // html += "<button class='blue' id='correct-sentence_" + i + "'>Start correction</button>";
                        // html += "</div>";
                        // html += "</div>";
                    }
                }
            }
        }

        return html;
    }

    ApplyValidatedCorrections(sentenceAnalysisResult, sentenceValidatedCorrections, correctionTokens,
        excludedValidatedCorrectionIndice, addActions, options) {
        if (sentenceValidatedCorrections && sentenceAnalysisResult) {
            var identifiedRules = this.GetSet(sentenceAnalysisResult);
            if (identifiedRules) {

                if (sentenceValidatedCorrections.length &&
                    !sentenceValidatedCorrections[sentenceValidatedCorrections.length - 1].manualCorrection) {
                    for (var ei = 0; ei < sentenceValidatedCorrections.length; ei++) {
                        if (excludedValidatedCorrectionIndice != undefined &&
                            ei == excludedValidatedCorrectionIndice) {
                            continue;
                        }
                        var validatedCorrection = sentenceValidatedCorrections[ei];
                        if (validatedCorrection) {
                            var identifiedRule = identifiedRules[validatedCorrection.identRuleIndice];
                            if (identifiedRule && identifiedRule[this.action]) {
                                var actions = identifiedRule[this.action];
                                var tokenModifications = actions.suggestions[validatedCorrection.suggestionIndice].corrections ||
                                    actions.suggestions[validatedCorrection.suggestionIndice].modifications;
                                var localOptions = options;
                                if (!localOptions) {
                                    localOptions = {};
                                }
                                localOptions.identifiedRule = addActions ? identifiedRule : null;
                                localOptions.modified = 0;
                                this.ApplyCorrections(correctionTokens, tokenModifications, localOptions);
                            }
                            else {
                                debugger;
                            }
                        }
                        else {
                            debugger;
                        }
                    }
                }
            }
            else {
                debugger;
            }
        }
    }
    ApplyCorrections(correctionTokens, tokenModifications, options) {
        if (tokenModifications) {
            for (var ci = 0; ci < tokenModifications.length; ci++) {
                var tokenCorrection = tokenModifications[ci];
                this.ApplyTokenCorrection(correctionTokens, tokenCorrection, options);
            }
        }
        else {
            debugger;
        }
    }

    ShowCorrections(correctionTokens, tokenModifications) {
        var toModifiedTokens = [];
        if (tokenModifications) {
            for (var ci = 0; ci < tokenModifications.length; ci++) {
                var tokenCorrection = tokenModifications[ci];
                if (tokenCorrection.tokenIndice != undefined) {
                    toModifiedTokens.push(tokenCorrection.tokenIndice);
                }
            }
        }
        return this.GetCorrectedSentenceAsHtml(correctionTokens, toModifiedTokens);
    }

    GetValidatedCorrectionCount() {
        var count = 0;
        for (var key in this.validatedCorrections) {
            count += this.validatedCorrections[key].length;
        }
        return count;
    }
    ComputeExercices() {
        var exercices = [];
        var correctedTexts = [];
        for (var si = 0; si < this.sentenceAnalysisResults.length; si++) {
            let correctedText = "";
            let sentenceValidatedCorrections = this.validatedCorrections[si];
            if (sentenceValidatedCorrections &&
                sentenceValidatedCorrections.length &&
                sentenceValidatedCorrections[sentenceValidatedCorrections.length - 1].manualCorrection) {
                correctedText = sentenceValidatedCorrections[sentenceValidatedCorrections.length - 1].manualCorrection;
            }
            else {
                var sentenceAnalysisResult = this.sentenceAnalysisResults[si];
                var correctionTokens = this.CreateSentenceCorrectionTokens(sentenceAnalysisResult);
                this.ApplyValidatedCorrections(sentenceAnalysisResult, sentenceValidatedCorrections, correctionTokens);
                correctedText = this.GetCorrectedSentence(correctionTokens);
            }
            correctedTexts.push(correctedText);
        }
        this.analysisSet.push({
            sentenceAnalysisResults: this.sentenceAnalysisResults,
            sentenceCorrectionTokens: this.sentenceCorrectionTokens,
            validatedCorrections: this.validatedCorrections
        });

        var correctionTokens = null;
        var options = {
            indice: 0
        };
        for (var si = 0; si < this.sentenceAnalysisResults.length; si++) {
            for (var asi = 0; asi < this.analysisSet.length; asi++) {
                var sentenceAnalysisResults = this.analysisSet[asi].sentenceAnalysisResults;
                var sentenceAnalysisResult = sentenceAnalysisResults[si];
                options.prefixId = asi + "-" + si;
                if (asi == 0) {
                    correctionTokens = this.CreateSentenceCorrectionTokens(sentenceAnalysisResult, options.prefixId);
                }
                else {
                    correctionTokens = this.CreateSentenceCorrectionTokens1(asi, si, correctionTokens);
                }
                if (!correctionTokens) {
                    debugger;
                    continue;
                }
                var sentenceValidatedCorrections = this.analysisSet[asi].validatedCorrections[si];
                if (sentenceValidatedCorrections) {
                    this.ApplyValidatedCorrections(sentenceAnalysisResult, sentenceValidatedCorrections,
                        correctionTokens, undefined, true, options);
                }
            }
        }
        // disable errors : WHY ?
        var ct = this.GetFirstCorrectionToken(correctionTokens);
        var disabledErrors = [];
        var usedCts = [];
        while (ct) {
            if (ct.corrections) {
                for (var ai1 = ct.corrections.length - 1; ai1 >= 1; ai1--) {
                    for (var ai2 = ai1 - 1; ai2 >= 0; ai2--) {
                        if (ct.corrections[ai1].type == "delete") {
                            if (disabledErrors.indexOf(ct.corrections[ai2].error) == -1) {
                                disabledErrors.push(ct.corrections[ai2].error);
                            }
                        }
                        else if (ct.corrections[ai1].type == "move") {
                            if (ct.corrections[ai2].type == "move") {
                                if (disabledErrors.indexOf(ct.corrections[ai2].error) == -1) {
                                    disabledErrors.push(ct.corrections[ai2].error);
                                }
                            }
                            else if (ct.corrections[ai2].type == "new") {
                                if (disabledErrors.indexOf(ct.corrections[ai1].error) == -1) {
                                    disabledErrors.push(ct.corrections[ai1].error);
                                }
                            }
                        }
                        else if (ct.corrections[ai1].type == "modifyAtt") {
                            if (ct.corrections[ai2].type == "modifyAtt") {
                                if (disabledErrors.indexOf(ct.corrections[ai2].error) == -1) {
                                    disabledErrors.push(ct.corrections[ai2].error);
                                }
                            }
                            else if (ct.corrections[ai2].type == "new") {
                                if (disabledErrors.indexOf(ct.corrections[ai1].error) == -1) {
                                    disabledErrors.push(ct.corrections[ai1].error);
                                }
                            }
                        }
                    }
                }
            }
            ct = ct.Next(usedCts);
        }
        for (var si = 0; si < this.sentenceAnalysisResults.length; si++) {
            for (var asi = 0; asi < this.analysisSet.length; asi++) {

                var sentenceAnalysisResults = this.analysisSet[asi].sentenceAnalysisResults;
                var sentenceAnalysisResult = sentenceAnalysisResults[si];
                if (!sentenceAnalysisResult) {
                    debugger;
                    continue;
                }
                var errors = this.GetSet(sentenceAnalysisResult);
                if (!errors) {
                    continue;
                }
                var correctedText = correctedTexts[si];

                var sentenceValidatedCorrections = this.analysisSet[asi].validatedCorrections[si];
                if (sentenceValidatedCorrections &&
                    sentenceValidatedCorrections.length) {
                    if (!sentenceValidatedCorrections[sentenceValidatedCorrections.length - 1].manualCorrection) {
                        for (var svci = 0; svci < sentenceValidatedCorrections.length; svci++) {
                            var validatedCorrection = sentenceValidatedCorrections[svci];
                            var identifiedRule = errors[validatedCorrection.identRuleIndice];
                            if (identifiedRule && identifiedRule.learningCard) {
                                if (disabledErrors.indexOf(identifiedRule) == -1) {
                                    var correctionTokens = null;
                                    var options = {
                                        indice: 0
                                    };
                                    // we apply all correction excepted svci correction
                                    for (var asi2 = 0; asi2 < this.analysisSet.length; asi2++) {
                                        var sentenceAnalysisResults = this.analysisSet[asi2].sentenceAnalysisResults;
                                        var sentenceAnalysisResult = sentenceAnalysisResults[si];
                                        options.prefixId = asi2 + "-" + si;
                                        if (asi2 == 0) {
                                            correctionTokens = this.CreateSentenceCorrectionTokens(sentenceAnalysisResult, options.prefixId);
                                        }
                                        else {
                                            correctionTokens = this.CreateSentenceCorrectionTokens2(asi2, si, correctionTokens);
                                        }
                                        if (!correctionTokens) {
                                            debugger;
                                            continue;
                                        }
                                        var sentenceValidatedCorrections2 = this.analysisSet[asi2].validatedCorrections[si];
                                        if (sentenceValidatedCorrections2) {
                                            var excludedValidatedCorrectionIndice = undefined;
                                            if (asi2 == asi) {
                                                excludedValidatedCorrectionIndice = svci;
                                            }
                                            this.ApplyValidatedCorrections(sentenceAnalysisResult, sentenceValidatedCorrections2,
                                                correctionTokens, excludedValidatedCorrectionIndice, false,
                                                options);
                                        }
                                    }
                                    if (correctionTokens) {
                                        var text = this.GetCorrectedSentence(correctionTokens);
                                        // console.log(text);
                                        var diff = new ONPDiff(text, correctedText);
                                        diff.compose();
                                        var correction = diff.getResult();

                                        var exercice = {
                                            type: "correction",
                                            correction: correction,
                                            learningCard: identifiedRule.learningCard
                                        };
                                        if (exercice.learningCard.type &&
                                            exercice.learningCard.type == otherLang.learningCardType.correctionWord) {
                                            var suggestions = identifiedRule[this.action].suggestions;
                                            var corrections = suggestions[validatedCorrection.suggestionIndice].corrections ||
                                                suggestions[validatedCorrection.suggestionIndice].modifications;
                                            var found = false;
                                            for (var ci = 0; ci < corrections.length; ci++) {
                                                var corr = corrections[ci];
                                                if (corr.type == "replaceAttValue" &&
                                                    corr.att == "word") {
                                                    exercice.learningCard.word = corr.text;
                                                    found = true;
                                                    break;
                                                }
                                            }
                                            if (!found) {
                                                debugger;
                                                continue;
                                            }
                                        }
                                        exercices.push(exercice);
                                    }
                                    else {
                                        debugger;
                                    }
                                }
                            }
                            else {
                                debugger;
                            }
                        }
                    }
                    else{
                        //
                        // to finish
                        //
                        debugger;
                        // var text = this.GetCorrectedSentence(correctionTokens);
                        // var diff = new ONPDiff(text, correctedText);
                        // diff.compose();
                        // var correction = diff.getResult();
                        // var exercice = {
                        //     type: "correction",
                        //     correction: correction,
                        //     learningCard: identifiedRule.learningCard
                        // };
                    }
                }
            }
        }
        return exercices;
    }
    OnCorrectManually(correction) {
        if (!this.validatedCorrections[this.sentenceIndice]) {
            this.validatedCorrections[this.sentenceIndice] = [];
        }

        this.validatedCorrections[this.sentenceIndice].push({
            identRuleIndice: this.identRuleIndice,
            manualCorrection: correction
        });
    }
    OnAcceptCorrectionSuggestion(identifiedRule, indice) {
        var actions = identifiedRule[this.action];
        if (!actions || !actions.suggestions) {
            debugger;
            return;
        }
        if (indice >= 0 && indice < actions.suggestions.length) {
            var correctionTokens = this.sentenceCorrectionTokens[this.sentenceIndice];
            if (correctionTokens) {
                var tokenModifications = actions.suggestions[indice].corrections ||
                    actions.suggestions[indice].modifications;
                if (tokenModifications) {
                    var options = {
                        // error: identifiedRule,
                        modified: 1
                    };
                    this.ApplyCorrections(correctionTokens, tokenModifications, options);

                    if (!this.validatedCorrections[this.sentenceIndice]) {
                        this.validatedCorrections[this.sentenceIndice] = [];
                    }

                    this.validatedCorrections[this.sentenceIndice].push({
                        identRuleIndice: this.identRuleIndice,
                        suggestionIndice: indice
                    });
                }
                else {
                    debugger;
                }
            }
            else {
                debugger;
            }
        }
        else {
            debugger;
        }
    }
    static AddLearningCardInfos(learningCard, json) {
        if (learningCard && learningCard.title && learningCard.lessonNumber) {
            var key = learningCard.title + "_" + learningCard.lessonNumber;
            if (json.learningCards[key]) {
                json.learningCards[key]++;
            }
            else {
                json.learningCards[key] = 1;
            }
        }
    }
    RecAddError(indice, identifiedRules, suggestionIndices, learningCards, json) {
        if (indice >= identifiedRules.length) {
            for (var i = 0; i < identifiedRules.length; i++) {
                var identifiedRule = identifiedRules[i];
                this.OnAcceptCorrectionSuggestion(identifiedRule, suggestionIndices[i]);
            }
            var text = this.GetCorrectedText();
            var error = {
                sentence: text,
                nlp: this.GetModifiedNLP(),
                learningCards: {}
            };
            for (var li = 0; li < learningCards.length; li++) {
                ModificationTokenServices.AddLearningCardInfos(learningCards[li], error);
            }
            json.errors.push(error);
            this.GenerateCorrectionTokens();
            this.InitializeSuggestions();
            return;
        }
        var identifiedRule = identifiedRules[indice];
        if (identifiedRule) {
            if (identifiedRule.learningCard) {
                learningCards[indice] = identifiedRule.learningCard;
            }
            else {
                learningCards[indice] = {};
            }
        }
        else {
            debugger;
            learningCards[indice] = {};
        }
        var actions = identifiedRule.errors;
        if (actions && actions.suggestions) {
            for (var si = 0; si < actions.suggestions.length; si++) {
                suggestionIndices[indice] = si;
                this.RecAddError(indice + 1,
                    identifiedRules, suggestionIndices, learningCards,
                    json);
            }
        }
        else {
            debugger;
        }
    }
    //  ------------------
    //    RecAddCorrection
    //  ------------------
    RecAddCorrection(indice, identifiedRules, suggestionIndices, learningCards,
        json) {
        if (indice >= identifiedRules.length) {
            for (var i = 0; i < identifiedRules.length; i++) {
                var identifiedRule = identifiedRules[i];
                this.OnAcceptCorrectionSuggestion(identifiedRule, suggestionIndices[i]);
            }
            var text = this.GetCorrectedText();
            var correction = {
                sentence: text,
                learningCards: {}
            };
            for (var li = 0; li < learningCards.length; li++) {
                ModificationTokenServices.AddLearningCardInfos(learningCards[li], correction);
            }
            json.corrections.push(correction);
            this.GenerateCorrectionTokens();
            this.InitializeSuggestions();
            return;
        }
        var identifiedRule = identifiedRules[indice];
        if (identifiedRule) {
            if (identifiedRule.learningCard) {
                learningCards[indice] = identifiedRule.learningCard;
            }
            else {
                learningCards[indice] = {};
            }
        }
        else {
            debugger;
            learningCards[indice] = {};
        }
        var actions = identifiedRule.corrections;
        if (actions && actions.suggestions) {
            for (var si = 0; si < actions.suggestions.length; si++) {
                suggestionIndices[indice] = si;
                this.RecAddCorrection(indice + 1,
                    identifiedRules, suggestionIndices, learningCards,
                    json);
            }
        }
        else {
            debugger;
        }
    }
    RecComputeCombination(identifiedRules, dicoConflicts, indice, count, combinations, combination) {
        if (combination.length == count) {
            var key = combination[0].id;
            for (var i = 1; i < combination.length; i++) {
                key += "_" + combination[i].id;
            }
            if (!combinations[key]) {
                combinations[key] = combination.slice(0);
            }
            return;
        }
        if (indice >= identifiedRules.length) {
            combination = [];
            return;
        }
        var identifiedRule = identifiedRules[indice];
        var conflicts = dicoConflicts[identifiedRule.id];
        if (conflicts.length) {
            this.RecComputeCombination(identifiedRules, dicoConflicts, indice + 1, count, combinations, combination);
            var notForbidden = true;
            for (var i = 0; i < combination.length; i++) {
                var prevIdentifiedRule = combination[i];
                if (dicoConflicts[prevIdentifiedRule.id].indexOf(identifiedRule.id) != -1) {
                    notForbidden = false;
                }
            }
            if (notForbidden) {
                combination.push(identifiedRule);
                this.RecComputeCombination(identifiedRules, dicoConflicts, indice + 1, count, combinations, combination);
                combination.splice(combination.length - 1, 1);
            }
        }
        else {
            combination.push(identifiedRule);
            this.RecComputeCombination(identifiedRules, dicoConflicts, indice + 1, count, combinations, combination);
            combination.splice(combination.length - 1, 1);
        }
    }
    GetAllCorrectionSuggestions(originalText) {

        var json = {
            sentence: originalText,
            corrections: []
        };
        // only one correction
        var identifiedRules = [];
        //
        var dicoRules = {};
        var dicoConflicts = [];

        let result = this.NextSuggestions();
        if (result.manualCorrection) {
            debugger;
        }
        let identifiedRule = result.identifiedRule;
        while (identifiedRule) {
            let actions = identifiedRule.corrections;
            if (actions && actions.suggestions) {
                dicoRules[identifiedRule.id] = identifiedRules.length;
                identifiedRules.push(identifiedRule);
                dicoConflicts[identifiedRule.id] = [];
            }
            result = this.NextSuggestions();
            if (result.manualCorrection) {
                debugger;
            }
            identifiedRule = result.identifiedRule;
        }
        var conflictCount = 0;
        var ruleWithoutConflictCount = 0;

        for (var i = 0; i < identifiedRules.length; i++) {
            let identifiedRule = identifiedRules[i];
            if (identifiedRule.conflicts &&
                identifiedRule.conflicts.length) {
                var conflicts = dicoConflicts[identifiedRule.id];
                for (var ci = 0; ci < identifiedRule.conflicts.length; ci++) {
                    var indice = dicoRules[identifiedRule.conflicts[ci]];
                    if (indice != undefined) {
                        conflicts.push(indice);
                        conflictCount++;
                    }
                }
            }
            else {
                ruleWithoutConflictCount++;
            }
        }
        if (identifiedRules.length) {
            var combinations = {};

            if (conflictCount == 0) {
                combinations["all"] = identifiedRules;
            }
            else {
                var minCount = ruleWithoutConflictCount + 1;
                var maxCount = identifiedRules.length - 1;
                for (var count = minCount; count <= maxCount; count++) {
                    for (var startIndice = 0; startIndice <= identifiedRules.length - count; startIndice++) {
                        var combination = [];
                        this.RecComputeCombination(identifiedRules, dicoConflicts, startIndice, count, combinations, combination);
                    }
                }
            }

            for (var key in combinations) {
                var suggestions = [];
                var learningCards = [];
                identifiedRules = combinations[key];
                for (var iri = 0; iri < identifiedRules.length; iri++) {
                    suggestions.push(0);
                    learningCards.push({});
                }
                // all corrections
                this.InitializeSuggestions();
                this.RecAddCorrection(0, identifiedRules, suggestions, learningCards, json);
            }
        }

        return json;
    }
    GetAllErrorSuggestions(originalText) {

        var json = {
            sentence: originalText,
            errors: []
        };
        // only one error
        var identifiedRules = [];
        var suggestions = [];
        var learningCards = [];
        //
        let result = this.NextSuggestions();
        if (result.manualCorrection) {
            debugger;
        }
        let identifiedRule = result.identifiedRule;
        while (identifiedRule) {
            var actions = identifiedRule.errors;
            if (actions && actions.suggestions) {
                identifiedRules.push(identifiedRule);
                suggestions.push(0);
                learningCards.push({});
            }
            result = this.NextSuggestions();
            if (result.manualCorrection) {
                debugger;
            }
            identifiedRule = result.identifiedRule;
        }
        // all errors
        if (identifiedRules.length) {
            this.InitializeSuggestions();
            this.RecAddError(0, identifiedRules, suggestions, learningCards, json);
        }
        return json;
    }
    CheckCases() {
        for (var si = 0; si < this.sentenceCorrectionTokens.length; si++) {
            var correctionTokens = this.sentenceCorrectionTokens[si];
            if (correctionTokens) {
                var usedCts = [];
                var ct = this.GetFirstCorrectionToken(correctionTokens);
                if (ct) {
                    var token = ct.GetModifiedToken();
                    var upperCase = dicoLowerUpperCases[token.word[0]];
                    if (upperCase) {
                        var word = upperCase + token.word.substring(1);
                        ct.SetModifiedWord(word);
                    }
                    ct = ct.NextActive(usedCts);
                    if (ct) {
                        while (ct) {
                            var token = ct.GetModifiedToken();
                            if (!token.keepCase &&
                                token.word != "I" &&
                                token.pos != "NNP" &&
                                token.pos != "NNPS") {
                                var lowerCase = dicoUpperCaseLowers[token.word[0]];
                                if (lowerCase) {
                                    var word = lowerCase + token.word.substring(1);
                                    ct.SetModifiedWord(word);
                                }
                            }
                            ct = ct.NextActive(usedCts);
                        }
                    }
                    else {
                        debugger;
                    }
                }
            }
            else {
                debugger;
            }
        }
    }
    CheckSpaceBefore() {
        for (var si = 0; si < this.sentenceCorrectionTokens.length; si++) {
            var correctionTokens = this.sentenceCorrectionTokens[si];
            if (correctionTokens) {
                var usedCts = [];
                var ct = this.GetFirstCorrectionToken(correctionTokens);
                if (si) {
                    if (ct.token.spaceBefore == 0) {
                        //ct.token.spaceBefore = 1;
                        ct.SetModifiedSpaceBefore(1);
                    }
                }
                else {
                    if (ct.token.spaceBefore > 0) {
                        //ct.token.spaceBefore = 0;
                        ct.SetModifiedSpaceBefore(0);
                    }
                }
                ct = ct.NextActive(usedCts);
                if (ct) {
                    while (ct) {
                        var word = ct.GetModifiedWord();
                        if (wordWithNoSpaceBefore[word]) {
                            if (ct.token.spaceBefore) {
                                //ct.token.spaceBefore = 0;
                                ct.SetModifiedSpaceBefore(0);
                                // console.log("spaceBefore removed for word= "+ word);
                            }
                        }
                        else {
                            if (!ct.token.spaceBefore) {
                                //ct.token.spaceBefore = 1;
                                ct.SetModifiedSpaceBefore(1);
                                // console.log("spaceBefore added for word= "+ word);
                            }
                        }
                        ct = ct.NextActive(usedCts);
                    }
                }
                else {
                    debugger;
                }
            }
            else {
                debugger;
            }
        }
    }
}
const dicoLowerUpperCases = {
    "a": "A",
    "b": "B",
    "c": "C",
    "d": "D",
    "e": "E",
    "f": "F",
    "g": "G",
    "h": "H",
    "i": "I",
    "j": "J",
    "k": "K",
    "l": "L",
    "m": "M",
    "n": "N",
    "o": "O",
    "p": "P",
    "q": "Q",
    "r": "R",
    "s": "S",
    "t": "T",
    "u": "U",
    "v": "V",
    "w": "W",
    "x": "X",
    "y": "Y",
    "z": "Z",
    "é": "É",
    "è": "È",
    "à": "À",
    "ù": "Ù"
};
const dicoUpperCaseLowers = {
    "A": "a",
    "B": "b",
    "C": "c",
    "D": "d",
    "E": "e",
    "F": "f",
    "G": "g",
    "H": "h",
    "I": "i",
    "J": "j",
    "K": "k",
    "L": "l",
    "M": "m",
    "N": "n",
    "O": "o",
    "P": "p",
    "Q": "q",
    "R": "r",
    "S": "s",
    "T": "t",
    "U": "u",
    "V": "v",
    "W": "w",
    "X": "x",
    "Y": "y",
    "Z": "z",
    "É": "é",
    "È": "è",
    "À": "à",
    "Ù": "ù"
};
var wordWithNoSpaceBefore = {
    "n't": true,
    "'m": true,
    "'ve": true,
    "'re": true,
    "'s": true,
    "'ll": true,
    "'d": true,

    "n’t": true,
    "’m": true,
    "’ve": true,
    "’re": true,
    "’s": true,
    "’ll": true,
    "’d": true,

    ".": true,
    ",": true,
    ";": true,
    ":": true,
    "!": true,
    "?": true,
    "(": true,
    ")": true,
    "[": true,
    "]": true,
    "{": true,
    "}": true
};