import CircuitElement from '../circuitElement';
import simulationArea from '../simulationArea';
import { correctWidth, fillText } from '../canvasApi';
import Node, { findNode } from '../node';

// helper function to convert decimal to binary
function dec2bin(dec, bitWidth = undefined) {
    // only for positive nos
    var bin = (dec).toString(2);
    if (bitWidth == undefined) return bin;
    return '0'.repeat(bitWidth - bin.length) + bin;
}

/**
 * TestBench Output has a node for it's  input which is
 * compared to desired output according tp testData of
 * input TB Every TB_output has a uniq identifier matching
 * it's TB_Input
 * @class
 * @extends CircuitElement
 * @param {number} x - the x coord of TB
 * @param {number} y - the y coord of TB
 * @param {Scope=} scope - the circuit on which TB is drawn
 * @param {string} dir - direction
 * @param {string} identifier - id to identify tests
 * @category testbench
 */

export default class TB_Output extends CircuitElement {
    constructor(x, y, scope = globalScope, dir = 'RIGHT', identifier) {
        super(x, y, scope, dir, 1);
        // this.setDimensions(60,20);
        this.objectType = 'TB_Output';
        this.scope.TB_Output.push(this);

        // this.xSize=10;

        // this.plotValues = [];
        // this.inp1 = new Node(0, 0, 0, this);
        // this.inp1 = new Node(100, 100, 0, this);
        this.setIdentifier(identifier || 'Test1');
        this.inputs = [];
        this.testBenchInput = undefined;

        this.setup();
    }

    // TB_Output.prototype.dblclick=function(){
    //     this.testData=JSON.parse(prompt("Enter TestBench Json"));
    //     this.setup();
    // }
    setDimensions() {
        this.leftDimensionX = 0;
        this.rightDimensionX = 160;
        this.upDimensionY = 0;
        this.downDimensionY = 40;
        if (this.testBenchInput) { this.downDimensionY = 40 + this.testBenchInput.testData.outputs.length * 20; }
    }

    setup() {
        // this.iteration = 0;
        // this.running = false;
        // this.nodeList.clean(this.clockInp);
        this.deleteNodes(); // deletes all nodes whenever setup is called.
        this.nodeList = [];

        this.inputs = [];
        this.testBenchInput = undefined;
        // find it's pair input
        for (var i = 0; i < this.scope.TB_Input.length; i++) {
            if (this.scope.TB_Input[i].identifier == this.identifier) {
                this.testBenchInput = this.scope.TB_Input[i];
                break;
            }
        }

        this.setDimensions();

        if (this.testBenchInput) {
            for (var i = 0; i < this.testBenchInput.testData.outputs.length; i++) {
                this.inputs.push(new Node(0, 30 + i * 20, NODE_INPUT, this, this.testBenchInput.testData.outputs[i].bitWidth, this.testBenchInput.testData.outputs[i].label));
            }
        }
    }

    customSave() {
        var data = {
            constructorParamaters: [this.direction, this.identifier],
            nodes: {
                inputs: this.inputs.map(findNode),
            },
        };
        return data;
    }

    /**
     * @memberof TB_output
     * set identifier for this testbench
     */
    setIdentifier(id = '') {
        if (id.length == 0 || id == this.identifier) return;
        this.identifier = id;
        this.setup();
    }

    /**
     * @memberof TB_output
     * Function to check if the input for this TB exist
     */
    checkPairing(id = '') {
        if (this.testBenchInput) {
            if (this.testBenchInput.deleted || this.testBenchInput.identifier != this.identifier) {
                this.setup();
            }
        } else {
            this.setup();
        }
    }

