/* Copyright (c) Royal Holloway, University of London | Contact Blake Loring (blake@parsed.uk), Duncan Mitchell (Duncan.Mitchell.2015@rhul.ac.uk), or Johannes Kinder (johannes.kinder@rhul.ac.uk) for details or support | LICENSE.md for license details */

"use strict";

import iidToLocation from './Utilities/iidToLocation';

const LAST_IID = 'LAST_IID';

/**
 * Bits for coverage info propagation
 */

const IS_TOUCHED = 0x1;
const CONDITIONAL_TRUE = 0x2;
const CONDITIONAL_FALSE = 0x4;

class Coverage {

    /**
     * Creates an instance of Coverage.
     * @param {any} sandbox The Jalangi sandbox
     * _branches is an array of coverages for a given sid where the sid is branches[sid+1]
     * @memberOf Coverage
     */
    constructor(sandbox) {
        this._sandbox = sandbox;
        this._branches = [];
        this._branchFilenameMap = [];
        this._lastIid = 0; //Store the last IID touched for search strategizer
    }

    _pushLines(set, map, sid) {
        for (const nextIid in map) {
            if (!isNaN(parseInt(nextIid))) {
                const location = iidToLocation(this._sandbox, sid, nextIid);
                if (location) {
                    set.add(location.uninstrumentedLineNumber);
                }
            }
        }
    }

    end() {
        const payload = {};

        for (let i = 0; i < this._branches.length; i++) {
            
            //SID are indexed from 1 not 0
            const localSid = i + 1;

            if (this._branches[i] !== undefined) {

                //TODO: Return an Array[0,1,2] instead of 2 sets
                const touchedLines = new Set();
                const allLines = new Set();

                //Deep copy the smap
                const map = JSON.parse(JSON.stringify(this._sandbox.smap[localSid]));

                //Strip away any non SID related entities
                //Also replace all source index arrays to a single value to reduce stdout
                for (const localIid in map) {
                    if (isNaN(parseInt(localIid))) {
                        delete map[localIid];
                    } else {
                        const location = iidToLocation(this._sandbox, localSid, localIid); 
                        map[localIid] = { line: location.uninstrumentedLineNumber, column: location.uninstrumentedCharacterNumber };
                    }
                }

                this._pushLines(allLines, map, localSid);
                this._pushLines(touchedLines, this._branches[i], localSid);

                payload[this._branchFilenameMap[i]] = {
                    smap: map,
                    branches: this._branches[i],
                    lines: {
                        all: Array.from(allLines),
                        touched: Array.from(touchedLines)
                    }
                };
            }
        }

        payload[LAST_IID] = this._lastIid;

        return payload;
    }

    getBranchInfo() {

        //-1 from 1-indexed sid to start from 0
        const localIndex = this._sandbox.sid - 1;
        let branchInfo = this._branches[localIndex];

        if (!branchInfo) {
            branchInfo = {};
            this._branches[localIndex] = branchInfo;
            this._branchFilenameMap[localIndex] = this._sandbox.smap[this._sandbox.sid].originalCodeFileName;
        }

        return branchInfo;
    }

    touch(iid) {
        this.getBranchInfo()[iid] |= IS_TOUCHED;
        this._lastIid = iid;
    }

    touch_cnd(iid, result) {
        this.touch(iid);
        this.getBranchInfo()[iid] |= (result ? CONDITIONAL_TRUE : CONDITIONAL_FALSE);
    }

    last() {
        return this._lastIid || 0;
    }
}

export default Coverage;

@@ -938,344 +938,8 @@
  %7D%0A%0A
-    _pushLines(set, map, sid) %7B%0A        for (const nextIid in map) %7B%0A            if (!isNaN(parseInt(nextIid))) %7B%0A                const location = iidToLocation(this._sandbox, sid, nextIid);%0A                if (location) %7B%0A                    set.add(location.uninstrumentedLineNumber);%0A                %7D%0A            %7D%0A        %7D%0A    %7D%0A%0A
     
@@ -2068,422 +2068,126 @@
     
-this._pushLines(allLines, map, localSid);%0A                this._pushLines(touchedLines, this._branches%5Bi%5D, localSid);%0A%0A                payload%5Bthis._branchFilenameMap%5Bi%5D%5D = %7B%0A                    smap: map,%0A                    branches: this._branches%5Bi%5D,%0A                    lines: %7B%0A                        all: Array.from(allLines),%0A                        touched: Array.from(touchedLines)%0A                    %7D
+payload%5Bthis._branchFilenameMap%5Bi%5D%5D = %7B%0A                    smap: map,%0A                    branches: this._branches%5Bi%5D
 %0A   

Remove line numbers in coverage - we're going to work it out in the distributor