"use strict";

const TokenRuleCondition = require('./tokenRuleCondition').TokenRuleCondition;
const TokenRuleAttCondition = require('./tokenRuleCondition').TokenRuleAttCondition;

var CalculatedTokenConditionCount = 0;

class TokenRuleConditionMacro extends TokenRuleCondition {
    constructor(json, macro) {
        super(json);
        this.macro = macro;
    }
    match(token, params,tokenRuleResult) {
        return this.addOverloads(this.macro.match(token, params, tokenRuleResult), tokenRuleResult);
    }
    ContainsMandatoryEqualCondition(att, values)
    {
        return this.macro.ContainsMandatoryEqualCondition(att, values);
    }
}
class TokenRuleConditionIsNotMacro extends TokenRuleConditionMacro {
    constructor(json, macro) {
        super(json,macro);
    }
    match(token, params,tokenRuleResult) {
        var status = this.macro.match(token, params, tokenRuleResult);
        if (status == 0)
        {
            status = 1;
        }
        else{
            status = 0;
        }
        return this.addOverloads(status, tokenRuleResult);
    }
}
class TokenRuleConditionAND extends TokenRuleCondition {
    constructor(json, conditions) {
        super(json);
        if (conditions)
        {
            this.conditions = conditions;
        }
    }
    ContainsMandatoryEqualCondition(att, values)
    {
        var prevCount = values.length;
        for (var i = 0; i < this.conditions.length; i++) {
            this.conditions[i].ContainsMandatoryEqualCondition(att, values);
            if (values.length>prevCount)
            {
                break;
            }
        }
    }
    match(token, params, tokenRuleResult) {
        var status = token.conditionResults[this.id];
        if (status != undefined) {
            // debugger;
            CalculatedTokenConditionCount++;
            return this.addOverloads(status, tokenRuleResult);
        }
        var localTokenRuleResult={
            overloads: [],
            modifications: []
        };
        var maxTokentCount = 0;
        for (var i = 0; i < this.conditions.length; i++) {
            var tokentCount = this.conditions[i].match(token, params, localTokenRuleResult);
            if (!tokentCount) {
                token.conditionResults[this.id] = 0;
                return 0;
            }
            if (maxTokentCount < tokentCount)
            {
                maxTokentCount = tokentCount;
            }
        }
        token.conditionResults[this.id] = maxTokentCount;
        this._addOverloads(tokenRuleResult.overloads, localTokenRuleResult.overloads);
        this._addCorrections(tokenRuleResult.modifications, localTokenRuleResult.modifications);
        return this.addOverloads(maxTokentCount, tokenRuleResult);
    }
}
class TokenRuleConditionOR extends TokenRuleCondition {
    constructor(json, conditions) {
        super(json);
        this.conditions = conditions;
    }
    ContainsMandatoryEqualCondition(att, values)
    {
        for (var i = 0; i < this.conditions.length; i++) {
            this.conditions[i].ContainsMandatoryEqualCondition(att, values);
        }
    }
    match(token, params, tokenRuleResult) {
        var status = token.conditionResults[this.id];
        if (status != undefined) {
            // debugger;
            CalculatedTokenConditionCount++;
            return this.addOverloads(status, tokenRuleResult);
        }
        for (var i = 0; i < this.conditions.length; i++) {

            var localTokenRuleResult = {
                overloads: [],
                modifications: []
            };
            var tokenCount = this.conditions[i].match(token, params, localTokenRuleResult);
            if (tokenCount) {
                token.conditionResults[this.id] = tokenCount;
                this._addOverloads(tokenRuleResult.overloads, localTokenRuleResult.overloads);
                this._addCorrections(tokenRuleResult.modifications, localTokenRuleResult.modifications);
                return this.addOverloads(tokenCount, tokenRuleResult);
            }
        }
        token.conditionResults[this.id] = 0;
        return 0;
    }
}
class TokenRuleConditionPhrase extends TokenRuleCondition {
    constructor(json) {
        super(json);
        if (json.attribute)
        {
            this.attribute = json.attribute;
        }
        else{
            debugger;
        }
    }
    match(token, params, tokenRuleResult) {
        var status = token.conditionResults[this.id];
        if (status == undefined) {
            var phrase = token[this.attribute];
            status = phrase == undefined ? 0 : phrase.tokenCount;
            token.conditionResults[this.id] = status;
        }
        else {
            //debugger;
            CalculatedTokenConditionCount++;
        }
        return this.addOverloads(status, tokenRuleResult);
    }
}
class TokenRuleConditionNotPhrase extends TokenRuleCondition {
    constructor(json) {
        super(json);
        if (json.attribute)
        {
            this.attribute = json.attribute;
        }
        else{
            debugger;
        }
    }
    match(token, params, tokenRuleResult) {
        var status = token.conditionResults[this.id];
        if (status == undefined) {
            var phrase = token[this.attribute];
            status = phrase == undefined ? 1 : 0;
            token.conditionResults[this.id] = status;
        }
        else {
            //debugger;
            CalculatedTokenConditionCount++;
        }
        return this.addOverloads(status, tokenRuleResult);
    }
}

