"use strict";
var IV_Table = require('./ivt');
var G_Table = require('./gt');
var MOD_Table = require('./mod');
var cUtils = require('../../context/coverage/coverage-utils');
var lpUtils = require('./loop-record-utils');
(function (LoopTable) {
    LoopTable[LoopTable["IV"] = 0] = "IV";
    LoopTable[LoopTable["GT"] = 1] = "GT";
    LoopTable[LoopTable["MOD"] = 2] = "MOD";
})(exports.LoopTable || (exports.LoopTable = {}));
var LoopTable = exports.LoopTable;
var LoopRecord = (function () {
    function LoopRecord() {
        this.activeLoops = [];
    }
    LoopRecord.prototype.addLoop = function (loopKey, loopAST) {
        var currentLoop = {};
        var loopKeyInt = parseInt(loopKey);
        currentLoop.loopKey = loopKey;
        currentLoop.iteration = 0;
        currentLoop.nStatements = cUtils.getNumberOfStatementsOfLoop(loopAST);
        if (currentLoop.nStatements === -1) {
            throw new Error(LoopRecord.ERROR_PREFIX + 'unable to get the number of statements of the loop');
        }
        currentLoop.statementsKeys = [loopKey];
        for (var k = 0; k < currentLoop.nStatements; k++) {
            currentLoop.statementsKeys.push((loopKeyInt + k + 1).toString());
        }
        this.activeLoops.push(currentLoop);
    };
    LoopRecord.prototype.isActive = function () {
        return (this.activeLoops.length > 0);
    };
    LoopRecord.prototype.addEntry = function (table, property, M, S) {
        if (!this.isActive()) {
            throw new Error(LoopRecord.ERROR_PREFIX + 'unable to add property "' + property + '" when no one loop is active');
        }
        if (table === LoopTable.IV) {
            this.activeLoops[this.activeLoops.length - 1].IVT.addEntry(property, M, S);
        }
        else if (table === LoopTable.MOD) {
            this.activeLoops[this.activeLoops.length - 1].MOD.addEntry(property, M, S);
        }
        else {
            throw new Error(LoopRecord.ERROR_PREFIX + 'unable to add property "' + property + '" on unknown table');
        }
    };
    LoopRecord.prototype.isStatementDeclaredInsideLoop = function (statementKey) {
        if (!this.isActive()) {
            return false;
        }
        var lastLoop = this.activeLoops[this.activeLoops.length - 1];
        var isStatementDeclaredInsideLoop_ = (lastLoop.statementsKeys.indexOf(statementKey) !== -1);
        return isStatementDeclaredInsideLoop_;
    };
    LoopRecord.prototype.isLastStatementDeclaredInsideLoop = function (statementKey, nextStatementKey) {
        if (!this.isActive() || nextStatementKey === null) {
            return false;
        }
        var lastLoop;
        var isLastStatement = false;
        lastLoop = this.activeLoops[this.activeLoops.length - 1];
        if (this.isStatementDeclaredInsideLoop(nextStatementKey)) {
            isLastStatement = (parseInt(statementKey) >= parseInt(nextStatementKey));
        }
        return isLastStatement;
    };
    LoopRecord.prototype.isLastIteration = function (statementKey, nextStatementKey) {
        if (!this.isActive() || nextStatementKey === null) {
            return false;
        }
        var lastLoop;
        var isLastIteration = false;
        lastLoop = this.activeLoops[this.activeLoops.length - 1];
        isLastIteration = !(this.isStatementDeclaredInsideLoop(nextStatementKey));
        return isLastIteration;
    };
    LoopRecord.prototype.incrementIteration = function () {
        if (!this.isActive()) {
            throw new Error(LoopRecord.ERROR_PREFIX + 'unable to increment the iteration of the loop when no one loop is active');
        }
        this.activeLoops[this.activeLoops.length - 1].iteration++;
    };
    LoopRecord.prototype.getIteration = function () {
        if (!this.isActive()) {
            throw new Error(LoopRecord.ERROR_PREFIX + 'unable to increment the iteration of the loop when no one loop is active');
        }
        return this.activeLoops[this.activeLoops.length - 1].iteration;
    };
    LoopRecord.prototype.deleteLoop = function () {
        if (!this.isActive()) {
            throw new Error(LoopRecord.ERROR_PREFIX + 'unable to delete the loop when no one loop is active');
        }
        this.activeLoops.pop();
    };
    LoopRecord.prototype.createTables = function () {
        if (!this.isActive()) {
            throw new Error(LoopRecord.ERROR_PREFIX + 'unable to create tables when no one loop is active');
        }
        this.activeLoops[this.activeLoops.length - 1].IVT = new IV_Table();
        this.activeLoops[this.activeLoops.length - 1].GT = new G_Table();
        this.activeLoops[this.activeLoops.length - 1].MOD = new MOD_Table();
    };
    LoopRecord.prototype.MODhasProperty = function (property) {
        if (!this.isActive()) {
            return false;
        }
        var lastLoop;
        var modHasProperty;
        lastLoop = this.activeLoops[this.activeLoops.length - 1];
        modHasProperty = lastLoop.MOD.hasProperty(property);
        return modHasProperty;
    };
    LoopRecord.prototype.echoIVT = function () {
        if (!this.isActive()) {
            throw new Error(LoopRecord.ERROR_PREFIX + 'unable to print IV table when no one loop is active');
        }
        console.log(this.activeLoops[this.activeLoops.length - 1].IVT.toString());
    };
    LoopRecord.prototype.echoGT = function () {
        if (!this.isActive()) {
            throw new Error(LoopRecord.ERROR_PREFIX + 'unable to print guard table when no one loop is active');
        }
        console.log(this.activeLoops[this.activeLoops.length - 1].GT.toString());
    };
    LoopRecord.prototype.updateIVT = function (M, S) {
        if (!this.isActive()) {
            throw new Error(LoopRecord.ERROR_PREFIX + 'unable to update the IV table when no one loop is active');
        }
        var lastLoop;
        lastLoop = this.activeLoops[this.activeLoops.length - 1];
        this.activeLoops[this.activeLoops.length - 1].IVT.update(lastLoop.iteration, M, S);
    };
    LoopRecord.prototype.updateGT = function (pc, conditionAST, valueCondition, pathConstraint, stackBranch, executedConditions, M, S, cb) {
        if (!this.isActive()) {
            cb(new Error(LoopRecord.ERROR_PREFIX + 'unable to update the guard table when no one loop is active'), null);
        }
        var lastLoop;
        lastLoop = this.activeLoops[this.activeLoops.length - 1];
        this.activeLoops[this.activeLoops.length - 1].GT.update(pc, conditionAST, valueCondition, lastLoop.iteration, pathConstraint, stackBranch, executedConditions, M, S, function (err, res) {
            if (err) {
                cb(err, null);
            }
            else {
                cb(null, res);
            }
        });
    };
    LoopRecord.prototype.guessPostconditions = function (S) {
        if (!this.isActive()) {
            throw new Error(LoopRecord.ERROR_PREFIX + 'unable to guess postconditions table when no one loop is active');
        }
        var lastLoop;
        lastLoop = this.activeLoops[this.activeLoops.length - 1];
        try {
            lpUtils.guessPostconditions(lastLoop.iteration, lastLoop.IVT, lastLoop.GT, S);
        }
        catch (e) {
            throw e;
        }
    };
    LoopRecord.ERROR_PREFIX = '[LoopRecord] Exception. Reason: ';
    return LoopRecord;
}());
exports.LoopRecord = LoopRecord;