    customDraw() {
        var ctx = simulationArea.context;
        ctx.beginPath();
        ctx.strokeStyle = 'grey';
        ctx.fillStyle = '#fcfcfc';
        ctx.lineWidth = correctWidth(1);
        var xx = this.x;
        var yy = this.y;

        var xRotate = 0;
        var yRotate = 0;
        if (this.direction == 'LEFT') {
            xRotate = 0;
            yRotate = 0;
        } else if (this.direction == 'RIGHT') {
            xRotate = 120 - this.xSize;
            yRotate = 0;
        } else if (this.direction == 'UP') {
            xRotate = 60 - this.xSize / 2;
            yRotate = -20;
        } else {
            xRotate = 60 - this.xSize / 2;
            yRotate = 20;
        }

        // rect2(ctx, -120+xRotate+this.xSize, -20+yRotate, 120-this.xSize, 40, xx, yy, "RIGHT");
        // if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this))
        //     ctx.fillStyle = "rgba(255, 255, 32,0.8)";
        // ctx.fill();
        // ctx.stroke();
        //
        // ctx.font = "14px Raleway";
        // this.xOff = ctx.measureText(this.identifier).width;
        // ctx.beginPath();
        // rect2(ctx, -105+xRotate+this.xSize, -11+yRotate,this.xOff + 10, 23, xx, yy, "RIGHT");
        // ctx.fillStyle = "#eee"
        // ctx.strokeStyle = "#ccc";
        // ctx.fill();
        // ctx.stroke();
        //


        ctx.beginPath();
        ctx.textAlign = 'center';
        ctx.fillStyle = 'black';
        fillText(ctx, `${this.identifier} [OUTPUT]`, xx + this.rightDimensionX / 2, yy + 14, 10);

        // fillText(ctx, ["Not Running","Running"][+this.running], xx + this.rightDimensionX/ 2 , yy + 14 + 10 + 20*this.testData.inputs.length, 10);
        // fillText(ctx, "Case: "+(this.iteration), xx + this.rightDimensionX/ 2 , yy + 14 + 20 + 20*this.testData.inputs.length, 10);
        fillText(ctx, ['Unpaired', 'Paired'][+(this.testBenchInput != undefined)], xx + this.rightDimensionX / 2, yy + this.downDimensionY - 5, 10);
        ctx.fill();


        if (this.testBenchInput) {
            ctx.beginPath();
            ctx.font = '30px Raleway';
            ctx.textAlign = 'left';
            ctx.fillStyle = 'blue';
            for (var i = 0; i < this.testBenchInput.testData.outputs.length; i++) {
                // ctx.beginPath();
                fillText(ctx, this.testBenchInput.testData.outputs[i].label, 5 + xx, 30 + i * 20 + yy + 4, 10);
            }
            ctx.fill();

            if (this.testBenchInput.running && this.testBenchInput.iteration) {
                ctx.beginPath();
                ctx.font = '30px Raleway';
                ctx.textAlign = 'right';
                ctx.fillStyle = 'blue';
                ctx.beginPath();
                for (var i = 0; i < this.testBenchInput.testData.outputs.length; i++) {
                    fillText(ctx, this.testBenchInput.testData.outputs[i].values[this.testBenchInput.iteration - 1], xx + this.rightDimensionX - 5, 30 + i * 20 + yy + 4, 10);
                }

                ctx.fill();
            }

            if (this.testBenchInput.running && this.testBenchInput.iteration) {
                ctx.beginPath();
                ctx.font = '30px Raleway';
                ctx.textAlign = 'center';
                ctx.fillStyle = 'blue';

                for (var i = 0; i < this.testBenchInput.testData.outputs.length; i++) {
                    if (this.inputs[i].value != undefined) {
                        ctx.beginPath();
                        if (this.testBenchInput.testData.outputs[i].values[this.testBenchInput.iteration - 1] == 'x' || parseInt(this.testBenchInput.testData.outputs[i].values[this.testBenchInput.iteration - 1], 2) == this.inputs[i].value) { ctx.fillStyle = 'green'; } else { ctx.fillStyle = 'red'; }
                        fillText(ctx, dec2bin(this.inputs[i].value, this.inputs[i].bitWidth), xx + this.rightDimensionX / 2, 30 + i * 20 + yy + 4, 10);
                        ctx.fill();
                    } else {
                        ctx.beginPath();
                        if (this.testBenchInput.testData.outputs[i].values[this.testBenchInput.iteration - 1] == 'x') { ctx.fillStyle = 'green'; } else { ctx.fillStyle = 'red'; }
                        fillText(ctx, 'X', xx + this.rightDimensionX / 2, 30 + i * 20 + yy + 4, 10);
                        ctx.fill();
                    }
                }
            }
        }
    }
}

TB_Output.prototype.tooltipText = 'Test Bench Output Selected';
TB_Output.prototype.helplink = 'https://docs.circuitverse.org/#/testbench';
TB_Output.prototype.centerElement = true;
TB_Output.prototype.mutableProperties = {
    identifier: {
        name: 'TestBench Name:',
        type: 'text',
        maxlength: '10',
        func: 'setIdentifier',
    },
};
TB_Output.prototype.objectType = 'TB_Output';