class TokenRuleConditionPartOfPhrase extends TokenRuleCondition {
    constructor(json) {
        super(json);
        this.attribute = json.attribute;
    }
    match(token, params, tokenRuleResult) {
        var status = token.conditionResults[this.id];
        if (status == undefined) {
            status = 0;
            if (token.partOfPhrases)
            {
                status = token.partOfPhrases[this.attribute] ? 1:0;
            }
            token.conditionResults[this.id] = status;
        }
        else {
            //debugger;
            // CalcultedTokenConditionCount++;
        }
        return this.addOverloads(status, tokenRuleResult);
    }
}
class TokenRuleConditionNotPartOfPhrase extends TokenRuleCondition {
    constructor(json) {
        super(json);
        if (json.attribute)
        {
            this.attribute = json.attribute;
        }
        else{
            debugger;
        }
    }
    match(token, params, tokenRuleResult) {
        var status = token.conditionResults[this.id];
        if (status == undefined) {
            status = 0;
            if (token.partOfPhrases)
            {
                status = token.partOfPhrases[this.attribute] ? 0:1;
            }
            else{
                status = 1;
            }
            token.conditionResults[this.id] = status;
        }
        else {
            //debugger;
            CalculatedTokenConditionCount++;
        }
        return this.addOverloads(status, tokenRuleResult);
    }
}
class TokenRuleAttConditionExists extends TokenRuleCondition {
    constructor(json) {
        super(json);
        if (json.attribute)
        {
            this.attribute = json.attribute;
        }
        else{
            debugger;
        }
    }
    match(token, params, tokenRuleResult) {
        var status = token.conditionResults[this.id];
        if (status == undefined) {
            status = token[this.attribute] == undefined ? 0 : 1;
            token.conditionResults[this.id] = status;
        }
        else {
            //debugger;
            CalculatedTokenConditionCount++;
        }
        return this.addOverloads(status, tokenRuleResult);
    }
}
class TokenRuleAttConditionNotExists extends TokenRuleCondition {
    constructor(json) {
        super(json);
        if (json.attribute)
        {
            this.attribute = json.attribute;
        }
        else{
            debugger;
        }
    }
    match(token, params, tokenRuleResult) {
        var status = token.conditionResults[this.id];
        if (status == undefined) {
            status = token[this.attribute] == undefined ? 1 : 0;
            token.conditionResults[this.id] = status;
        }
        else {
            //debugger;
            CalculatedTokenConditionCount++;
        }
        return this.addOverloads(status, tokenRuleResult);
    }
}

