ConditionConnector = {
    IF:"IF",
    ELSE:"ELSE",
    AND:"AND",
    OR:"OR"
};
Ext.define('AuthorConditionChunk', {
    constructor:function (conditionChunkNode, filter) {
        this.Connector = conditionChunkNode.getAttribute('connector');
        this.TargetVariableID = conditionChunkNode.getAttribute('targetVariableID');
        this.TargetVariableIsAction = false;
        if (this.TargetVariableID.indexOf('#') == 0) {
            this.TargetVariableIsAction = true;
            this.TargetVariableID = this.TargetVariableID.substr(1);
        }

        this.Operator = conditionChunkNode.getAttribute('operator');

        this.ValueExpression = conditionChunkNode.getAttribute('valueExpression');
        this.Filter = filter;
        this.UpperCase = (this.Filter.charAt(0) == "C");
        this.WildChar = (this.Filter.charAt(1) == "W");
        this.RemoveSpace = (this.Filter.charAt(2) == "S");
        this.NumericEvaluation = (this.Filter.charAt(3) == "N");
    },
    checkTextMatch:function (value, targetValue) {
       // Author.log( Ext.String.format("Doing text comparison: {0} {1} {2}",value, this.Operator, targetValue));

        if (this.WildChar) {
            targetValue = targetValue.replace(/\*/g, ".*");
            targetValue = targetValue.replace(/\?/g, ".{1}");
            var regex = new RegExp(targetValue);
            switch (this.Operator) {
                case '{}':
                    return value.search(regex) >= 0;
                    break;
                case '=':
                    return value.search(regex) >= 0;
                    break;
                case '!=':
                    return value.search(regex) == -1;
                    break;
                default:
                    return false;
            }
        }
        else {
            switch (this.Operator) {
                case '{}':
                    return value.indexOf(targetValue) >= 0;
                    break;
                case '=':
                    return value == targetValue;
                    break;
                case '>':
                    return value > targetValue;
                    break;
                case '>=':
                    return value >= targetValue;
                    break;
                case '<':
                    return value < targetValue;
                    break;
                case '<=':
                    return value <= targetValue;
                    break;
                case '!=':
                    return value != targetValue;
                    break;
            }
        }
    },
    checkNumericMatch:function (currentValue, targetValue) {
       // Author.log( Ext.String.format("Check Numeric:{0} [{1}] {2} {3}, {4} vs {5}", this.Connector, this.TargetVariableID, this.Operator, this.ValueExpression, currentValue, targetValue));
        if (isNaN(targetValue)) {
            return (this.Operator == '!=');
        }
        else {
         //   Author.log(Ext.String.format("Doing numeric comparison: {0} {1} {2}", currentValue, this.Operator, targetValue));
           // Author.log(this.Operator);
            switch (this.Operator) {
                case '{}':
                case '=':
                    return (parseFloat(currentValue) - parseFloat(targetValue)) == 0;
                    break;
                case '>':
                    return (parseFloat(currentValue) - parseFloat(targetValue)) > 0;
                    break;
                case '>=':
                    return (parseFloat(currentValue) - parseFloat(targetValue)) >= 0;
                    break;
                case '<':
                    return (parseFloat(currentValue) - parseFloat(targetValue)) < 0;
                    break;
                case '<=':
                    return (parseFloat(currentValue) - parseFloat(targetValue)) <= 0;
                    break;
                case '!=':
                    return (parseFloat(currentValue) - parseFloat(targetValue)) != 0;
                    break;
            }
        }
    },
    isMatched:function () {
         if (this.Connector == ConditionConnector.ELSE) {
            return true;
        }
        if (this.TargetVariableIsAction) {
            currentValue = Author.VariableManager.getActionValueByActionID(this.TargetVariableID);

            if (currentValue == null) {
                currentValue = '';
            }
            targetValue = ExpressionEngine.evalExpression(this.ValueExpression);
            //  Author.log(Ext.String.format("Value: {0} vs targetValue: {1}, {2}",currentValue,targetValue,this.checkTextMatch(currentValue, targetValue)));
            if (targetValue.toLowerCase()=='true' || targetValue.toLowerCase() =='false'){
                targetValue = targetValue.toLowerCase();
            }
            if (this.UpperCase) {
                currentValue = currentValue.toUpperCase();
                targetValue = targetValue.toUpperCase();
            }
            if (this.RemoveSpace) {
                currentValue = currentValue.replace(/\s/g, '');
                targetValue = targetValue.replace(/\s/g, '');
            }
            return (this.NumericEvaluation ? this.checkNumericMatch(currentValue, targetValue) : this.checkTextMatch(currentValue, targetValue));
        }

        var thisVar = Author.VariableManager.getVariableByID(this.TargetVariableID);
        if (thisVar == null) {
            Author.log("variable [" + this.TargetVariableID + "] does not exists");
        }
        var targetValue, currentValue;

        switch (thisVar.Type) {
            case AuthorVariableTypes.Boolean:
                return thisVar.getValue();
                break;
            case AuthorVariableTypes.Numeric:

                targetValue = ExpressionEngine.evalExpression(this.ValueExpression);
                currentValue = thisVar.getValue();

                return this.checkNumericMatch(currentValue, targetValue);
                break;
            case AuthorVariableTypes.Text:
                currentValue = thisVar.getValue();
                if (currentValue == null) {
                    currentValue = '';
                }
                targetValue = ExpressionEngine.evalExpression(this.ValueExpression);
                if (this.UpperCase) {
                    currentValue = currentValue.toUpperCase();
                    targetValue = targetValue.toUpperCase();
                }
                if (this.RemoveSpace) {
                    currentValue = currentValue.replace(/\s/g, '');
                    targetValue = targetValue.replace(/\s/g, '');
                }

                return (this.NumericEvaluation ? this.checkNumericMatch(currentValue, targetValue) : this.checkTextMatch(currentValue, targetValue));
                break;
        }
    },
    toString:function () {
        if (this.Connector == ConditionConnector.ELSE) {
            return "Else";
        }
        return Ext.String.format("{0} [{1}] {2} {3}, IsMatch: {4}", this.Connector, this.TargetVariableID, this.Operator, this.ValueExpression, this.isMatched());
    }

});
Ext.define('AuthorCondition', {
    constructor:function (conditionNode) {
        this.ForResponse = conditionNode.getAttribute('forResponse').toLowerCase() == 'true';
        this.Attempt = parseInt(conditionNode.getAttribute('attempt'));
        this.Filter = conditionNode.getAttribute('filter');
        this.UpperCase = (this.Filter.charAt(0) == "C");
        this.WildChar = (this.Filter.charAt(1) == "W");
        this.RemoveSpace = (this.Filter.charAt(2) == "S");
        this.NumericEvaluation = (this.Filter.charAt(3) == "N");
        this.ConditionChunks = new Ext.util.MixedCollection();
        var chunkNodes = conditionNode.getElementsByTagName('conditionChunk');
        for (var i = 0; i < chunkNodes.length; i++) {
            this.ConditionChunks.add("C" + i, new AuthorConditionChunk(chunkNodes[i], this.Filter));
        }
    },
    isConditionMatched:function () {
        if (this.ForResponse) {
            var attempt = Author.VariableManager.getSystemVariableValue(AuthorSystemVariables.ATTEMPT, 0);
            if (this.Attempt != 0 && this.Attempt != attempt) {
                return false;
            }
        }

        if (this.getConditionKeyWord() == ConditionConnector.ELSE) {
            return true;
        }
        var result = true;

        this.ConditionChunks.each(function (conditionChunk, index, length) {
            switch (conditionChunk.Connector) {
                case ConditionConnector.IF:
                case ConditionConnector.AND:
                    result = result && conditionChunk.isMatched();
                    //Author.log(conditionChunk.toString());
                    break;
                case ConditionConnector.OR:
                    result = result || conditionChunk.isMatched();
                   // Author.log(conditionChunk.toString());
                    break;
                default:
                    alert("Else Connector. Shouldn't come to here");
            }
            //Author.log(conditionChunk + ", Result: " + result);
        }, this);

        return result;
    },
    getConditionKeyWord:function () {
        var chunkCount = this.ConditionChunks.getCount();
        if (chunkCount == 0) {
            alert("No condition chunk in condition " + this);
        }
        return this.ConditionChunks.getAt(0).Connector;
    },
    toString:function () {
        var str = "";
        this.ConditionChunks.each(function (item, index, length) {
            str += (item.toString() + "\n");
        }, this);
        str += Ext.String.format("Filter: {0}", this.Filter);
        if (this.ForResponse) {
            str += Ext.String.format(", Attempt: {0}", this.Attempt);
        }
        str += Ext.String.format("\nIsConditionMatched: {0}", this.isConditionMatched());
        return str;
    }
});
