"use strict";
var escodegen = require('escodegen');
var estraverse = require('estraverse');
var _ = require('underscore');
var cUtils = require('./coverage-utils');
(function (BranchType) {
    BranchType[BranchType["If"] = 0] = "If";
    BranchType[BranchType["Switch"] = 1] = "Switch";
    BranchType[BranchType["TernaryOperator"] = 2] = "TernaryOperator";
    BranchType[BranchType["Unknown"] = 3] = "Unknown";
})(exports.BranchType || (exports.BranchType = {}));
var BranchType = exports.BranchType;
var CoverageBranch = (function () {
    function CoverageBranch(key, start, end, functionAST) {
        this.key = key;
        this.start = start;
        this.end = end;
        try {
            this.setBranchValue(functionAST);
        }
        catch (e) {
            throw e;
        }
    }
    CoverageBranch.prototype.setBranchValue = function (functionAST) {
        var that = this;
        estraverse.traverse(functionAST, {
            enter: function (node, parent) {
                var loc = node.loc;
                var isThisLoc;
                isThisLoc = loc.start.line === that.start.line
                    && loc.start.column === that.start.column;
                if (isThisLoc) {
                    try {
                        var branchType = null;
                        var node_ = node;
                        branchType = cUtils.getExpressionNodeNameOfBranch(node.type || '');
                        if (branchType === null && (parent !== null || parent !== undefined)) {
                            branchType = cUtils.getExpressionNodeNameOfBranch(parent.type || '');
                            node_ = parent;
                        }
                        if (branchType === null) {
                            throw new Error('Unable to get condition of branch. Type of both nodes is unknown');
                        }
                        if ((that.branchType = that.setBranchType(node_.type)) === BranchType.Unknown) {
                            throw new Error('Unknown branch type');
                        }
                        that.branchTypeToS = that.getBranchTypeToString();
                        that.conditions = [];
                        if (node_.type === 'SwitchStatement') {
                            var discriminant = escodegen.generate(node_[branchType]);
                            var indexDefaultMap = -1;
                            var indexDefault = -1;
                            var breakBeforeDefault = false;
                            var numInstructionMap = 0;
                            var entireCondition = null;
                            var pushCondition;
                            that.mapInstructionsToValues = [];
                            if (!_.isArray(node_.cases)) {
                                throw new Error('Unable to get conditions of switch. "cases" node is not an array');
                            }
                            for (var k = 0; k < node_.cases.length; k++) {
                                pushCondition = false;
                                if (node_.cases[k].test !== null) {
                                    var caseCondition = [
                                        discriminant,
                                        escodegen.generate(node_.cases[k].test)
                                    ].join(' === ');
                                    if (entireCondition === null) {
                                        entireCondition = caseCondition;
                                    }
                                    else {
                                        entireCondition = [
                                            entireCondition,
                                            caseCondition
                                        ].join(' || ');
                                    }
                                    numInstructionMap++;
                                    if (indexDefaultMap === -1) {
                                        breakBeforeDefault = cUtils.breakInTheLastNode(node_.cases[k].consequent);
                                    }
                                    if (cUtils.breakInTheLastNode(node_.cases[k].consequent)
                                        || k === (node_.cases.length - 1)) {
                                        pushCondition = true;
                                    }
                                }
                                else {
                                    indexDefaultMap = that.mapInstructionsToValues.length;
                                    indexDefault = that.conditions.length;
                                    if (cUtils.breakInTheLastNode(node_.cases[k].consequent) ||
                                        (k === (node_.cases.length - 1))) {
                                        if (entireCondition === null) {
                                            that.conditions.push('<empty>');
                                            that.mapInstructionsToValues.push(0);
                                            numInstructionMap = 0;
                                            entireCondition = null;
                                        }
                                        else {
                                            pushCondition = true;
                                        }
                                    }
                                }
                                if (pushCondition) {
                                    that.conditions.push(entireCondition);
                                    that.mapInstructionsToValues.push(numInstructionMap);
                                    numInstructionMap = 0;
                                    entireCondition = null;
                                }
                            }
                            if (indexDefault !== -1) {
                                var defaultCondition = '!(' +
                                    _.filter(that.conditions, function (i) {
                                        return (i !== '<empty>');
                                    }).join(' || ') +
                                    ')';
                                if (that.mapInstructionsToValues[indexDefaultMap] === 0) {
                                    that.conditions[indexDefault] = defaultCondition;
                                    that.mapInstructionsToValues[indexDefaultMap] = 1;
                                }
                                else if (that.mapInstructionsToValues[indexDefaultMap] >= 1) {
                                    var instruction = that.conditions[indexDefaultMap];
                                    var mapValue = that.mapInstructionsToValues[indexDefaultMap];
                                    that.conditions[indexDefault] = [
                                        instruction,
                                        defaultCondition
                                    ].join(' || ');
                                    that.mapInstructionsToValues[indexDefaultMap] = mapValue + 1;
                                }
                            }
                        }
                        else {
                            that.conditions.push(escodegen.generate(node_[branchType]));
                        }
                    }
                    catch (e) {
                        throw new Error('Unable to get condition of branch');
                    }
                }
            }
        });
    };
    CoverageBranch.prototype.initializeValues = function (branch) {
        var values = branch[this.key];
        this.nExecutions = 0;
        this.lastValueCondition = [];
        this.valuesCondition = [];
        for (var k = 0; k < values.length; k++) {
            this.lastValueCondition[k] = values[k];
        }
    };
    CoverageBranch.prototype.updateValues = function (branch) {
        var values = branch[this.key];
        this.nExecutions = this.valuesCondition.length;
    };
    CoverageBranch.prototype.getBranchTypeToString = function () {
        var branchTypeToS = (this.branchType === BranchType.If)
            ? 'IfStatement'
            : (this.branchType === BranchType.Switch)
                ? 'SwitchStatement'
                : (this.branchType === BranchType.TernaryOperator)
                    ? 'ConditionalExpression'
                    : 'Unknown';
        return branchTypeToS;
    };
    CoverageBranch.prototype.setBranchType = function (branchType) {
        var branchType_ = (branchType === 'IfStatement')
            ? BranchType.If
            : (branchType === 'SwitchStatement')
                ? BranchType.Switch
                : (branchType === 'ConditionalExpression')
                    ? BranchType.TernaryOperator
                    : BranchType.Unknown;
        return branchType_;
    };
    return CoverageBranch;
}());
exports.CoverageBranch = CoverageBranch;