class TokenRuleConditionEqual extends TokenRuleAttCondition {
    constructor(json) {
        super(json);
        if (json.value != undefined) {
            this.value = json.value;
        }
        else {
            debugger;
        }
    }
    ContainsMandatoryEqualCondition(att, values)
    {
        if (this.attribute == att)
        {
            if (values.indexOf(this.value)==-1)
            {
                values.push(this.value);
            }
        }
    }
    match(token, params, tokenRuleResult) {
        var status = token.conditionResults[this.id];
        if (status == undefined) {
            var value =  token[this.attribute];
            status = (value != undefined && value == this.value) ? 1 : 0;
            token.conditionResults[this.id] = status;
        }
        else {
            //debugger;
            CalculatedTokenConditionCount++;
        }
        return this.addOverloads(status, tokenRuleResult);
    }
}
class TokenRuleConditionNotEqual extends TokenRuleAttCondition {
    constructor(json) {
        super(json);
        if (json.value != undefined) {
            this.value = json.value;
        }
        else {
            debugger;
        }
    }
    match(token, params, tokenRuleResult) {
        var status = token.conditionResults[this.id];
        if (status == undefined) {
            var value =  token[this.attribute];
            status = (value != undefined && value != this.value) ? 1 : 0;
            token.conditionResults[this.id] = status;
        }
        else {
            // debugger;
            CalculatedTokenConditionCount++;
        }
        return this.addOverloads(status, tokenRuleResult);
    }
}
class TokenRuleConditionEqualToOtherAttribute extends TokenRuleAttCondition {
    constructor(json) {
        super(json);
        if (json.tokenAttValue) {
            this.tokenAttValue = json.tokenAttValue;
        }
        else {
            debugger;
        }
        if (json.tokenRuleIndice != undefined)
        {
            this.tokenRuleIndice = json.tokenRuleIndice;
        }
    }
    GetValue(token,params, result)
    {
        if (this.tokenRuleIndice == undefined)
        {
            result.value = token[this.tokenAttValue];
        }
        else{
            var tokenIndices = params.result.tokenRules[this.tokenRuleIndice].tokenIndices;
            if (tokenIndices)
            {
                if (tokenIndices.length)
                {
                    var otherToken = params.sentence.tokens[tokenIndices[0]];
                    result.value = otherToken[this.tokenAttValue];
                }
                else{
                    result.noToken = true;
                }
                return;
            }
            debugger;
        }
    }
    match(token, params, tokenRuleResult) {
        var status = token.conditionResults[this.id];
        if (status == undefined) {
            var result = {};
            this.GetValue(token, params, result);
            if (result.value != undefined)
            {
                var tokenValue = token[this.attribute];
                status = tokenValue != undefined && tokenValue == result.value ? 1 : 0;
            }
            else if (result.noToken)
            {
                status = 1;
            }
            else{
                status = 0;
            }
            token.conditionResults[this.id] = status;
        }
        else {
            //debugger;
            CalculatedTokenConditionCount++;
        }
        return this.addOverloads(status, tokenRuleResult);
    }
}
class TokenRuleConditionNotEqualToOtherAttribute extends TokenRuleConditionEqualToOtherAttribute {
    constructor(json) {
        super(json);
    }
    match(token, params, tokenRuleResult) {
        var status = token.conditionResults[this.id];
        if (status == undefined) {
            var result = {};
            this.GetValue(token, params, result);
            if (result.value != undefined)
            {
                var tokenValue = token[this.attribute];
                status = tokenValue != undefined && tokenValue != result.value ? 1 : 0;
            }
            else if (result.noToken)
            {
                status = 1;
            }
            else{
                status = 0;
            }
            token.conditionResults[this.id] = status;
        }
        else {
            // debugger;
            CalculatedTokenConditionCount++;
        }
        return this.addOverloads(status, tokenRuleResult);
    }
}
class TokenRuleConditionIsIn extends TokenRuleAttCondition {
    constructor(ruleManager, json) {
        super(json);
        this.values = {};
        if (json.values && json.values.length) {
            for (var vi = 0; vi < json.values.length; vi++) {
                this.values[json.values[vi]] = 1;
            }
        }
        else if (json.dictionary) {
            this.values = ruleManager.dictionaries[json.dictionary];
            if (!this.values) {
                console.error("dictionary is not in dictionaries: " + json.dictionary);
                debugger;
                this.values = {};
            }
        }
        else if (json.dictionaries) {
            for (var di = 0; di < json.dictionaries.length; di++) {
                var values = ruleManager.dictionaries[json.dictionaries[di]];
                if (!values) {
                    console.error("dictionary is not in dictionaries: " + json.dictionaries[di]);
                    debugger;
                    continue;
                }
                for (var key in values) {
                    this.values[key] = 1;
                }
            }
        }
        else {
            console.error("values or dictionary must be defined!");
            debugger;
        }
    }
    ContainsMandatoryEqualCondition(att, values)
    {
        if (att == this.attribute)
        {
            for (var key in this.values)
            {
                if (values.indexOf(key)==-1)
                {
                    values.push(key);
                }
            }
        }
    }
    match(token, params, tokenRuleResult) {
        var status = token.conditionResults[this.id];
        if (status == undefined) {
            status = this.values[token[this.attribute]];
            if (status == undefined) {
                status = 0;
            }
            else {
                status = 1;
            }
            token.conditionResults[this.id] = status;
        }
        else {
            //debugger;
            CalculatedTokenConditionCount++;
        }
        return this.addOverloads(status, tokenRuleResult);
    }
}
class TokenRuleConditionIsNotIn extends TokenRuleConditionIsIn {
    constructor(ruleManager, json) {
        super(ruleManager, json);
    }
    match(token, params, tokenRuleResult) {
        var status = token.conditionResults[this.id];
        if (status == undefined) {
            status = this.values[token[this.attribute]];
            if (status == undefined) {
                status = 1;
            }
            else {
                status = 0;
            }
            token.conditionResults[this.id] = status;
        }
        else {
            //debugger;
            CalculatedTokenConditionCount++;
        }
        return this.addOverloads(status, tokenRuleResult);
    }
}
class TokenRuleConditionRegExp extends TokenRuleAttCondition {
    constructor(json) {
        super(json);
        if (json.value!= undefined) {
            this.re = new RegExp(json.value);
        }
        else {
            debugger;
        }
    }
    match(token, params, tokenRuleResult) {
        var status = token.conditionResults[this.id];
        if (status == undefined) {
            if (!token[this.attribute]) {
                status = 0;
            }
            else {
                status = token[this.attribute].match(this.re);
                if (status == undefined) {
                    status = 0;
                }
                else {
                    status = 1;
                }
            }
        }
        else {
            CalculatedTokenConditionCount++;
        }
        return this.addOverloads(status, tokenRuleResult);
    }
}
class TokenRuleConditionNotRegExp extends TokenRuleConditionRegExp {
    constructor(json) {
        super(json);
    }
    match(token, params, tokenRuleResult) {
        var status = token.conditionResults[this.id];
        if (status == undefined) {
            if (!token[this.attribute]) {
                status = 1;
            }
            else {
                status = token[this.attribute].match(this.re);
                if (status == undefined) {
                    status = 1;
                }
                else {
                    status = 0;
                }
            }
        }
        else {
            // debugger;
            CalculatedTokenConditionCount++;
        }
        return this.addOverloads(status, tokenRuleResult);
    }
}
//
// Condition on dictionary attribute
//
class TokenRuleDicAttCondition extends TokenRuleCondition {
    constructor(ruleManager, json) {
        super(json);
        this.dicAttribute = json.dicAttribute;
        if (json.dictionary) {
            this.values = ruleManager.dictionaries[json.dictionary];
            if (!this.values) {
                console.error("dictionary is not in dictionaries: " + json.dictionary);
                debugger;
                this.values = {};
            }
        }
        else {
            console.error("dictionary must be defined!");
            debugger;
        }
        if (json.key) {
            this.key = json.key;
        }
        else {
            debugger;
        }
    }
    match(token, params, tokenRuleResult) {
        debugger;
        return 0;
    }
    GetValue(token) {
        var key = token[this.key];
        if (key != undefined) {
            var data = this.values[key];
            if (data != undefined) {
                return data[this.dicAttribute];
            }
            else if (!this.ifExists){    
                console.error("att is not defined in dictionary key= " + key + " dicAttribute= " + this.dicAttribute);
                debugger;
            }
        }
        else {
            console.error("key is not in token key= " + key);
            debugger;
        }
        //debugger;
        return undefined;
    }
}
class TokenRuleDicAttConditionEqual extends TokenRuleDicAttCondition {
    constructor(ruleManager, json) {
        super(ruleManager, json);
        if (json.value!= undefined) {
            this.value = json.value;
        }
        else {
            debugger;
        }
    }
    match(token, params, tokenRuleResult) {
        var status = token.conditionResults[this.id];
        if (status == undefined) {
            var value = this.GetValue(token);
            if (value != undefined) {
                if (this.value != undefined)
                {
                    status = value == this.value ? 1 : 0;
                }
                else{
                    status = 0;
                }
            }
            else {
                status = 0;
            }
            token.conditionResults[this.id] = status;
        }
        else {
            //debugger;
            CalculatedTokenConditionCount++;
        }
        return this.addOverloads(status, tokenRuleResult);
    }
}
class TokenRuleDicAttConditionNotEqual extends TokenRuleDicAttCondition {
    constructor(ruleManager, json) {
        super(ruleManager, json);
        if (json.value!= undefined) {
            this.value = json.value;
        }
        else {
            debugger;
        }
    }
    match(token, params, tokenRuleResult) {
        var status = token.conditionResults[this.id];
        if (status == undefined) {
            var value = this.GetValue(token);
            if (value != undefined) {
                if (this.value != undefined)
                {
                    status = value != this.value ? 1 : 0;
                }
                else{
                    status = 0;
                }
            }
            else {
                status = 1;
            }
            token.conditionResults[this.id] = status;
        }
        else {
            // debugger;
            CalculatedTokenConditionCount++;
        }
        return this.addOverloads(status, tokenRuleResult);
    }
}
class TokenRuleDicAttConditionRegExp extends TokenRuleDicAttCondition {
    constructor(ruleManager, json) {
        super(ruleManager, json);
        if (json.value!= undefined) {
            this.re = new RegExp(json.value);
        }
        else {
            debugger;
        }
    }
    match(token, params, tokenRuleResult) {
        var status = token.conditionResults[this.id];
        if (status == undefined) {
            var value = this.GetValue(token);
            if (value != undefined) {
                status = value.match(this.re);
                if (status == undefined) {
                    status = 0;
                }
                else {
                    status = 1;
                }
            }
            else {
                status = 0;
            }
            token.conditionResults[this.id] = status;
        }
        else {
            CalculatedTokenConditionCount++;
        }
        return this.addOverloads(status, tokenRuleResult);
    }
}
class TokenRuleDicAttConditionNotRegExp extends TokenRuleDicAttConditionRegExp {
    constructor(ruleManager, json) {
        super(ruleManager, json);
    }
    match(token, params, tokenRuleResult) {
        var status = token.conditionResults[this.id];
        if (status == undefined) {
            var value = this.GetValue(token);
            if (value != undefined) {
                status = value.match(this.re);
                if (status == undefined) {
                    status = 1;
                }
                else {
                    status = 0;
                }
            }
            else {
                status = 1;
            }
            token.conditionResults[this.id] = status;
        }
        else {
            // debugger;
            CalculatedTokenConditionCount++;
        }
        return this.addOverloads(status, tokenRuleResult);
    }
}
class TokenRuleDicAttEqualToTokenAtt extends TokenRuleDicAttCondition {
    constructor(ruleManager, json) {
        super(ruleManager, json);
        if (json.attribute) {
            this.attribute = json.attribute;
        }
        else {
            debugger;
        }
        if (json.ifExists)
        {
            this.ifExists = json.ifExists;
        }
    }
    match(token, params, tokenRuleResult) {
        var status = token.conditionResults[this.id];
        if (status == undefined) {
            var value = this.GetValue(token);
            if (value != undefined) {
                var tokenValue = token[this.attribute];
                if (tokenValue != undefined)
                {
                    status = value == tokenValue ? 1 : 0;
                }
                else{
                    status = 0;
                }
            }
            else {
                status = 0;
            }
            token.conditionResults[this.id] = status;
        }
        else {
            //debugger;
            CalculatedTokenConditionCount++;
        }
        return this.addOverloads(status, tokenRuleResult);
    }
}
class TokenRuleDicAttNotEqualToTokenAtt extends TokenRuleDicAttCondition {
    constructor(ruleManager, json) {
        super(ruleManager, json);
        if (json.attribute) {
            this.attribute = json.attribute;
        }
        else {
            debugger;
        }
        if (json.ifExists)
        {
            this.ifExists = json.ifExists;
        }
    }
    match(token, params, tokenRuleResult) {
        var status = token.conditionResults[this.id];
        if (status == undefined) {
            var value = this.GetValue(token);
            if (value != undefined) {
                var tokenValue = token[this.attribute];
                if (tokenValue != undefined)
                {
                    status = value != tokenValue ? 1 : 0;
                }
                else{
                    status = 0;
                }
            }
            else {
                status = 0;
            }
            token.conditionResults[this.id] = status;
        }
        else {
            // debugger;
            CalculatedTokenConditionCount++;
        }
        return this.addOverloads(status, tokenRuleResult);
    }
}
module.exports = {
    TokenRuleConditionMacro: TokenRuleConditionMacro,
    TokenRuleConditionIsNotMacro: TokenRuleConditionIsNotMacro,
    TokenRuleConditionEqual: TokenRuleConditionEqual,
    TokenRuleConditionEqualToOtherAttribute: TokenRuleConditionEqualToOtherAttribute,
    TokenRuleConditionNotEqual: TokenRuleConditionNotEqual,
    TokenRuleConditionNotEqualToOtherAttribute: TokenRuleConditionNotEqualToOtherAttribute,
    TokenRuleConditionRegExp: TokenRuleConditionRegExp,
    TokenRuleConditionNotRegExp: TokenRuleConditionNotRegExp,
    TokenRuleConditionIsIn: TokenRuleConditionIsIn,
    TokenRuleConditionIsNotIn: TokenRuleConditionIsNotIn,
    TokenRuleAttConditionExists: TokenRuleAttConditionExists,
    TokenRuleAttConditionNotExists: TokenRuleAttConditionNotExists,
    TokenRuleConditionPhrase: TokenRuleConditionPhrase,
    TokenRuleConditionNotPhrase: TokenRuleConditionNotPhrase,
    TokenRuleConditionPartOfPhrase: TokenRuleConditionPartOfPhrase,
    TokenRuleConditionNotPartOfPhrase: TokenRuleConditionNotPartOfPhrase,
    TokenRuleDicAttConditionEqual: TokenRuleDicAttConditionEqual,
    TokenRuleDicAttConditionNotEqual: TokenRuleDicAttConditionNotEqual,
    TokenRuleDicAttConditionRegExp: TokenRuleDicAttConditionRegExp,
    TokenRuleDicAttConditionNotRegExp: TokenRuleDicAttConditionNotRegExp,
    TokenRuleDicAttEqualToTokenAtt: TokenRuleDicAttEqualToTokenAtt,
    TokenRuleDicAttNotEqualToTokenAtt: TokenRuleDicAttNotEqualToTokenAtt,
    TokenRuleConditionAND: TokenRuleConditionAND,
    TokenRuleConditionOR: TokenRuleConditionOR
};
