
"use strict";

const TokenRuleConditionServices = require("./tokenRuleConditionServices");
const Overload = require('./overload');

const repeatPattern = /^{(.*),(.*)}$/;
var integerPattern = /^[0-9]{1,}$/;

module.exports = class TokenRule {
    constructor(json, condition) {
        this.rootCondition = condition;
        // default : 1
        // *       : {0,}
        // +       : {1,}
        // ?       : {0,1}
        // {x,y}   : y >= x and x>=0
        //         : x has to be defined where as y could be empty
        this.minCount = 1;
        this.maxCount = 1;
        this.matchIfNoToken = false;
        if (json.repeat) {
            var found = false;
            if (json.repeat == "*" || json.repeat == "?") {
                this.minCount = 0;
                found = true;
            }
            if (json.repeat == "*" || json.repeat == "+") {
                this.maxCount = 1.e20;
                found = true;
            }
            if (json.repeat == "noToken-1") {
                this.matchIfNoToken = true;
                found = true;
            }
            if (!found) {
                var result = json.repeat.match(integerPattern);
                if (result) {
                    if (json.repeat != "1")
                    {
                        this.minCount = parseInt(json.repeat, 10);
                        this.maxCount = this.minCount;
                    }
                }
                else {
                    result = json.repeat.match(repeatPattern);
                    if (result) {
                        if (result.length != 3) {
                            console.error("syntax don't supported for repeat attribute: " + repeat);
                            debugger;
                        }
                        else {
                            if (result[1] == "") {
                                console.error("syntax don't supported for repeat attribute: " + repeat);
                                debugger;
                            }
                            else {
                                this.minCount = parseInt(result[1], 10);
                            }
                            if (result[2] == "") {
                                this.maxCount = 1.e20;
                            }
                            else {
                                this.maxCount = parseInt(result[2], 10);
                            }
                        }
                        if (this.maxCount < this.minCount) {
                            debugger;
                        }
                    }
                }
            }
        }
        this.rememberMatch = 1;
        if (json.rememberMatch != undefined) {
            this.rememberMatch = json.rememberMatch;
        }
        if (json.useForConflict != undefined) {
            this.useForConflict = json.useForConflict;
        }
        else{
            this.useForConflict = this.rememberMatch & 1 ? 1:0;
        }
        if (json.valueIndice != undefined) {
            this.valueIndice = json.valueIndice;
        }
        if (json.valueKey != undefined) {
            this.valueKey = json.valueKey;
        }
        this.mainToken = 0;
        if (json.mainToken != undefined) {
            this.mainToken = json.mainToken;
        }
        if (json.corrections) {
            this.modifications = json.corrections;
        }
        if (json.modifications) {
            this.modifications = json.modifications;
        }
        if (this.mainToken && this.minCount != 1 && this.maxCount != 1) {
            // console.error("mainToken and (minCount,maxCount) are incompatible: ");
            // debugger;
        }
        if (json.overloads) {
            this.overloads = Overload.ConvertOverloads(json.overloads);
        }
    }
    isMinCountReached(count) {
        return count >= this.minCount;
    }
    isMaxCountReached(count) {
        return count >= this.maxCount;
    }
    AddOverloads(overloads) {
        if (this.overloads) {
            for (var i = 0; i < this.overloads.length; i++) {
                var overload = this.overloads[i];
                if (overloads.indexOf(overload) == -1) {
                    overloads.push(overload);
                }
                else {
                    break;
                }
            }
        }
    }
    AddModifications(modifications) {
        if (this.modifications) {
            for (var ci = 0; ci < this.modifications.length; ci++) {
                var modification = this.modifications[ci];
                if (modifications.indexOf(modification) == -1) {
                    modifications.push(modification);
                }
                else {
                    break;
                }
            }
        }
    }
    match(params) {
        var token = params.sentence.tokens[params.tokenIndice];
        var result = params.result;
        var tokenRuleResult = result.tokenRules[params.tokenRuleIndice];
        var status = this.rootCondition.match(token, params, tokenRuleResult);
        if (status) {
            for (var ti = 0; ti < status; ti++) {

                tokenRuleResult.tokenIndices.push(params.tokenIndice);
                if (this.useForConflict == 1) {
                        result.conflictTokenIndices.push(params.tokenIndice);
                }
                if (this.rememberMatch & 1) {
                    result.tokenIndices.push(params.tokenIndice);
                    if (this.valueIndice != undefined)
                    {
                        if (!result.valueIndices)
                        {
                            result.valueIndices = {};
                        }
                        result.valueIndices[params.tokenIndice] = this.valueIndice;
                    }
                    if (this.valueKey != undefined)
                    {
                        if (!result.valueKeys)
                        {
                            result.valueKeys = {};
                        }
                        result.valueKeys[params.tokenIndice] = this.valueKey;
                    }
                }
                if (this.rememberMatch & 2) {
                    if (!result.fTokenIndices) {
                        result.fTokenIndices = [];
                    }
                    result.fTokenIndices.push(params.tokenIndice);
                }
                if (this.mainToken) {
                    result.mainTokenIndices.push(params.tokenIndice);
                }
                params.tokenIndice++;
            }

            this.AddOverloads(tokenRuleResult.overloads);
            this.AddModifications(tokenRuleResult.modifications);
        }
        return status;
    }

    static Instanciate(ruleManager, json) {
        var rootCondition = null;
        if (json.conditionId) {
            rootCondition = ruleManager.conditions[json.conditionId];
        }
        else if (json.rootCondition) {
            rootCondition = TokenRuleConditionServices.Instanciate(ruleManager, json.rootCondition);
        }
        if (!rootCondition) {
            console.error("rootCondition is not found");
            debugger;
            return null;
        }
        var tokenRule = new TokenRule(json, rootCondition);
        return tokenRule;
    }
    static Build(ruleManager, json, dicoConditions) {
        if (json.rootCondition) {
            if (!TokenRuleConditionServices.Build(ruleManager, json.rootCondition, dicoConditions)) {
                if (json.rootCondition.conditionId) {
                    json.conditionId = json.rootCondition.conditionId;
                }
                else {
                    console.error("conditionId is not defined");
                    debugger;
                }
                delete json.rootCondition;
            }
            // else{
            //     debugger;
            // }
        }
        else {
            console.error("rootCondition is not defined");
            debugger;
        }
    }
}
