//AndGate - (x,y)-position , scope - circuit level, inputLength - no of nodes, dir - direction of gate

function changeInputSize(size) {
    if (size == undefined || size < 2 || size > 10) return;
    if (this.inputSize == size) return;
    size = parseInt(size, 10)
    var obj = new window[this.objectType](this.x, this.y, this.scope, this.direction, size, this.bitWidth);
    this.delete();
    simulationArea.lastSelected = obj;
    return obj;
    // showProperties(obj);

}

function AndGate(x, y, scope = globalScope, dir = "RIGHT", inputLength = 2, bitWidth = 1) {

    CircuitElement.call(this, x, y, scope, dir, bitWidth);
    this.rectangleObject = false;
    this.setDimensions(15, 20);
    this.inp = [];

    this.inputSize = inputLength;


    //variable inputLength , node creation
    if (inputLength % 2 == 1) {
        for (var i = 0; i < inputLength / 2 - 1; i++) {
            var a = new Node(-10, -10 * (i + 1), 0, this);
            this.inp.push(a);
        }
        var a = new Node(-10, 0, 0, this);
        this.inp.push(a);
        for (var i = inputLength / 2 + 1; i < inputLength; i++) {
            var a = new Node(-10, 10 * (i + 1 - inputLength / 2 - 1), 0, this);
            this.inp.push(a);
        }
    } else {
        for (var i = 0; i < inputLength / 2; i++) {
            var a = new Node(-10, -10 * (i + 1), 0, this);
            this.inp.push(a);
        }
        for (var i = inputLength / 2; i < inputLength; i++) {
            var a = new Node(-10, 10 * (i + 1 - inputLength / 2), 0, this);
            this.inp.push(a);
        }
    }

    this.output1 = new Node(20, 0, 1, this);


}

AndGate.prototype = Object.create(CircuitElement.prototype);
AndGate.prototype.constructor = AndGate;
AndGate.prototype.tooltipText = "And Gate Tooltip : Implements logical conjunction";
AndGate.prototype.changeInputSize = changeInputSize;
AndGate.prototype.alwaysResolve = true;
AndGate.prototype.verilogType = "and";
AndGate.prototype.helplink = "https://docs.circuitverse.org/#/gates?id=and-gate";
//fn to create save Json Data of object
AndGate.prototype.customSave = function () {
    var data = {
        constructorParamaters: [this.direction, this.inputSize, this.bitWidth],
        nodes: {
            inp: this.inp.map(findNode),
            output1: findNode(this.output1)
        },
    }
    return data;
}

//resolve output values based on inputData
AndGate.prototype.resolve = function () {
    var result = this.inp[0].value || 0;
    if (this.isResolvable() == false) {
        return;
    }
    for (var i = 1; i < this.inputSize; i++)
        result = result & ((this.inp[i].value) || 0);
    this.output1.value = result;
    simulationArea.simulationQueue.add(this.output1);
}

//fn to draw
AndGate.prototype.customDraw = function () {

    ctx = simulationArea.context;

    ctx.beginPath();
    ctx.lineWidth = correctWidth(3);
    ctx.strokeStyle = "black"; //("rgba(0,0,0,1)");
    ctx.fillStyle = "white";
    var xx = this.x;
    var yy = this.y;

    moveTo(ctx, -10, -20, xx, yy, this.direction);
    lineTo(ctx, 0, -20, xx, yy, this.direction);
    arc(ctx, 0, 0, 20, (-Math.PI / 2), (Math.PI / 2), xx, yy, this.direction);
    lineTo(ctx, -10, 20, xx, yy, this.direction);
    lineTo(ctx, -10, -20, xx, yy, this.direction);
    ctx.closePath();

    if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";
    ctx.fill();
    ctx.stroke();

}
//translate to gate for single bit, assign for multi bit
AndGate.prototype.generateVerilog = function () {
    return gateGenerateVerilog.call(this, '&');
}


function NandGate(x, y, scope = globalScope, dir = "RIGHT", inputLength = 2, bitWidth = 1) {
    CircuitElement.call(this, x, y, scope, dir, bitWidth);
    this.rectangleObject = false;
    this.setDimensions(15, 20);
    this.inp = [];


    this.inputSize = inputLength;


    //variable inputLength , node creation
    if (inputLength % 2 == 1) {
        for (var i = 0; i < inputLength / 2 - 1; i++) {
            var a = new Node(-10, -10 * (i + 1), 0, this);
            this.inp.push(a);
        }
        var a = new Node(-10, 0, 0, this);
        this.inp.push(a);
        for (var i = inputLength / 2 + 1; i < inputLength; i++) {
            var a = new Node(-10, 10 * (i + 1 - inputLength / 2 - 1), 0, this);
            this.inp.push(a);
        }
    } else {
        for (var i = 0; i < inputLength / 2; i++) {
            var a = new Node(-10, -10 * (i + 1), 0, this);
            this.inp.push(a);
        }
        for (var i = inputLength / 2; i < inputLength; i++) {
            var a = new Node(-10, 10 * (i + 1 - inputLength / 2), 0, this);
            this.inp.push(a);
        }
    }

    this.output1 = new Node(30, 0, 1, this);


}
NandGate.prototype = Object.create(CircuitElement.prototype);
NandGate.prototype.constructor = NandGate;
NandGate.prototype.tooltipText = "Nand Gate ToolTip : Combination of AND and NOT gates";
NandGate.prototype.alwaysResolve = true;
NandGate.prototype.changeInputSize = changeInputSize;
NandGate.prototype.verilogType = "nand";
NandGate.prototype.helplink = "https://docs.circuitverse.org/#/gates?id=nand-gate";
//fn to create save Json Data of object
NandGate.prototype.customSave = function () {
    var data = {

        constructorParamaters: [this.direction, this.inputSize, this.bitWidth],
        nodes: {
            inp: this.inp.map(findNode),
            output1: findNode(this.output1)
        },
    }
    return data;
}
//resolve output values based on inputData
NandGate.prototype.resolve = function () {
    var result = this.inp[0].value || 0;
    if (this.isResolvable() == false) {
        return;
    }
    for (var i = 1; i < this.inputSize; i++)
        result = result & (this.inp[i].value || 0);
    result = ((~result >>> 0) << (32 - this.bitWidth)) >>> (32 - this.bitWidth);
    this.output1.value = result;
    simulationArea.simulationQueue.add(this.output1);
}
//fn to draw
NandGate.prototype.customDraw = function () {

    ctx = simulationArea.context;
    ctx.beginPath();
    ctx.lineWidth = correctWidth(3);
    ctx.strokeStyle = "black";
    ctx.fillStyle = "white";
    var xx = this.x;
    var yy = this.y;

    moveTo(ctx, -10, -20, xx, yy, this.direction);
    lineTo(ctx, 0, -20, xx, yy, this.direction);
    arc(ctx, 0, 0, 20, (-Math.PI / 2), (Math.PI / 2), xx, yy, this.direction);
    lineTo(ctx, -10, 20, xx, yy, this.direction);
    lineTo(ctx, -10, -20, xx, yy, this.direction);
    ctx.closePath();

    if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.5)";
    ctx.fill();
    ctx.stroke();
    ctx.beginPath();
    drawCircle2(ctx, 25, 0, 5, xx, yy, this.direction);
    ctx.stroke();


}
//translate to gate for single bit, assign for multi bit
NandGate.prototype.generateVerilog = function () {
    return gateGenerateVerilog.call(this, '&', true);
}


function Multiplexer(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1, controlSignalSize = 1) {
    // //console.log("HIT");
    // //console.log(x,y,scope,dir,bitWidth,controlSignalSize);
    CircuitElement.call(this, x, y, scope, dir, bitWidth);

    this.controlSignalSize = controlSignalSize || parseInt(prompt("Enter control signal bitWidth"), 10);
    this.inputSize = 1 << this.controlSignalSize;
    this.xOff = 0;
    this.yOff = 1;
    if (this.controlSignalSize == 1) {
        this.xOff = 10;
    }
    if (this.controlSignalSize <= 3) {
        this.yOff = 2;
    }

    this.setDimensions(20 - this.xOff, this.yOff * 5 * (this.inputSize));
    this.rectangleObject = false;

    this.inp = [];
    for (var i = 0; i < this.inputSize; i++) {
        var a = new Node(-20 + this.xOff, +this.yOff * 10 * (i - this.inputSize / 2) + 10, 0, this);
        this.inp.push(a);
    }

    this.output1 = new Node(20 - this.xOff, 0, 1, this);
    this.controlSignalInput = new Node(0, this.yOff * 10 * (this.inputSize / 2 - 1) + this.xOff + 10, 0, this, this.controlSignalSize, "Control Signal");



}
Multiplexer.prototype = Object.create(CircuitElement.prototype);
Multiplexer.prototype.constructor = Multiplexer;
Multiplexer.prototype.tooltipText = "Multiplexer ToolTip : Multiple inputs and a single line output.";
Multiplexer.prototype.helplink = "https://docs.circuitverse.org/#/decodersandplexers?id=multiplexer";
Multiplexer.prototype.changeControlSignalSize = function (size) {
    if (size == undefined || size < 1 || size > 8) return;
    if (this.controlSignalSize == size) return;
    var obj = new window[this.objectType](this.x, this.y, this.scope, this.direction, this.bitWidth, size);
    this.cleanDelete();
    simulationArea.lastSelected = obj;
    return obj;
}
Multiplexer.prototype.mutableProperties = {
    "controlSignalSize": {
        name: "Control Signal Size",
        type: "number",
        max: "8",
        min: "1",
        func: "changeControlSignalSize",
    },
}
Multiplexer.prototype.newBitWidth = function (bitWidth) {
    this.bitWidth = bitWidth;
    for (var i = 0; i < this.inputSize; i++) {
        this.inp[i].bitWidth = bitWidth
    }
    this.output1.bitWidth = bitWidth;
}
//fn to create save Json Data of object
Multiplexer.prototype.isResolvable = function () {
    if (this.controlSignalInput.value != undefined && this.inp[this.controlSignalInput.value].value != undefined) return true;
    return false;
}
Multiplexer.prototype.customSave = function () {
    var data = {
        constructorParamaters: [this.direction, this.bitWidth, this.controlSignalSize],
        nodes: {
            inp: this.inp.map(findNode),
            output1: findNode(this.output1),
            controlSignalInput: findNode(this.controlSignalInput)
        },
    }
    return data;
}
Multiplexer.prototype.resolve = function () {

    if (this.isResolvable() == false) {
        return;
    }
    this.output1.value = this.inp[this.controlSignalInput.value].value;
    simulationArea.simulationQueue.add(this.output1);
}
Multiplexer.prototype.customDraw = function () {

    ctx = simulationArea.context;

    var xx = this.x;
    var yy = this.y;

    ctx.beginPath();
    moveTo(ctx, 0, this.yOff * 10 * (this.inputSize / 2 - 1) + 10 + 0.5 * this.xOff, xx, yy, this.direction);
    lineTo(ctx, 0, this.yOff * 5 * (this.inputSize - 1) + this.xOff, xx, yy, this.direction);
    ctx.stroke();

    ctx.lineWidth = correctWidth(3);
    ctx.beginPath();
    ctx.strokeStyle = ("rgba(0,0,0,1)");

    ctx.fillStyle = "white";
    moveTo(ctx, -20 + this.xOff, -this.yOff * 10 * (this.inputSize / 2), xx, yy, this.direction);
    lineTo(ctx, -20 + this.xOff, 20 + this.yOff * 10 * (this.inputSize / 2 - 1), xx, yy, this.direction);
    lineTo(ctx, 20 - this.xOff, +this.yOff * 10 * (this.inputSize / 2 - 1) + this.xOff, xx, yy, this.direction);
    lineTo(ctx, 20 - this.xOff, -this.yOff * 10 * (this.inputSize / 2) - this.xOff + 20, xx, yy, this.direction);

    ctx.closePath();
    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.beginPath();
    // ctx.lineWidth = correctWidth(2);
    ctx.fillStyle = "black";
    ctx.textAlign = "center";
    for (var i = 0; i < this.inputSize; i++) {

        if (this.direction == "RIGHT") fillText(ctx, String(i), xx + this.inp[i].x + 7, yy + this.inp[i].y + 2, 10);
        else if (this.direction == "LEFT") fillText(ctx, String(i), xx + this.inp[i].x - 7, yy + this.inp[i].y + 2, 10);
        else if (this.direction == "UP") fillText(ctx, String(i), xx + this.inp[i].x, yy + this.inp[i].y - 4, 10);
        else fillText(ctx, String(i), xx + this.inp[i].x, yy + this.inp[i].y + 10, 10);
    }
    ctx.fill();
}

Multiplexer.prototype.verilogBaseType = function() {
    return this.verilogName() + this.inp.length;
}

//this code to generate Verilog
Multiplexer.prototype.generateVerilog = function () {
    Multiplexer.selSizes.add(this.controlSignalSize);
    return CircuitElement.prototype.generateVerilog.call(this);
}
//This code to determine what sizes are used to generate the needed modules
Multiplexer.selSizes = new Set();
//generate the needed modules
Multiplexer.moduleVerilog = function () {
    var output = "";

    for (var size of Multiplexer.selSizes) {
        var numInput = 1 << size;
        var inpString = "";
        for (var j = 0; j < numInput; j++) {
            inpString += `in${j}, `;
        }
        output += `\nmodule Multiplexer${numInput}(out, ${inpString}sel);\n`;

        output += "  parameter WIDTH = 1;\n";
        output += "  output reg [WIDTH-1:0] out;\n";

        output += "  input [WIDTH-1:0] "
        for (var j = 0; j < numInput-1; j++) {
            output += `in${j}, `;
        }
        output += "in" + (numInput-1) + ";\n";

        output += `  input [${size-1}:0] sel;\n`;
        output += "  \n";

        output += "  always @ (*)\n";
        output += "    case (sel)\n";
        for (var j = 0; j < numInput; j++) {
            output += `      ${j} : out = in${j};\n`;
        }
        output += "    endcase\n";
        output += "endmodule\n";
        output += "\n";
    }

    return output;
}
//reset the sized before Verilog generation
Multiplexer.resetVerilog = function () {
    Multiplexer.selSizes = new Set();
}

function XorGate(x, y, scope = globalScope, dir = "RIGHT", inputs = 2, bitWidth = 1) {
    CircuitElement.call(this, x, y, scope, dir, bitWidth);
    this.rectangleObject = false;
    this.setDimensions(15, 20);

    this.inp = [];
    this.inputSize = inputs;

    if (inputs % 2 == 1) {
        for (var i = 0; i < inputs / 2 - 1; i++) {
            var a = new Node(-20, -10 * (i + 1), 0, this);
            this.inp.push(a);
        }
        var a = new Node(-20, 0, 0, this);
        this.inp.push(a);
        for (var i = inputs / 2 + 1; i < inputs; i++) {
            var a = new Node(-20, 10 * (i + 1 - inputs / 2 - 1), 0, this);
            this.inp.push(a);
        }
    } else {
        for (var i = 0; i < inputs / 2; i++) {
            var a = new Node(-20, -10 * (i + 1), 0, this);
            this.inp.push(a);
        }
        for (var i = inputs / 2; i < inputs; i++) {
            var a = new Node(-20, 10 * (i + 1 - inputs / 2), 0, this);
            this.inp.push(a);
        }
    }
    this.output1 = new Node(20, 0, 1, this);

}

XorGate.prototype = Object.create(CircuitElement.prototype);
XorGate.prototype.constructor = XorGate;
XorGate.prototype.tooltipText = "Xor Gate Tooltip : Implements an exclusive OR.";
XorGate.prototype.alwaysResolve = true;

XorGate.prototype.changeInputSize = changeInputSize;
XorGate.prototype.verilogType = "xor";
XorGate.prototype.helplink = "https://docs.circuitverse.org/#/gates?id=xor-gate";
XorGate.prototype.customSave = function () {
    // //console.log(this.scope.allNodes);
    var data = {
        constructorParamaters: [this.direction, this.inputSize, this.bitWidth],
        nodes: {
            inp: this.inp.map(findNode),
            output1: findNode(this.output1)
        },
    }
    return data;
}
XorGate.prototype.resolve = function () {
    var result = this.inp[0].value || 0;
    if (this.isResolvable() == false) {
        return;
    }
    for (var i = 1; i < this.inputSize; i++)
        result = result ^ (this.inp[i].value || 0);

    this.output1.value = result;
    simulationArea.simulationQueue.add(this.output1);
}
XorGate.prototype.customDraw = function () {

    ctx = simulationArea.context;
    ctx.strokeStyle = ("rgba(0,0,0,1)");
    ctx.lineWidth = correctWidth(3);

    var xx = this.x;
    var yy = this.y;
    ctx.beginPath();
    ctx.fillStyle = "white";
    moveTo(ctx, -10, -20, xx, yy, this.direction, true);
    bezierCurveTo(0, -20, +15, -10, 20, 0, xx, yy, this.direction);
    bezierCurveTo(0 + 15, 0 + 10, 0, 0 + 20, -10, +20, xx, yy, this.direction);
    bezierCurveTo(0, 0, 0, 0, -10, -20, xx, yy, this.direction);
    // arc(ctx, 0, 0, -20, (-Math.PI / 2), (Math.PI / 2), xx, yy, this.direction);
    ctx.closePath();
    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.beginPath();
    arc2(ctx, -35, 0, 25, 1.70 * (Math.PI), 0.30 * (Math.PI), xx, yy, this.direction);
    ctx.stroke();


}
//translate to gate for single bit, assign for multi bit
XorGate.prototype.generateVerilog = function () {
    return gateGenerateVerilog.call(this, '^');
}



function XnorGate(x, y, scope = globalScope, dir = "RIGHT", inputs = 2, bitWidth = 1) {
    CircuitElement.call(this, x, y, scope, dir, bitWidth);
    this.rectangleObject = false;
    this.setDimensions(15, 20);

    this.inp = [];
    this.inputSize = inputs;

    if (inputs % 2 == 1) {
        for (var i = 0; i < inputs / 2 - 1; i++) {
            var a = new Node(-20, -10 * (i + 1), 0, this);
            this.inp.push(a);
        }
        var a = new Node(-20, 0, 0, this);
        this.inp.push(a);
        for (var i = inputs / 2 + 1; i < inputs; i++) {
            var a = new Node(-20, 10 * (i + 1 - inputs / 2 - 1), 0, this);
            this.inp.push(a);
        }
    } else {
        for (var i = 0; i < inputs / 2; i++) {
            var a = new Node(-20, -10 * (i + 1), 0, this);
            this.inp.push(a);
        }
        for (var i = inputs / 2; i < inputs; i++) {
            var a = new Node(-20, 10 * (i + 1 - inputs / 2), 0, this);
            this.inp.push(a);
        }
    }
    this.output1 = new Node(30, 0, 1, this);

}

XnorGate.prototype = Object.create(CircuitElement.prototype);
XnorGate.prototype.constructor = XnorGate;
XnorGate.prototype.alwaysResolve = true;
XnorGate.prototype.tooltipText = "Xnor Gate ToolTip : Logical complement of the XOR gate";
XnorGate.prototype.changeInputSize = changeInputSize;
XnorGate.prototype.verilogType = "xnor";
XnorGate.prototype.helplink = "https://docs.circuitverse.org/#/gates?id=xnor-gate";
XnorGate.prototype.customSave = function () {
    var data = {
        constructorParamaters: [this.direction, this.inputSize, this.bitWidth],
        nodes: {
            inp: this.inp.map(findNode),
            output1: findNode(this.output1)
        },
    }
    return data;
}
XnorGate.prototype.resolve = function () {
    var result = this.inp[0].value || 0;
    if (this.isResolvable() == false) {
        return;
    }
    for (var i = 1; i < this.inputSize; i++)
        result = result ^ (this.inp[i].value || 0);
    result = ((~result >>> 0) << (32 - this.bitWidth)) >>> (32 - this.bitWidth);
    this.output1.value = result;
    simulationArea.simulationQueue.add(this.output1);
}
XnorGate.prototype.customDraw = function () {

    ctx = simulationArea.context;
    ctx.strokeStyle = ("rgba(0,0,0,1)");
    ctx.lineWidth = correctWidth(3);

    var xx = this.x;
    var yy = this.y;
    ctx.beginPath();
    ctx.fillStyle = "white";
    moveTo(ctx, -10, -20, xx, yy, this.direction, true);
    bezierCurveTo(0, -20, +15, -10, 20, 0, xx, yy, this.direction);
    bezierCurveTo(0 + 15, 0 + 10, 0, 0 + 20, -10, +20, xx, yy, this.direction);
    bezierCurveTo(0, 0, 0, 0, -10, -20, xx, yy, this.direction);
    // arc(ctx, 0, 0, -20, (-Math.PI / 2), (Math.PI / 2), xx, yy, this.direction);
    ctx.closePath();
    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.beginPath();
    arc2(ctx, -35, 0, 25, 1.70 * (Math.PI), 0.30 * (Math.PI), xx, yy, this.direction);
    ctx.stroke();
    ctx.beginPath();
    drawCircle2(ctx, 25, 0, 5, xx, yy, this.direction);
    ctx.stroke();

}
//translate to gate for single bit, assign for multi bit
XnorGate.prototype.generateVerilog = function () {
    return gateGenerateVerilog.call(this,'^', true);
}



function SevenSegDisplay(x, y, scope = globalScope) {
    CircuitElement.call(this, x, y, scope, "RIGHT", 1);
    this.fixedBitWidth = true;
    this.directionFixed = true;
    this.setDimensions(30, 50);

    this.g = new Node(-20, -50, 0, this);
    this.f = new Node(-10, -50, 0, this);
    this.a = new Node(+10, -50, 0, this);
    this.b = new Node(+20, -50, 0, this);
    this.e = new Node(-20, +50, 0, this);
    this.d = new Node(-10, +50, 0, this);
    this.c = new Node(+10, +50, 0, this);
    this.dot = new Node(+20, +50, 0, this);
    this.direction = "RIGHT";


}
SevenSegDisplay.prototype = Object.create(CircuitElement.prototype);
SevenSegDisplay.prototype.constructor = SevenSegDisplay;
SevenSegDisplay.prototype.tooltipText = "Seven Display ToolTip: Consists of 7+1 single bit inputs.";
SevenSegDisplay.prototype.helplink = "https://docs.circuitverse.org/#/outputs?id=seven-segment-display";
SevenSegDisplay.prototype.customSave = function () {
    var data = {

        nodes: {
            g: findNode(this.g),
            f: findNode(this.f),
            a: findNode(this.a),
            b: findNode(this.b),
            d: findNode(this.d),
            e: findNode(this.e),
            c: findNode(this.c),
            d: findNode(this.d),
            dot: findNode(this.dot)
        },
    }
    return data;
}
SevenSegDisplay.prototype.customDrawSegment = function (x1, y1, x2, y2, color) {
    if (color == undefined) color = "lightgrey";
    ctx = simulationArea.context;
    ctx.beginPath();
    ctx.strokeStyle = color;
    ctx.lineWidth = correctWidth(5);
    xx = this.x;
    yy = this.y;
    moveTo(ctx, x1, y1, xx, yy, this.direction);
    lineTo(ctx, x2, y2, xx, yy, this.direction);
    ctx.closePath();
    ctx.stroke();
}

SevenSegDisplay.prototype.customDraw = function () {
    ctx = simulationArea.context;

    var xx = this.x;
    var yy = this.y;

    this.customDrawSegment(18, -3, 18, -38, ["lightgrey", "red"][this.b.value]);
    this.customDrawSegment(18, 3, 18, 38, ["lightgrey", "red"][this.c.value]);
    this.customDrawSegment(-18, -3, -18, -38, ["lightgrey", "red"][this.f.value]);
    this.customDrawSegment(-18, 3, -18, 38, ["lightgrey", "red"][this.e.value]);
    this.customDrawSegment(-17, -38, 17, -38, ["lightgrey", "red"][this.a.value]);
    this.customDrawSegment(-17, 0, 17, 0, ["lightgrey", "red"][this.g.value]);
    this.customDrawSegment(-15, 38, 17, 38, ["lightgrey", "red"][this.d.value]);

    ctx.beginPath();
    var dotColor = ["lightgrey", "red"][this.dot.value] || "lightgrey"
    ctx.strokeStyle = dotColor;
    rect(ctx, xx + 22, yy + 42, 2, 2);
    ctx.stroke();
}
SevenSegDisplay.prototype.generateVerilog = function () {
    return `
  always @ (*)
    $display("SevenSegDisplay:${this.verilogLabel}.abcdefg. = %b%b%b%b%b%b%b%b}",
             ${this.a.verilogLabel}, ${this.b.verilogLabel}, ${this.c.verilogLabel}, ${this.d.verilogLabel}, ${this.e.verilogLabel}, ${this.f.verilogLabel}, ${this.g.verilogLabel}, ${this.dot.verilogLabel});`;
}

function SixteenSegDisplay(x, y, scope = globalScope) {
    CircuitElement.call(this, x, y, scope, "RIGHT", 16);
    this.fixedBitWidth = true;
    this.directionFixed = true;
    this.setDimensions(30, 50);

    this.input1 = new Node(0, -50, 0, this, 16);
    this.dot = new Node(0, 50, 0, this, 1);
    this.direction = "RIGHT";
}

SixteenSegDisplay.prototype = Object.create(CircuitElement.prototype);
SixteenSegDisplay.prototype.constructor = SixteenSegDisplay;
SixteenSegDisplay.prototype.tooltipText = "Sixteen Display ToolTip: Consists of 16+1 bit inputs.";
SixteenSegDisplay.prototype.helplink = "https://docs.circuitverse.org/#/outputs?id=sixteen-segment-display";
SixteenSegDisplay.prototype.customSave = function () {
    var data = {
        nodes: {
            input1: findNode(this.input1),
            dot: findNode(this.dot)
        }
    }
    return data;
}

SixteenSegDisplay.prototype.customDrawSegment = function (x1, y1, x2, y2, color) {
    if (color == undefined) color = "lightgrey";
    ctx = simulationArea.context;
    ctx.beginPath();
    ctx.strokeStyle = color;
    ctx.lineWidth = correctWidth(4);
    xx = this.x;
    yy = this.y;
    moveTo(ctx, x1, y1, xx, yy, this.direction);
    lineTo(ctx, x2, y2, xx, yy, this.direction);
    ctx.closePath();
    ctx.stroke();
}

SixteenSegDisplay.prototype.customDrawSegmentSlant = function (x1, y1, x2, y2, color) {
    if (color == undefined) color = "lightgrey";
    ctx = simulationArea.context;
    ctx.beginPath();
    ctx.strokeStyle = color;
    ctx.lineWidth = correctWidth(3);
    xx = this.x;
    yy = this.y;
    moveTo(ctx, x1, y1, xx, yy, this.direction);
    lineTo(ctx, x2, y2, xx, yy, this.direction);
    ctx.closePath();
    ctx.stroke();
}

SixteenSegDisplay.prototype.customDraw = function () {
    ctx = simulationArea.context;

    var xx = this.x;
    var yy = this.y;

    var color = ["lightgrey", "red"];
    var value = this.input1.value;

    this.customDrawSegment(-20, -38, 0, -38, ["lightgrey", "red"][(value >> 15) & 1]);		//a1
    this.customDrawSegment(20, -38, 0, -38, ["lightgrey", "red"][(value >> 14) & 1]);		//a2
    this.customDrawSegment(21.5, -2, 21.5, -36, ["lightgrey", "red"][(value >> 13) & 1]);	//b
    this.customDrawSegment(21.5, 2, 21.5, 36, ["lightgrey", "red"][(value >> 12) & 1]);		//c
    this.customDrawSegment(-20, 38, 0, 38, ["lightgrey", "red"][(value >> 11) & 1]);		//d1
    this.customDrawSegment(20, 38, 0, 38, ["lightgrey", "red"][(value >> 10) & 1]);			//d2
    this.customDrawSegment(-21.5, 2, -21.5, 36, ["lightgrey", "red"][(value >> 9) & 1]);	//e
    this.customDrawSegment(-21.5, -36, -21.5, -2, ["lightgrey", "red"][(value >> 8) & 1]);	//f
    this.customDrawSegment(-20, 0, 0, 0, ["lightgrey", "red"][(value >> 7) & 1]);			//g1
    this.customDrawSegment(20, 0, 0, 0, ["lightgrey", "red"][(value >> 6) & 1]);			//g2
    this.customDrawSegmentSlant(0, 0, -21, -37, ["lightgrey", "red"][(value >> 5) & 1]);	//h
    this.customDrawSegment(0, -2, 0, -36, ["lightgrey", "red"][(value >> 4) & 1]);			//i
    this.customDrawSegmentSlant(0, 0, 21, -37, ["lightgrey", "red"][(value >> 3) & 1]);		//j
    this.customDrawSegmentSlant(0, 0, 21, 37, ["lightgrey", "red"][(value >> 2) & 1]);		//k
    this.customDrawSegment(0, 2, 0, 36, ["lightgrey", "red"][(value >> 1) & 1]);			//l
    this.customDrawSegmentSlant(0, 0, -21, 37, ["lightgrey", "red"][(value >> 0) & 1]);		//m

    ctx.beginPath();
    var dotColor = ["lightgrey", "red"][this.dot.value] || "lightgrey"
    ctx.strokeStyle = dotColor;
    rect(ctx, xx + 22, yy + 42, 2, 2);
    ctx.stroke();
}
SixteenSegDisplay.prototype.generateVerilog = function () {
    return `
  always @ (*)
    $display("SixteenSegDisplay:{${this.input1.verilogLabel},${this.dot.verilogLabel}} = {%16b,%1b}", ${this.input1.verilogLabel}, ${this.dot.verilogLabel});`;
}

function HexDisplay(x, y, scope = globalScope) {
    CircuitElement.call(this, x, y, scope, "RIGHT", 4);
    this.directionFixed = true;
    this.fixedBitWidth = true;
    this.setDimensions(30, 50);

    this.inp = new Node(0, -50, 0, this, 4);
    this.direction = "RIGHT";
}

HexDisplay.prototype = Object.create(CircuitElement.prototype);
HexDisplay.prototype.constructor = HexDisplay;
HexDisplay.prototype.tooltipText = "Hex Display ToolTip: Inputs a 4 Bit Hex number and displays it."
HexDisplay.prototype.helplink = "https://docs.circuitverse.org/#/outputs?id=hex-display";
/* Older code convert HexDisplay to output
HexDisplay.prototype.generateVerilog = function () {
    return "assign " + this.label + " = " + this.inp.verilogLabel + ";"
}
*/
//Use $display
HexDisplay.prototype.generateVerilog = function () {
    return `
  always @ (*)
    $display("HexDisplay:${this.verilogLabel}=%d", ${this.inp.verilogLabel});`;
}
HexDisplay.prototype.customSave = function () {
    var data = {


        nodes: {
            inp: findNode(this.inp)
        }

    }
    return data;
}
HexDisplay.prototype.customDrawSegment = function (x1, y1, x2, y2, color) {
    if (color == undefined) color = "lightgrey";
    ctx = simulationArea.context;
    ctx.beginPath();
    ctx.strokeStyle = color;
    ctx.lineWidth = correctWidth(5);
    xx = this.x;
    yy = this.y;

    moveTo(ctx, x1, y1, xx, yy, this.direction);
    lineTo(ctx, x2, y2, xx, yy, this.direction);
    ctx.closePath();
    ctx.stroke();
}
HexDisplay.prototype.customDraw = function () {
    ctx = simulationArea.context;

    var xx = this.x;
    var yy = this.y;

    ctx.strokeStyle = "black";
    ctx.lineWidth = correctWidth(3);
    var a = b = c = d = e = f = g = 0;
    switch (this.inp.value) {
        case 0:
            a = b = c = d = e = f = 1;
            break;
        case 1:
            b = c = 1;
            break;
        case 2:
            a = b = g = e = d = 1;
            break;
        case 3:
            a = b = g = c = d = 1;
            break;
        case 4:
            f = g = b = c = 1;
            break;
        case 5:
            a = f = g = c = d = 1;
            break;
        case 6:
            a = f = g = e = c = d = 1;
            break;
        case 7:
            a = b = c = 1;
            break;
        case 8:
            a = b = c = d = e = g = f = 1;
            break;
        case 9:
            a = f = g = b = c = 1;
            break;
        case 0xA:
            a = f = b = c = g = e = 1;
            break;
        case 0xB:
            f = e = g = c = d = 1;
            break;
        case 0xC:
            a = f = e = d = 1;
            break;
        case 0xD:
            b = c = g = e = d = 1;
            break;
        case 0xE:
            a = f = g = e = d = 1;
            break;
        case 0xF:
            a = f = g = e = 1;
            break;
        default:

    }
    this.customDrawSegment(18, -3, 18, -38, ["lightgrey", "red"][b]);
    this.customDrawSegment(18, 3, 18, 38, ["lightgrey", "red"][c]);
    this.customDrawSegment(-18, -3, -18, -38, ["lightgrey", "red"][f]);
    this.customDrawSegment(-18, 3, -18, 38, ["lightgrey", "red"][e]);
    this.customDrawSegment(-17, -38, 17, -38, ["lightgrey", "red"][a]);
    this.customDrawSegment(-17, 0, 17, 0, ["lightgrey", "red"][g]);
    this.customDrawSegment(-15, 38, 17, 38, ["lightgrey", "red"][d]);

}

function OrGate(x, y, scope = globalScope, dir = "RIGHT", inputs = 2, bitWidth = 1) {
    // Calling base class constructor
    CircuitElement.call(this, x, y, scope, dir, bitWidth);
    this.rectangleObject = false;
    this.setDimensions(15, 20);
    // Inherit base class prototype

    this.inp = [];
    this.inputSize = inputs;


    if (inputs % 2 == 1) {
        // for (var i = 0; i < inputs / 2 - 1; i++) {
        //     var a = new Node(-10, -10 * (i + 1), 0, this);
        //     this.inp.push(a);
        // }
        // var a = new Node(-10, 0, 0, this);
        // this.inp.push(a);
        // for (var i = inputs / 2 + 1; i < inputs; i++) {
        //     var a = new Node(-10, 10 * (i + 1 - inputs / 2 - 1), 0, this);
        //     this.inp.push(a);
        // }
        for (var i = Math.floor(inputs / 2) - 1; i >= 0; i--) {
            var a = new Node(-10, -10 * (i + 1), 0, this);
            this.inp.push(a);
        }
        var a = new Node(-10, 0, 0, this);
        this.inp.push(a);
        for (var i = 0; i < Math.floor(inputs / 2); i++) {
            var a = new Node(-10, 10 * (i + 1), 0, this);
            this.inp.push(a);
        }
    } else {
        for (var i = inputs / 2 - 1; i >= 0; i--) {
            var a = new Node(-10, -10 * (i + 1), 0, this);
            this.inp.push(a);
        }
        for (var i = 0; i < inputs / 2; i++) {
            var a = new Node(-10, 10 * (i + 1), 0, this);
            this.inp.push(a);
        }
    }
    this.output1 = new Node(20, 0, 1, this);



}
OrGate.prototype = Object.create(CircuitElement.prototype);
OrGate.prototype.constructor = OrGate;
OrGate.prototype.tooltipText = "Or Gate Tooltip : Implements logical disjunction";
OrGate.prototype.changeInputSize = changeInputSize;
OrGate.prototype.alwaysResolve = true;
OrGate.prototype.verilogType = "or";
OrGate.prototype.helplink = "https://docs.circuitverse.org/#/gates?id=or-gate";
OrGate.prototype.customSave = function () {
    var data = {

        constructorParamaters: [this.direction, this.inputSize, this.bitWidth],

        nodes: {
            inp: this.inp.map(findNode),
            output1: findNode(this.output1),
        },
    }
    return data;
}
OrGate.prototype.resolve = function () {
    var result = this.inp[0].value || 0;
    if (this.isResolvable() == false) {
        return;
    }
    for (var i = 1; i < this.inputSize; i++)
        result = result | (this.inp[i].value || 0);
    this.output1.value = result;
    simulationArea.simulationQueue.add(this.output1);
}
OrGate.prototype.customDraw = function () {

    ctx = simulationArea.context;
    ctx.strokeStyle = ("rgba(0,0,0,1)");
    ctx.lineWidth = correctWidth(3);

    var xx = this.x;
    var yy = this.y;
    ctx.beginPath();
    ctx.fillStyle = "white";

    moveTo(ctx, -10, -20, xx, yy, this.direction, true);
    bezierCurveTo(0, -20, +15, -10, 20, 0, xx, yy, this.direction);
    bezierCurveTo(0 + 15, 0 + 10, 0, 0 + 20, -10, +20, xx, yy, this.direction);
    bezierCurveTo(0, 0, 0, 0, -10, -20, xx, yy, this.direction);
    ctx.closePath();
    if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";
    ctx.fill();
    ctx.stroke();



}
OrGate.prototype.generateVerilog = function () {
    return gateGenerateVerilog.call(this, '|');
}


function Stepper(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 8) {

    CircuitElement.call(this, x, y, scope, dir, bitWidth);
    this.setDimensions(20, 20);

    this.output1 = new Node(20, 0, 1, this, bitWidth);
    this.state = 0;

}
Stepper.prototype = Object.create(CircuitElement.prototype);
Stepper.prototype.constructor = Stepper;
Stepper.prototype.tooltipText = "Stepper ToolTip: Increase/Decrease value by selecting the stepper and using +/- keys."
Stepper.prototype.helplink = "https://docs.circuitverse.org/#/inputElements?id=stepper";
Stepper.prototype.customSave = function () {
    var data = {
        constructorParamaters: [this.direction, this.bitWidth],
        nodes: {
            output1: findNode(this.output1),
        },
        values: {
            state: this.state
        }
    }
    return data;
}
Stepper.prototype.customDraw = function () {
    ctx = simulationArea.context;

    ctx.beginPath();
    ctx.font = "20px Georgia";
    ctx.fillStyle = "green";
    ctx.textAlign = "center";
    fillText(ctx, this.state.toString(16), this.x, this.y + 5);
    ctx.fill();;
}
Stepper.prototype.resolve = function () {
    this.state = Math.min(this.state, (1 << this.bitWidth) - 1);
    this.output1.value = this.state;
    simulationArea.simulationQueue.add(this.output1);
}
Stepper.prototype.keyDown2 = function (key) {
    //console.log(key);
    if (this.state + 1 < (1 << this.bitWidth) && (key == "+" || key == "=")) this.state++;
    if (this.state > 0 && (key == "_" || key == "-")) this.state--;
}

function NotGate(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {

    CircuitElement.call(this, x, y, scope, dir, bitWidth);
    this.rectangleObject = false;
    this.setDimensions(15, 15);

    this.inp1 = new Node(-10, 0, 0, this);
    this.output1 = new Node(20, 0, 1, this);


}
NotGate.prototype = Object.create(CircuitElement.prototype);
NotGate.prototype.constructor = NotGate;
NotGate.prototype.tooltipText = "Not Gate Tooltip : Inverts the input digital signal.";
NotGate.prototype.verilogType = "not";
NotGate.prototype.helplink = "https://docs.circuitverse.org/#/gates?id=not-gate";
NotGate.prototype.customSave = function () {
    var data = {
        constructorParamaters: [this.direction, this.bitWidth],
        nodes: {
            output1: findNode(this.output1),
            inp1: findNode(this.inp1)
        },
    }
    return data;
}
NotGate.prototype.resolve = function () {
    if (this.isResolvable() == false) {
        return;
    }
    this.output1.value = ((~this.inp1.value >>> 0) << (32 - this.bitWidth)) >>> (32 - this.bitWidth);
    simulationArea.simulationQueue.add(this.output1);
}
NotGate.prototype.customDraw = function () {

    ctx = simulationArea.context;
    ctx.strokeStyle = "black";
    ctx.lineWidth = correctWidth(3);

    var xx = this.x;
    var yy = this.y;
    ctx.beginPath();
    ctx.fillStyle = "white";
    moveTo(ctx, -10, -10, xx, yy, this.direction);
    lineTo(ctx, 10, 0, xx, yy, this.direction);
    lineTo(ctx, -10, 10, xx, yy, this.direction);
    ctx.closePath();
    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.beginPath();
    drawCircle2(ctx, 15, 0, 5, xx, yy, this.direction);
    ctx.stroke();

}
//translate to gate for single bit, assign for multi bit
NotGate.prototype.generateVerilog = function () {
    return "assign " + this.output1.verilogLabel + " = ~" + this.inp1.verilogLabel + ";"
}


function ForceGate(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {

    CircuitElement.call(this, x, y, scope, dir, bitWidth);
    this.setDimensions(20, 10);

    this.inp1 = new Node(-20, 0, 0, this);
    this.inp2 = new Node(0, 0, 0, this);
    this.output1 = new Node(20, 0, 1, this);


}
ForceGate.prototype = Object.create(CircuitElement.prototype);
ForceGate.prototype.constructor = ForceGate;
ForceGate.prototype.tooltipText = "Force Gate ToolTip : ForceGate Selected.";
ForceGate.prototype.isResolvable = function () {
    return (this.inp1.value != undefined || this.inp2.value != undefined)
}
ForceGate.prototype.customSave = function () {
    var data = {
        constructorParamaters: [this.direction, this.bitWidth],
        nodes: {
            output1: findNode(this.output1),
            inp1: findNode(this.inp1),
            inp2: findNode(this.inp2)
        },
    }
    return data;
}
ForceGate.prototype.resolve = function () {
    if (this.inp2.value != undefined)
        this.output1.value = this.inp2.value;
    else
        this.output1.value = this.inp1.value;
    simulationArea.simulationQueue.add(this.output1);
}
ForceGate.prototype.customDraw = function () {

    ctx = simulationArea.context;
    var xx = this.x;
    var yy = this.y;



    ctx.beginPath();
    ctx.fillStyle = "Black";
    ctx.textAlign = "center"

    fillText4(ctx, "I", -10, 0, xx, yy, this.direction, 10);
    fillText4(ctx, "O", 10, 0, xx, yy, this.direction, 10);
    ctx.fill();

}


function Text(x, y, scope = globalScope, label = "", fontSize = 14) {

    CircuitElement.call(this, x, y, scope, "RIGHT", 1);
    // this.setDimensions(15, 15);
    this.fixedBitWidth = true;
    this.directionFixed = true;
    this.labelDirectionFixed = true;
    this.setHeight(10);
    this.setLabel(label);
    this.setFontSize(fontSize);



}
Text.prototype = Object.create(CircuitElement.prototype);
Text.prototype.constructor = Text;
Text.prototype.propagationDelayFixed = true;
Text.prototype.tooltipText = "Text ToolTip: Use this to document your circuit."
Text.prototype.helplink = "https://docs.circuitverse.org/#/annotation?id=adding-labels";
Text.prototype.setLabel = function (str = "") {

    this.label = str;
    ctx = simulationArea.context;
    ctx.font = this.fontSize + "px Georgia";
    this.leftDimensionX = 10;
    this.rightDimensionX = ctx.measureText(this.label).width + 10;
    //console.log(this.leftDimensionX,this.rightDimensionX,ctx.measureText(this.label))
}

Text.prototype.setFontSize = function (fontSize = 14) {
    this.fontSize = fontSize;
    ctx = simulationArea.context;
    ctx.font = this.fontSize + "px Georgia";
    this.leftDimensionX = 10;
    this.rightDimensionX = ctx.measureText(this.label).width + 10;
}

Text.prototype.customSave = function () {
    var data = {
        constructorParamaters: [this.label, this.fontSize],
    }
    return data;
}
Text.prototype.keyDown = function (key) {


    if (key.length == 1) {
        if (this.label == "Enter Text Here")
            this.setLabel(key)
        else
            this.setLabel(this.label + key);
    } else if (key == "Backspace") {
        if (this.label == "Enter Text Here")
            this.setLabel("")
        else
            this.setLabel(this.label.slice(0, -1));
    }
}

Text.prototype.mutableProperties = {
    "fontSize": {
        name: "Font size: ",
        type: "number",
        max: "84",
        min: "14",
        func: "setFontSize",
    }
}

Text.prototype.draw = function () {

    if (this.label.length == 0 && simulationArea.lastSelected != this) this.delete();

    ctx = simulationArea.context;
    ctx.strokeStyle = "black";
    ctx.lineWidth = 1;



    var xx = this.x;
    var yy = this.y;

    if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) {
        ctx.beginPath();
        ctx.fillStyle = "white";
        var magicDimenstion = this.fontSize - 14;
        rect2(ctx, -this.leftDimensionX, -this.upDimensionY - magicDimenstion,
            this.leftDimensionX + this.rightDimensionX,
            this.upDimensionY + this.downDimensionY + magicDimenstion, this.x, this.y, "RIGHT");
        ctx.fillStyle = "rgba(255, 255, 32,0.1)";
        ctx.fill();
        ctx.stroke();
    }
    ctx.beginPath();
    ctx.textAlign = "left";
    ctx.fillStyle = "black"
    fillText(ctx, this.label, xx, yy + 5, this.fontSize);
    ctx.fill();

}

function TriState(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {
    CircuitElement.call(this, x, y, scope, dir, bitWidth);
    this.rectangleObject = false;
    this.setDimensions(15, 15);

    this.inp1 = new Node(-10, 0, 0, this);
    this.output1 = new Node(20, 0, 1, this);
    this.state = new Node(0, 0, 0, this, 1, "Enable");


}
TriState.prototype = Object.create(CircuitElement.prototype);
TriState.prototype.constructor = TriState;
TriState.prototype.tooltipText = "TriState ToolTip : Effectively removes the output from the circuit.";
TriState.prototype.helplink = "https://docs.circuitverse.org/#/miscellaneous?id=tri-state-buffer"
// TriState.prototype.propagationDelay=10000;
TriState.prototype.customSave = function () {
    var data = {
        constructorParamaters: [this.direction, this.bitWidth],
        nodes: {
            output1: findNode(this.output1),
            inp1: findNode(this.inp1),
            state: findNode(this.state),
        },
    }
    return data;
}
// TriState.prototype.isResolvable = function(){
// 	return this.inp1.value!=undefined
// }
TriState.prototype.newBitWidth = function (bitWidth) {
    this.inp1.bitWidth = bitWidth;
    this.output1.bitWidth = bitWidth;
    this.bitWidth = bitWidth;
}
TriState.prototype.resolve = function () {
    if (this.isResolvable() == false) {
        return;
    }

    if (this.state.value == 1) {
        if (this.output1.value != this.inp1.value) {
            this.output1.value = this.inp1.value; //>>>0)<<(32-this.bitWidth))>>>(32-this.bitWidth);
            simulationArea.simulationQueue.add(this.output1);
        }
        simulationArea.contentionPending.clean(this);
    } else {
        if (this.output1.value != undefined && !simulationArea.contentionPending.contains(this)) {
            this.output1.value = undefined;
            simulationArea.simulationQueue.add(this.output1);
        }

    }
    simulationArea.contentionPending.clean(this);
}
TriState.prototype.customDraw = function () {

    ctx = simulationArea.context;
    ctx.strokeStyle = ("rgba(0,0,0,1)");
    ctx.lineWidth = correctWidth(3);

    var xx = this.x;
    var yy = this.y;
    ctx.beginPath();
    ctx.fillStyle = "white";
    moveTo(ctx, -10, -15, xx, yy, this.direction);
    lineTo(ctx, 20, 0, xx, yy, this.direction);
    lineTo(ctx, -10, 15, xx, yy, this.direction);
    ctx.closePath();
    if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";
    ctx.fill();
    ctx.stroke();

}
TriState.prototype.generateVerilog = function () {
    return `assign ${this.output1.verilogLabel} = (${this.state.verilogLabel}!=0) ? ${this.inp1.verilogLabel} : ${this.inp1.bitWidth}'b?;`;
}

function Buffer(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {
    CircuitElement.call(this, x, y, scope, dir, bitWidth);
    this.rectangleObject = false;
    this.setDimensions(15, 15);

    this.state = 0;
    this.preState = 0;
    this.inp1 = new Node(-10, 0, 0, this);
    this.reset = new Node(0, 0, 0, this, 1, "reset");
    this.output1 = new Node(20, 0, 1, this);


}
Buffer.prototype = Object.create(CircuitElement.prototype);
Buffer.prototype.constructor = Buffer;
Buffer.prototype.tooltipText = "Buffer ToolTip : Isolate the input from the output.";
Buffer.prototype.helplink = "https://docs.circuitverse.org/#/miscellaneous?id=buffer"
Buffer.prototype.customSave = function () {
    var data = {
        constructorParamaters: [this.direction, this.bitWidth],
        nodes: {
            output1: findNode(this.output1),
            inp1: findNode(this.inp1),
            reset: findNode(this.reset),
        },
    }
    return data;
}
Buffer.prototype.newBitWidth = function (bitWidth) {
    this.inp1.bitWidth = bitWidth;
    this.output1.bitWidth = bitWidth;
    this.bitWidth = bitWidth;
}
Buffer.prototype.isResolvable = function () {
    return true;
}
Buffer.prototype.resolve = function () {

    if (this.reset.value == 1) {
        this.state = this.preState;
    }
    if (this.inp1.value !== undefined)
        this.state = this.inp1.value;

    this.output1.value = this.state;
    simulationArea.simulationQueue.add(this.output1);

}
Buffer.prototype.customDraw = function () {

    ctx = simulationArea.context;
    ctx.strokeStyle = ("rgba(200,0,0,1)");
    ctx.lineWidth = correctWidth(3);

    var xx = this.x;
    var yy = this.y;
    ctx.beginPath();
    ctx.fillStyle = "white";
    moveTo(ctx, -10, -15, xx, yy, this.direction);
    lineTo(ctx, 20, 0, xx, yy, this.direction);
    lineTo(ctx, -10, 15, xx, yy, this.direction);
    ctx.closePath();
    if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";
    ctx.fill();
    ctx.stroke();

}
Buffer.prototype.generateVerilog = function () {
    return "assign " + this.output1.verilogLabel + " = " + this.inp1.verilogLabel + ";"
}

function ControlledInverter(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {
    CircuitElement.call(this, x, y, scope, dir, bitWidth);
    this.rectangleObject = false;
    this.setDimensions(15, 15);

    this.inp1 = new Node(-10, 0, 0, this);
    this.output1 = new Node(30, 0, 1, this);
    this.state = new Node(0, 0, 0, this, 1, "Enable");


}
ControlledInverter.prototype = Object.create(CircuitElement.prototype);
ControlledInverter.prototype.constructor = ControlledInverter;
ControlledInverter.prototype.tooltipText = "Controlled Inverter ToolTip : Controlled buffer and NOT gate.";
ControlledInverter.prototype.customSave = function () {
    var data = {
        constructorParamaters: [this.direction, this.bitWidth],
        nodes: {
            output1: findNode(this.output1),
            inp1: findNode(this.inp1),
            state: findNode(this.state)
        },
    }
    return data;
}
ControlledInverter.prototype.newBitWidth = function (bitWidth) {
    this.inp1.bitWidth = bitWidth;
    this.output1.bitWidth = bitWidth;
    this.bitWidth = bitWidth;
}
ControlledInverter.prototype.resolve = function () {
    if (this.isResolvable() == false) {
        return;
    }
    if (this.state.value == 1) {
        this.output1.value = ((~this.inp1.value >>> 0) << (32 - this.bitWidth)) >>> (32 - this.bitWidth);
        simulationArea.simulationQueue.add(this.output1);
    }
    if (this.state.value == 0) {
        this.output1.value = undefined;
    }
}
ControlledInverter.prototype.customDraw = function () {

    ctx = simulationArea.context;
    ctx.strokeStyle = ("rgba(0,0,0,1)");
    ctx.lineWidth = correctWidth(3);

    var xx = this.x;
    var yy = this.y;
    ctx.beginPath();
    ctx.fillStyle = "white";
    moveTo(ctx, -10, -15, xx, yy, this.direction);
    lineTo(ctx, 20, 0, xx, yy, this.direction);
    lineTo(ctx, -10, 15, xx, yy, this.direction);
    ctx.closePath();
    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.beginPath();
    drawCircle2(ctx, 25, 0, 5, xx, yy, this.direction);
    ctx.stroke();

}
ControlledInverter.prototype.generateVerilog = function () {
    return `assign ${this.output1.verilogLabel} = (${this.state.verilogLabel}!=0) ? ~${this.inp1.verilogLabel} : ${this.inp1.verilogLabel};`;
}

function Adder(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {

    CircuitElement.call(this, x, y, scope, dir, bitWidth);
    this.setDimensions(20, 20);

    this.inpA = new Node(-20, -10, 0, this, this.bitWidth, "A");
    this.inpB = new Node(-20, 0, 0, this, this.bitWidth, "B");
    this.carryIn = new Node(-20, 10, 0, this, 1, "Cin");
    this.sum = new Node(20, 0, 1, this, this.bitWidth, "Sum");
    this.carryOut = new Node(20, 10, 1, this, 1, "Cout");



}
Adder.prototype = Object.create(CircuitElement.prototype);
Adder.prototype.constructor = Adder;
Adder.prototype.tooltipText = "Adder ToolTip : Performs addition of numbers.";
Adder.prototype.helplink = "https://docs.circuitverse.org/#/miscellaneous?id=adder"
Adder.prototype.customSave = function () {
    var data = {
        constructorParamaters: [this.direction, this.bitWidth],
        nodes: {
            inpA: findNode(this.inpA),
            inpB: findNode(this.inpB),
            carryIn: findNode(this.carryIn),
            carryOut: findNode(this.carryOut),
            sum: findNode(this.sum)
        },
    }
    return data;
}
Adder.prototype.isResolvable = function () {
    return this.inpA.value != undefined && this.inpB.value != undefined;
}
Adder.prototype.newBitWidth = function (bitWidth) {
    this.bitWidth = bitWidth;
    this.inpA.bitWidth = bitWidth;
    this.inpB.bitWidth = bitWidth;
    this.sum.bitWidth = bitWidth;
}
Adder.prototype.resolve = function () {
    if (this.isResolvable() == false) {
        return;
    }
    var carryIn = this.carryIn.value;
    if (carryIn == undefined) carryIn = 0;
    var sum = this.inpA.value + this.inpB.value + carryIn;

    this.sum.value = ((sum) << (32 - this.bitWidth)) >>> (32 - this.bitWidth);
    this.carryOut.value = +((sum >>> (this.bitWidth)) !== 0);
    simulationArea.simulationQueue.add(this.carryOut);
    simulationArea.simulationQueue.add(this.sum);
}
Adder.prototype.generateVerilog = function () {
    if(this.carryIn.verilogLabel) {
        return `assign ${this.sum.verilogLabel} = ${this.inpA.verilogLabel} + ${this.inpB.verilogLabel} + ${this.carryIn.verilogLabel};`;
    }
    return `assign ${this.sum.verilogLabel} = ${this.inpA.verilogLabel} + ${this.inpB.verilogLabel};`;
}


function TwoComplement(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {

    CircuitElement.call(this, x, y, scope, dir, bitWidth);
    this.rectangleObject = false;
    this.setDimensions(15, 15);

    this.inp1 = new Node(-10, 0, 0, this, this.bitWidth, "input stream");
    this.output1 = new Node(20, 0, 1, this, this.bitWidth, "2's complement");


}
TwoComplement.prototype = Object.create(CircuitElement.prototype);
TwoComplement.prototype.constructor = TwoComplement;
TwoComplement.prototype.tooltipText = "Two's Complement Tooltip : Calculates the two's complement";
TwoComplement.prototype.customSave = function () {
    var data = {
        constructorParamaters: [this.direction, this.bitWidth],
        nodes: {
            output1: findNode(this.output1),
            inp1: findNode(this.inp1)
        },
    }
    return data;
}
TwoComplement.prototype.resolve = function () {
    if (this.isResolvable() == false) {
        return;
    }
    let output = ((~this.inp1.value >>> 0) << (32 - this.bitWidth)) >>> (32 - this.bitWidth);
    output += 1;
    this.output1.value = ((output) << (32 - this.bitWidth)) >>> (32 - this.bitWidth);
	simulationArea.simulationQueue.add(this.output1);
}
TwoComplement.prototype.customDraw = function () {

    ctx = simulationArea.context;
    ctx.strokeStyle = "black";
    ctx.lineWidth = correctWidth(3);

    var xx = this.x;
    var yy = this.y;
    ctx.beginPath();
    ctx.fillStyle = "black";
    fillText(ctx, "2'", xx, yy, 10);
    if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";
    ctx.fill();
    ctx.beginPath();
    drawCircle2(ctx, 5, 0, 15, xx, yy, this.direction);
    ctx.stroke();
}
TwoComplement.prototype.generateVerilog = function () {
    return `assign ${this.output1.verilogLabel} = ~${this.inp1.verilogLabel} + 1;`;
}

function Rom(x, y, scope = globalScope, data = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) {

    CircuitElement.call(this, x, y, scope, "RIGHT", 1);
    this.fixedBitWidth = true;
    this.directionFixed = true;
    this.rectangleObject = false;
    this.setDimensions(80, 50);

    this.memAddr = new Node(-80, 0, 0, this, 4, "Address");
    this.en = new Node(0, 50, 0, this, 1, "Enable");
    this.dataOut = new Node(80, 0, 1, this, 8, "DataOut");
    this.data = data || prompt("Enter data").split(' ').map(function (x) {
        return parseInt(x, 16);
    });
    //console.log(this.data);



}
Rom.prototype = Object.create(CircuitElement.prototype);
Rom.prototype.constructor = Rom;
Rom.prototype.tooltipText = "Read-only memory";
Rom.prototype.helplink = "https://docs.circuitverse.org/#/memoryElements?id=rom";
Rom.prototype.isResolvable = function () {
    if ((this.en.value == 1 || this.en.connections.length == 0) && this.memAddr.value != undefined) return true;
    return false;
}
Rom.prototype.customSave = function () {
    var data = {
        constructorParamaters: [this.data],
        nodes: {
            memAddr: findNode(this.memAddr),
            dataOut: findNode(this.dataOut),
            en: findNode(this.en),
        },

    }
    return data;
}
Rom.prototype.findPos = function () {
    var i = Math.floor((simulationArea.mouseX - this.x + 35) / 20)
    var j = Math.floor((simulationArea.mouseY - this.y + 35) / 16);
    if (i < 0 || j < 0 || i > 3 || j > 3) return undefined;
    return j * 4 + i;
}
Rom.prototype.click = function () { // toggle
    this.selectedIndex = this.findPos();
}
Rom.prototype.keyDown = function (key) {
    if (key == "Backspace") this.delete();
    if (this.selectedIndex == undefined) return;
    key = key.toLowerCase();
    if (!~"1234567890abcdef".indexOf(key)) return;
    else {
        this.data[this.selectedIndex] = (this.data[this.selectedIndex] * 16 + parseInt(key, 16)) % 256;
    }
}
Rom.prototype.customDraw = function () {




    var ctx = simulationArea.context;
    var xx = this.x;
    var yy = this.y;

    var hoverIndex = this.findPos();




    ctx.strokeStyle = "black";
    ctx.fillStyle = "white";
    ctx.lineWidth = correctWidth(3);
    ctx.beginPath();
    rect2(ctx, -this.leftDimensionX, -this.upDimensionY, this.leftDimensionX + this.rightDimensionX, this.upDimensionY + this.downDimensionY, this.x, this.y, [this.direction, "RIGHT"][+this.directionFixed]);
    if (hoverIndex == undefined && ((!simulationArea.shiftDown && this.hover) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this))) ctx.fillStyle = "rgba(255, 255, 32,0.8)";
    ctx.fill();
    ctx.stroke();
    // if (this.hover)
    //     ////console.log(this);

    ctx.strokeStyle = "black";
    ctx.fillStyle = "#fafafa";
    ctx.lineWidth = correctWidth(1);
    ctx.beginPath();

    for (var i = 0; i < 16; i += 4) {
        for (var j = i; j < i + 4; j++) {
            rect2(ctx, (j % 4) * 20, i * 4, 20, 16, xx - 35, yy - 35);
        }
    }
    ctx.fill();
    ctx.stroke();

    if (hoverIndex != undefined) {
        ctx.beginPath();
        ctx.fillStyle = "yellow";
        rect2(ctx, (hoverIndex % 4) * 20, Math.floor(hoverIndex / 4) * 16, 20, 16, xx - 35, yy - 35);
        ctx.fill();
        ctx.stroke();
    }
    if (this.selectedIndex != undefined) {
        ctx.beginPath();
        ctx.fillStyle = "lightgreen";
        rect2(ctx, (this.selectedIndex % 4) * 20, Math.floor(this.selectedIndex / 4) * 16, 20, 16, xx - 35, yy - 35);
        ctx.fill();
        ctx.stroke();
    }
    if (this.memAddr.value != undefined) {
        ctx.beginPath();
        ctx.fillStyle = "green";
        rect2(ctx, (this.memAddr.value % 4) * 20, Math.floor(this.memAddr.value / 4) * 16, 20, 16, xx - 35, yy - 35);
        ctx.fill();
        ctx.stroke();
    }

    ctx.beginPath();
    ctx.fillStyle = "Black";
    fillText3(ctx, "A", -65, 5, xx, yy, fontSize = 16, font = "Georgia", textAlign = "right");
    fillText3(ctx, "D", 75, 5, xx, yy, fontSize = 16, font = "Georgia", textAlign = "right");
    fillText3(ctx, "En", 5, 47, xx, yy, fontSize = 16, font = "Georgia", textAlign = "right");
    ctx.fill();


    ctx.beginPath();
    ctx.fillStyle = "Black";
    for (var i = 0; i < 16; i += 4) {
        for (var j = i; j < i + 4; j++) {
            var s = this.data[j].toString(16);
            if (s.length < 2) s = '0' + s;
            fillText3(ctx, s, (j % 4) * 20, i * 4, xx - 35 + 10, yy - 35 + 12, fontSize = 14, font = "Georgia", textAlign = "center")
        }
    }
    ctx.fill();

    ctx.beginPath();
    ctx.fillStyle = "Black";
    for (var i = 0; i < 16; i += 4) {

        var s = i.toString(16);
        if (s.length < 2) s = '0' + s;
        fillText3(ctx, s, 0, i * 4, xx - 40, yy - 35 + 12, fontSize = 14, font = "Georgia", textAlign = "right")

    }
    ctx.fill();


}
Rom.prototype.resolve = function () {
    if (this.isResolvable() == false) {
        return;
    }
    this.dataOut.value = this.data[this.memAddr.value];
    simulationArea.simulationQueue.add(this.dataOut);
}

Rom.prototype.verilogBaseType = function() {
    return this.verilogName() + (Rom.selSizes.length-1);
}
//this code to generate Verilog
Rom.prototype.generateVerilog = function () {
    Rom.selSizes.push(this.data);
    return CircuitElement.prototype.generateVerilog.call(this);
}
//This code to determine what sizes are used to generate the needed modules
Rom.selSizes = [];
//generate the needed modules
Rom.moduleVerilog = function () {
    var output = "";

    for (var i = 0; i < Rom.selSizes.length; i++) {
         output += `
module Rom${i}(dout, addr, en);
  parameter WIDTH = 8;
  parameter ADDR = 4;
  output reg [WIDTH-1:0] dout;
  input [ADDR-1:0] addr;
  input en;

  always @ (*) begin
    if (en == 0)
      dout = {WIDTH{1'bz}};
    else
      case (addr)
`;
        for (var j = 0; j < (1 << 4); j++) {
          output += "        " + j + " : dout = " + Rom.selSizes[i][j] + ";\n";
        }

    output += `      endcase
  end
endmodule
`;
    }

    return output;
}
//reset the sized before Verilog generation
Rom.resetVerilog = function () {
    Rom.selSizes = [];
}


/*

//This is a Rom without a clock - not normal
Rom.moduleVerilog = function () {
  var output = `
module ROM(dout, addr, en);
  parameter WIDTH = 8;
  parameter ADDR = 4;
  output [WIDTH-1:0] dout;
  input [ADDR-1:0] addr;
  input en;

  always @ (*) begin
    if (en)
      case (addr) begin
`;
    for (var i = 0; i < (1 << 4); i++) {
        output += "        " + i + " : dout = " + this.data[i];
    }

    output += `
      endcase
    else
      dout = WIDTH'z;
  end
endmodule
`;
    return output;
}
*/

function Splitter(x, y, scope = globalScope, dir = "RIGHT", bitWidth = undefined, bitWidthSplit = undefined) {

    CircuitElement.call(this, x, y, scope, dir, bitWidth);
    this.rectangleObject = false;

    this.bitWidthSplit = bitWidthSplit || prompt("Enter bitWidth Split").split(' ').filter(x => x != '').map(function(x) {
        return parseInt(x, 10)||1;

    });
    this.splitCount = this.bitWidthSplit.length;

    this.setDimensions(10, (this.splitCount - 1) * 10 + 10);
    this.yOffset = (this.splitCount / 2 - 1) * 20;

    this.inp1 = new Node(-10, 10 + this.yOffset, 0, this, this.bitWidth);

    this.outputs = [];
    // this.prevOutValues=new Array(this.splitCount)
    for (var i = 0; i < this.splitCount; i++)
        this.outputs.push(new Node(20, i * 20 - this.yOffset - 20, 0, this, this.bitWidthSplit[i]));

    this.prevInpValue = undefined;


}
Splitter.prototype = Object.create(CircuitElement.prototype);
Splitter.prototype.constructor = Splitter;
Splitter.prototype.tooltipText = "Splitter ToolTip: Split multiBit Input into smaller bitwidths or vice versa."
Splitter.prototype.helplink = "https://docs.circuitverse.org/#/splitter";
Splitter.prototype.customSave = function () {
    var data = {

        constructorParamaters: [this.direction, this.bitWidth, this.bitWidthSplit],
        nodes: {
            outputs: this.outputs.map(findNode),
            inp1: findNode(this.inp1)
        },
    }
    return data;
}
Splitter.prototype.removePropagation = function () {

    if (this.inp1.value == undefined) {
        let i = 0;

        for (i = 0; i < this.outputs.length; i++) { // False Hit
            if (this.outputs[i].value == undefined) return;
        }

        for (i = 0; i < this.outputs.length; i++) {
            if (this.outputs[i].value !== undefined) {
                this.outputs[i].value = undefined;
                simulationArea.simulationQueue.add(this.outputs[i]);
            }
        }
    } else {
        if (this.inp1.value !== undefined) {
            this.inp1.value = undefined;
            simulationArea.simulationQueue.add(this.inp1);
        }
    }

    this.prevInpValue = undefined;

}
Splitter.prototype.isResolvable = function () {
    var resolvable = false;
    if (this.inp1.value != this.prevInpValue) {
        if (this.inp1.value !== undefined) return true;
        return false;
    }
    var i;
    for (i = 0; i < this.splitCount; i++)
        if (this.outputs[i].value === undefined) break;
    if (i == this.splitCount) resolvable = true;
    return resolvable;
}
Splitter.prototype.resolve = function () {
    if (this.isResolvable() == false) {
        return;
    }
    if (this.inp1.value !== undefined && this.inp1.value != this.prevInpValue) {
        var bitCount = 1;
        for (var i = 0; i < this.splitCount; i++) {
            var bitSplitValue = extractBits(this.inp1.value, bitCount, bitCount + this.bitWidthSplit[i] - 1);
            if (this.outputs[i].value != bitSplitValue) {
                if (this.outputs[i].value != bitSplitValue) {
                    this.outputs[i].value = bitSplitValue;
                    simulationArea.simulationQueue.add(this.outputs[i]);
                }
            }
            bitCount += this.bitWidthSplit[i];
        }
    } else {
        var n = 0;
        for (var i = this.splitCount - 1; i >= 0; i--) {
            n <<= this.bitWidthSplit[i];
            n += this.outputs[i].value;
        }
        if (this.inp1.value != (n >>> 0)) {
            this.inp1.value = (n >>> 0);
            simulationArea.simulationQueue.add(this.inp1);
        }
        // else if (this.inp1.value != n) {
        //     console.log("CONTENTION");
        // }
    }
    this.prevInpValue = this.inp1.value;
}
Splitter.prototype.reset = function () {
    this.prevInpValue = undefined;
}
Splitter.prototype.processVerilog = function () {
    // Combiner
    if (this.inp1.verilogLabel == "") {
        this.isSplitter = false;
        this.inp1.verilogLabel = this.verilogLabel + "_cmb";
        if (!this.scope.verilogWireList[this.bitWidth].contains(this.inp1.verilogLabel))
            this.scope.verilogWireList[this.bitWidth].push(this.inp1.verilogLabel);
        this.scope.stack.push(this.inp1);
        return;
    }

    // Splitter
    this.isSplitter = true;
    for (var j = 0; j < this.outputs.length; j++) {
        var bitCount = 0;
        var inpLabel = this.inp1.verilogLabel;
        // Already Split Regex
        var re = /^(.*)\[(\d*):(\d*)\]$/;
        if(re.test(inpLabel)) {
            var matches = inpLabel.match(re);
            inpLabel = matches[1];
            bitCount = parseInt(matches[3]);
        }
        for (var i = 0; i < this.splitCount; i++) {
            if (this.bitWidthSplit[i] > 1)
                var label = inpLabel + '[' + (bitCount + this.bitWidthSplit[i] - 1) + ":" + bitCount + "]";
            else
                var label = inpLabel + '[' + bitCount + "]";
            if (this.outputs[i].verilogLabel != label) {
                this.outputs[i].verilogLabel = label;
                this.scope.stack.push(this.outputs[i]);
            }
            bitCount += this.bitWidthSplit[i];
        }
    }
}
//added to generate Splitter INPUTS
Splitter.prototype.generateVerilog = function () {
    var res = "";
    if (!this.isSplitter) {
        res += "assign " + this.inp1.verilogLabel + " = {";
        for (var i = this.outputs.length - 1; i > 0; i--)
          res += this.outputs[i].verilogLabel + ",";
        res += this.outputs[0].verilogLabel + "};";
    }
    return res;
}

Splitter.prototype.customDraw = function () {

    ctx = simulationArea.context;
    ctx.strokeStyle = ["black", "brown"][((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) + 0];
    ctx.lineWidth = correctWidth(3);

    var xx = this.x;
    var yy = this.y;
    ctx.beginPath();

    // drawLine(ctx, -10, -10, xx, y2, color, width)
    moveTo(ctx, -10, 10 + this.yOffset, xx, yy, this.direction);
    lineTo(ctx, 0, 0 + this.yOffset, xx, yy, this.direction);
    lineTo(ctx, 0, -20 * (this.splitCount - 1) + this.yOffset, xx, yy, this.direction);

    var bitCount = 0;
    for (var i = this.splitCount - 1; i >= 0; i--) {
        moveTo(ctx, 0, -20 * i + this.yOffset, xx, yy, this.direction);
        lineTo(ctx, 20, -20 * i + this.yOffset, xx, yy, this.direction);
    }
    ctx.stroke();
    ctx.beginPath();
    ctx.fillStyle = "black";
    for (var i = this.splitCount - 1; i >= 0; i--) {
        fillText2(ctx, bitCount + ":" + (bitCount + this.bitWidthSplit[this.splitCount - i - 1]), 12, -20 * i + this.yOffset + 10, xx, yy, this.direction);
        bitCount += this.bitWidthSplit[this.splitCount - i - 1];
    }
    ctx.fill();



}

function Ground(x, y, scope = globalScope, bitWidth = 1) {
    CircuitElement.call(this, x, y, scope, "RIGHT", bitWidth);
    this.rectangleObject = false;
    this.setDimensions(10, 10);
    this.directionFixed = true;
    this.output1 = new Node(0, -10, 1, this);
}
Ground.prototype = Object.create(CircuitElement.prototype);
Ground.prototype.tooltipText = "Ground: All bits are Low(0).";
Ground.prototype.helplink = "https://docs.circuitverse.org/#/inputElements?id=ground";
Ground.prototype.constructor = Ground;
Ground.prototype.propagationDelay = 0;
Ground.prototype.customSave = function () {
    var data = {
        nodes: {
            output1: findNode(this.output1)
        },
        values: {
            state: this.state
        },
        constructorParamaters: [this.direction, this.bitWidth]
    }
    return data;
}
Ground.prototype.resolve = function () {
    this.output1.value = 0;
    simulationArea.simulationQueue.add(this.output1);
}
Ground.prototype.customSave = function () {
    var data = {
        nodes: {
            output1: findNode(this.output1)
        },
        constructorParamaters: [this.bitWidth],
    }
    return data;
}
Ground.prototype.customDraw = function () {

    ctx = simulationArea.context;

    ctx.beginPath();
    ctx.strokeStyle = ["black", "brown"][((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) + 0];
    ctx.lineWidth = correctWidth(3);

    var xx = this.x;
    var yy = this.y;

    moveTo(ctx, 0, -10, xx, yy, this.direction);
    lineTo(ctx, 0, 0, xx, yy, this.direction);
    moveTo(ctx, -10, 0, xx, yy, this.direction);
    lineTo(ctx, 10, 0, xx, yy, this.direction);
    moveTo(ctx, -6, 5, xx, yy, this.direction);
    lineTo(ctx, 6, 5, xx, yy, this.direction);
    moveTo(ctx, -2.5, 10, xx, yy, this.direction);
    lineTo(ctx, 2.5, 10, xx, yy, this.direction);
    ctx.stroke();
}
//Ground translated into assign
Ground.prototype.generateVerilog = function () {
    return `assign ${this.output1.verilogLabel} = ${this.bitWidth}'b0;`;
}

function Power(x, y, scope = globalScope, bitWidth = 1) {

    CircuitElement.call(this, x, y, scope, "RIGHT", bitWidth);
    this.directionFixed = true;
    this.rectangleObject = false;
    this.setDimensions(10, 10);
    this.output1 = new Node(0, 10, 1, this);
}
Power.prototype = Object.create(CircuitElement.prototype);
Power.prototype.tooltipText = "Power: All bits are High(1).";
Power.prototype.helplink = "https://docs.circuitverse.org/#/inputElements?id=power";
Power.prototype.constructor = Power;
Power.prototype.propagationDelay = 0;
Power.prototype.resolve = function () {
    this.output1.value = ~0 >>> (32 - this.bitWidth);
    simulationArea.simulationQueue.add(this.output1);
}
Power.prototype.customSave = function () {
    var data = {

        nodes: {
            output1: findNode(this.output1)
        },
        constructorParamaters: [this.bitWidth],
    }
    return data;
}
Power.prototype.customDraw = function () {

    ctx = simulationArea.context;

    var xx = this.x;
    var yy = this.y;

    ctx.beginPath();
    ctx.strokeStyle = ("rgba(0,0,0,1)");
    ctx.lineWidth = correctWidth(3);
    ctx.fillStyle = "green";
    moveTo(ctx, 0, -10, xx, yy, this.direction);
    lineTo(ctx, -10, 0, xx, yy, this.direction);
    lineTo(ctx, 10, 0, xx, yy, this.direction);
    lineTo(ctx, 0, -10, xx, yy, this.direction);
    ctx.closePath();
    ctx.stroke();
    if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";
    ctx.fill();
    moveTo(ctx, 0, 0, xx, yy, this.direction);
    lineTo(ctx, 0, 10, xx, yy, this.direction);
    ctx.stroke();

}
//Power translated into assign
Power.prototype.generateVerilog = function () {
    return `assign ${this.output1.verilogLabel} = ~${this.bitWidth}'b0;`;
}

function get_next_position(x = 0, scope = globalScope) {
    var possible_y = 20;

    var done = {}
    for (var i = 0; i < scope.Input.length; i++)
        if (scope.Input[i].layoutProperties.x == x)
            done[scope.Input[i].layoutProperties.y] = 1
    for (var i = 0; i < scope.Output.length; i++)
        if (scope.Output[i].layoutProperties.x == x)
            done[scope.Output[i].layoutProperties.y] = 1

    // console.log(done)
    // return possible_y;

    while (done[possible_y] || done[possible_y + 10] || done[possible_y - 10])
        possible_y += 10;


    var height = possible_y + 20;
    if (height > scope.layout.height) {
        var old_height = scope.layout.height
        scope.layout.height = height;
        for (var i = 0; i < scope.Input.length; i++) {
            if (scope.Input[i].layoutProperties.y == old_height)
                scope.Input[i].layoutProperties.y = scope.layout.height;
        }
        for (var i = 0; i < scope.Output.length; i++) {
            if (scope.Output[i].layoutProperties.y == old_height)
                scope.Output[i].layoutProperties.y = scope.layout.height;
        }
    }
    return possible_y;
}

function Input(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1, layoutProperties) {

    if (layoutProperties)
        this.layoutProperties = layoutProperties;
    else {
        this.layoutProperties = {
            x: 0,
            y: get_next_position(0, scope),
            id: generateId(),
        }
    }

    // Call base class constructor
    CircuitElement.call(this, x, y, scope, dir, bitWidth);
    this.state = 0;
    this.orientationFixed = false;
    this.state = bin2dec(this.state); // in integer format
    this.output1 = new Node(this.bitWidth * 10, 0, 1, this);
    this.wasClicked = false;
    this.directionFixed = true;
    this.setWidth(this.bitWidth * 10);
    this.rectangleObject = true; // Trying to make use of base class draw



}
Input.prototype = Object.create(CircuitElement.prototype);
Input.prototype.constructor = Input;
Input.prototype.tooltipText = "Input ToolTip: Toggle the individual bits by clicking on them."
Input.prototype.helplink = "https://docs.circuitverse.org/#/inputElements?id=input";
Input.prototype.propagationDelay = 0;
Input.prototype.customSave = function () {
    var data = {
        nodes: {
            output1: findNode(this.output1)
        },
        values: {
            state: this.state
        },
        constructorParamaters: [this.direction, this.bitWidth, this.layoutProperties]
    }
    return data;
}
Input.prototype.resolve = function () {
    this.output1.value = this.state;
    simulationArea.simulationQueue.add(this.output1);
}
// Check if override is necessary!!
Input.prototype.newBitWidth = function (bitWidth) {
    if (bitWidth < 1) return;
    var diffBitWidth = bitWidth - this.bitWidth;
    this.bitWidth = bitWidth; //||parseInt(prompt("Enter bitWidth"),10);
    this.setWidth(this.bitWidth * 10);
    this.state = 0;
    this.output1.bitWidth = bitWidth;
    if (this.direction == "RIGHT") {
        this.x -= 10 * diffBitWidth;
        this.output1.x = 10 * this.bitWidth;
        this.output1.leftx = 10 * this.bitWidth;
    } else if (this.direction == "LEFT") {
        this.x += 10 * diffBitWidth;
        this.output1.x = -10 * this.bitWidth;
        this.output1.leftx = 10 * this.bitWidth;
    }
}
Input.prototype.click = function () { // toggle
    var pos = this.findPos();
    if (pos == 0) pos = 1; // minor correction
    if (pos < 1 || pos > this.bitWidth) return;
    this.state = ((this.state >>> 0) ^ (1 << (this.bitWidth - pos))) >>> 0;
}
Input.prototype.customDraw = function () {

    ctx = simulationArea.context;
    ctx.beginPath();
    ctx.strokeStyle = ("rgba(0,0,0,1)");
    ctx.lineWidth = correctWidth(3);
    var xx = this.x;
    var yy = this.y;

    ctx.beginPath();
    ctx.fillStyle = "green";
    ctx.textAlign = "center";
    var bin = dec2bin(this.state, this.bitWidth);
    for (var k = 0; k < this.bitWidth; k++)
        fillText(ctx, bin[k], xx - 10 * this.bitWidth + 10 + (k) * 20, yy + 5);
    ctx.fill();


}
Input.prototype.newDirection = function (dir) {
    if (dir == this.direction) return;
    this.direction = dir;
    this.output1.refresh();
    if (dir == "RIGHT" || dir == "LEFT") {
        this.output1.leftx = 10 * this.bitWidth;
        this.output1.lefty = 0;
    } else {
        this.output1.leftx = 10; //10*this.bitWidth;
        this.output1.lefty = 0;
    }

    this.output1.refresh();
    this.labelDirection = oppositeDirection[this.direction];
}
Input.prototype.findPos = function () {
    return Math.round((simulationArea.mouseX - this.x + 10 * this.bitWidth) / 20.0);
}

function Output(x, y, scope = globalScope, dir = "LEFT", bitWidth = 1, layoutProperties) {
    // Calling base class constructor

    if (layoutProperties)
        this.layoutProperties = layoutProperties
    else {
        this.layoutProperties = {
            x: scope.layout.width,
            y: get_next_position(scope.layout.width, scope),
            id: generateId(),
        }
    }


    CircuitElement.call(this, x, y, scope, dir, bitWidth);
    this.rectangleObject = false;
    this.directionFixed = true;
    this.orientationFixed = false;
    this.setDimensions(this.bitWidth * 10, 10);
    this.inp1 = new Node(this.bitWidth * 10, 0, 0, this);


}
Output.prototype = Object.create(CircuitElement.prototype);
Output.prototype.constructor = Output;
Output.prototype.tooltipText = "Output ToolTip: Simple output element showing output in binary.";
Output.prototype.helplink = "https://docs.circuitverse.org/#/outputs?id=output";
Output.prototype.propagationDelay = 0;
Output.prototype.generateVerilog = function () {
    return "assign " + this.verilogLabel + " = " + this.inp1.verilogLabel + ";"
}

Output.prototype.customSave = function () {
    var data = {
        nodes: {
            inp1: findNode(this.inp1)
        },
        constructorParamaters: [this.direction, this.bitWidth, this.layoutProperties],
    }
    return data;
}
Output.prototype.newBitWidth = function (bitWidth) {
    if (bitWidth < 1) return;
    var diffBitWidth = bitWidth - this.bitWidth;
    this.state = undefined;
    this.inp1.bitWidth = bitWidth;
    this.bitWidth = bitWidth;
    this.setWidth(10 * this.bitWidth);

    if (this.direction == "RIGHT") {
        this.x -= 10 * diffBitWidth;
        this.inp1.x = 10 * this.bitWidth;
        this.inp1.leftx = 10 * this.bitWidth;
    } else if (this.direction == "LEFT") {
        this.x += 10 * diffBitWidth;
        this.inp1.x = -10 * this.bitWidth;
        this.inp1.leftx = 10 * this.bitWidth;
    }
}
Output.prototype.customDraw = function () {
    this.state = this.inp1.value;
    ctx = simulationArea.context;
    ctx.beginPath();
    ctx.strokeStyle = ["blue", "red"][+(this.inp1.value == undefined)];
    ctx.fillStyle = "white";
    ctx.lineWidth = correctWidth(3);
    var xx = this.x;
    var yy = this.y;

    rect2(ctx, -10 * this.bitWidth, -10, 20 * this.bitWidth, 20, 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.beginPath();
    ctx.font = "20px Georgia";
    ctx.fillStyle = "green";
    ctx.textAlign = "center";
    if (this.state === undefined)
        var bin = 'x'.repeat(this.bitWidth);
    else
        var bin = dec2bin(this.state, this.bitWidth);

    for (var k = 0; k < this.bitWidth; k++)
        fillText(ctx, bin[k], xx - 10 * this.bitWidth + 10 + (k) * 20, yy + 5);
    ctx.fill();

}
Output.prototype.newDirection = function (dir) {
    if (dir == this.direction) return;
    this.direction = dir;
    this.inp1.refresh();
    if (dir == "RIGHT" || dir == "LEFT") {
        this.inp1.leftx = 10 * this.bitWidth;
        this.inp1.lefty = 0;
    } else {
        this.inp1.leftx = 10; //10*this.bitWidth;
        this.inp1.lefty = 0;
    }

    this.inp1.refresh();
    this.labelDirection = oppositeDirection[this.direction];
}

function BitSelector(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 2, selectorBitWidth = 1) {

    CircuitElement.call(this, x, y, scope, dir, bitWidth);
    this.setDimensions(20, 20);
    this.selectorBitWidth = selectorBitWidth || parseInt(prompt("Enter Selector bitWidth"), 10);
    this.rectangleObject = false;
    this.inp1 = new Node(-20, 0, 0, this, this.bitWidth, "Input");
    this.output1 = new Node(20, 0, 1, this, 1, "Output");
    this.bitSelectorInp = new Node(0, 20, 0, this, this.selectorBitWidth, "Bit Selector");

}
BitSelector.prototype = Object.create(CircuitElement.prototype);
BitSelector.prototype.constructor = BitSelector;
BitSelector.prototype.tooltipText = "BitSelector ToolTip : Divides input bits into several equal-sized groups.";
BitSelector.prototype.helplink = "https://docs.circuitverse.org/#/decodersandplexers?id=bit-selector";
BitSelector.prototype.changeSelectorBitWidth = function (size) {
    if (size == undefined || size < 1 || size > 32) return;
    this.selectorBitWidth = size;
    this.bitSelectorInp.bitWidth = size;
}
BitSelector.prototype.mutableProperties = {
    "selectorBitWidth": {
        name: "Selector Bit Width: ",
        type: "number",
        max: "32",
        min: "1",
        func: "changeSelectorBitWidth",
    }
}
BitSelector.prototype.customSave = function () {
    var data = {

        nodes: {
            inp1: findNode(this.inp1),
            output1: findNode(this.output1),
            bitSelectorInp: findNode(this.bitSelectorInp)
        },
        constructorParamaters: [this.direction, this.bitWidth, this.selectorBitWidth],
    }
    return data;
}
BitSelector.prototype.newBitWidth = function (bitWidth) {
    this.inp1.bitWidth = bitWidth;
    this.bitWidth = bitWidth;
}
BitSelector.prototype.resolve = function () {
    this.output1.value = extractBits(this.inp1.value, this.bitSelectorInp.value + 1, this.bitSelectorInp.value + 1); //(this.inp1.value^(1<<this.bitSelectorInp.value))==(1<<this.bitSelectorInp.value);
    simulationArea.simulationQueue.add(this.output1);
}
BitSelector.prototype.customDraw = function () {

    ctx = simulationArea.context;
    ctx.beginPath();
    ctx.strokeStyle = ["blue", "red"][(this.state === undefined) + 0];
    ctx.fillStyle = "white";
    ctx.lineWidth = correctWidth(3);
    var xx = this.x;
    var yy = this.y;
    rect(ctx, xx - 20, yy - 20, 40, 40);
    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.beginPath();
    ctx.font = "20px Georgia";
    ctx.fillStyle = "green";
    ctx.textAlign = "center";
    if (this.bitSelectorInp.value === undefined)
        var bit = 'x';
    else
        var bit = this.bitSelectorInp.value;

    fillText(ctx, bit, xx, yy + 5);
    ctx.fill();
}
BitSelector.prototype.generateVerilog = function () {
    return `assign ${this.output1.verilogLabel} = ${this.inp1.verilogLabel} >> ${this.bitSelectorInp.verilogLabel};`;
}

function ConstantVal(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1, state = "0") {
    this.state = state || prompt("Enter value");
    CircuitElement.call(this, x, y, scope, dir, this.state.length);
    this.setDimensions(10 * this.state.length, 10);
    this.bitWidth = bitWidth || this.state.length;
    this.directionFixed = true;
    this.orientationFixed = false;
    this.rectangleObject = false;

    this.output1 = new Node(this.bitWidth * 10, 0, 1, this);
    this.wasClicked = false;
    this.label = "";

}
ConstantVal.prototype = Object.create(CircuitElement.prototype);
ConstantVal.prototype.constructor = ConstantVal;
ConstantVal.prototype.tooltipText = "Constant ToolTip: Bits are fixed. Double click element to change the bits."
ConstantVal.prototype.helplink = "https://docs.circuitverse.org/#/inputElements?id=constantval";
ConstantVal.prototype.propagationDelay = 0;
ConstantVal.prototype.customSave = function () {
    var data = {
        nodes: {
            output1: findNode(this.output1)
        },
        constructorParamaters: [this.direction, this.bitWidth, this.state],
    }
    return data;
}
ConstantVal.prototype.resolve = function () {
    this.output1.value = bin2dec(this.state);
    simulationArea.simulationQueue.add(this.output1);
}
ConstantVal.prototype.dblclick = function () {
    this.state = prompt("Re enter the value") || "0";
    //console.log(this.state);
    this.newBitWidth(this.state.toString().length);
    //console.log(this.state, this.bitWidth);
}
ConstantVal.prototype.newBitWidth = function (bitWidth) {
    if (bitWidth > this.state.length) this.state = '0'.repeat(bitWidth - this.state.length) + this.state;
    else if (bitWidth < this.state.length) this.state = this.state.slice(this.bitWidth - bitWidth);
    this.bitWidth = bitWidth; //||parseInt(prompt("Enter bitWidth"),10);
    this.output1.bitWidth = bitWidth;
    this.setDimensions(10 * this.bitWidth, 10);
    if (this.direction == "RIGHT") {
        this.output1.x = 10 * this.bitWidth;
        this.output1.leftx = 10 * this.bitWidth;
    } else if (this.direction == "LEFT") {
        this.output1.x = -10 * this.bitWidth;
        this.output1.leftx = 10 * this.bitWidth;
    }
}
ConstantVal.prototype.customDraw = function () {

    ctx = simulationArea.context;
    ctx.beginPath();
    ctx.strokeStyle = ("rgba(0,0,0,1)");
    ctx.fillStyle = "white";
    ctx.lineWidth = correctWidth(1);
    var xx = this.x;
    var yy = this.y;

    rect2(ctx, -10 * this.bitWidth, -10, 20 * this.bitWidth, 20, 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.beginPath();
    ctx.fillStyle = "green";
    ctx.textAlign = "center";
    var bin = this.state; //dec2bin(this.state,this.bitWidth);
    for (var k = 0; k < this.bitWidth; k++)
        fillText(ctx, bin[k], xx - 10 * this.bitWidth + 10 + (k) * 20, yy + 5);
    ctx.fill();

}
ConstantVal.prototype.newDirection = function (dir) {
    if (dir == this.direction) return;
    this.direction = dir;
    this.output1.refresh();
    if (dir == "RIGHT" || dir == "LEFT") {
        this.output1.leftx = 10 * this.bitWidth;
        this.output1.lefty = 0;
    } else {
        this.output1.leftx = 10; //10*this.bitWidth;
        this.output1.lefty = 0;
    }

    this.output1.refresh();
    this.labelDirection = oppositeDirection[this.direction];
}
//ConstantValue translated into assign
ConstantVal.prototype.generateVerilog = function () {
    return `assign ${this.output1.verilogLabel} = ${this.bitWidth}'b${this.state};`;
}

function NorGate(x, y, scope = globalScope, dir = "RIGHT", inputs = 2, bitWidth = 1) {

    CircuitElement.call(this, x, y, scope, dir, bitWidth);
    this.rectangleObject = false;
    this.setDimensions(15, 20);

    this.inp = [];
    this.inputSize = inputs;

    if (inputs % 2 == 1) {
        for (var i = 0; i < inputs / 2 - 1; i++) {
            var a = new Node(-10, -10 * (i + 1), 0, this);
            this.inp.push(a);
        }
        var a = new Node(-10, 0, 0, this);
        this.inp.push(a);
        for (var i = inputs / 2 + 1; i < inputs; i++) {
            var a = new Node(-10, 10 * (i + 1 - inputs / 2 - 1), 0, this);
            this.inp.push(a);
        }
    } else {
        for (var i = 0; i < inputs / 2; i++) {
            var a = new Node(-10, -10 * (i + 1), 0, this);
            this.inp.push(a);
        }
        for (var i = inputs / 2; i < inputs; i++) {
            var a = new Node(-10, 10 * (i + 1 - inputs / 2), 0, this);
            this.inp.push(a);
        }
    }
    this.output1 = new Node(30, 0, 1, this);


}
NorGate.prototype = Object.create(CircuitElement.prototype);
NorGate.prototype.constructor = NorGate;
NorGate.prototype.tooltipText = "Nor Gate ToolTip : Combination of OR gate and NOT gate.";
NorGate.prototype.alwaysResolve = true;
NorGate.prototype.changeInputSize = changeInputSize;
NorGate.prototype.verilogType = "nor";
NorGate.prototype.helplink = "https://docs.circuitverse.org/#/gates?id=nor-gate";
NorGate.prototype.customSave = function () {
    var data = {
        constructorParamaters: [this.direction, this.inputSize, this.bitWidth],
        nodes: {
            inp: this.inp.map(findNode),
            output1: findNode(this.output1)
        },
    }
    return data;
}
NorGate.prototype.resolve = function () {
    var result = this.inp[0].value || 0;
    for (var i = 1; i < this.inputSize; i++)
        result = result | (this.inp[i].value || 0);
    result = ((~result >>> 0) << (32 - this.bitWidth)) >>> (32 - this.bitWidth);
    this.output1.value = result
    simulationArea.simulationQueue.add(this.output1);
}
NorGate.prototype.customDraw = function () {

    ctx = simulationArea.context;
    ctx.strokeStyle = ("rgba(0,0,0,1)");
    ctx.lineWidth = correctWidth(3);

    var xx = this.x;
    var yy = this.y;
    ctx.beginPath();
    ctx.fillStyle = "white";

    moveTo(ctx, -10, -20, xx, yy, this.direction, true);
    bezierCurveTo(0, -20, +15, -10, 20, 0, xx, yy, this.direction);
    bezierCurveTo(0 + 15, 0 + 10, 0, 0 + 20, -10, +20, xx, yy, this.direction);
    bezierCurveTo(0, 0, 0, 0, -10, -20, xx, yy, this.direction);
    ctx.closePath();
    if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.5)";
    ctx.fill();
    ctx.stroke();
    ctx.beginPath();
    drawCircle2(ctx, 25, 0, 5, xx, yy, this.direction);
    ctx.stroke();
    //for debugging
}
//translate to gate for single bit, assign for multi bit
NorGate.prototype.generateVerilog = function () {
    return gateGenerateVerilog.call(this, '|', true);
}


function DigitalLed(x, y, scope = globalScope, color = "Red") {
    // Calling base class constructor

    CircuitElement.call(this, x, y, scope, "UP", 1);
    this.rectangleObject = false;
    this.setDimensions(10, 20);
    this.inp1 = new Node(-40, 0, 0, this, 1);
    this.directionFixed = true;
    this.fixedBitWidth = true;
    this.color = color;
    var temp = colorToRGBA(this.color)
    this.actualColor = "rgba(" + temp[0] + "," + temp[1] + "," + temp[2] + "," + 0.8 + ")";


}
DigitalLed.prototype = Object.create(CircuitElement.prototype);
DigitalLed.prototype.constructor = DigitalLed;
/* Outdated, was translating into Output
DigitalLed.prototype.generateVerilog = function () {
    return "assign " + this.label + " = " + this.inp1.verilogLabel + ";"
}
*/
/*
//DigitalLed translated into $display
DigitalLed.prototype.generateVerilog = function () {
    var output = "";
    output += "\n";
    output += "  always @ (" + this.inp1.verilogLabel + ")\n";
    output += "    $display(\"" + this.inp1.verilogLabel + " = %d\", "
        + this.inp1.verilogLabel + ");\n";
    return output;

}
*/
DigitalLed.prototype.tooltipText = "Digital Led ToolTip: Digital LED glows high when input is High(1)."
DigitalLed.prototype.helplink = "https://docs.circuitverse.org/#/outputs?id=digital-led";

DigitalLed.prototype.customSave = function () {
    var data = {
        constructorParamaters: [this.color],
        nodes: {
            inp1: findNode(this.inp1)
        },
    }
    return data;
}
DigitalLed.prototype.mutableProperties = {
    "color": {
        name: "Color: ",
        type: "text",
        func: "changeColor",
    },
}
DigitalLed.prototype.changeColor = function (value) {
    if (validColor(value)) {
        this.color = value;
        var temp = colorToRGBA(this.color)
        this.actualColor = "rgba(" + temp[0] + "," + temp[1] + "," + temp[2] + "," + 0.8 + ")";
    }

}
DigitalLed.prototype.customDraw = function () {

    ctx = simulationArea.context;

    var xx = this.x;
    var yy = this.y;

    ctx.strokeStyle = "#e3e4e5";
    ctx.lineWidth = correctWidth(3);
    ctx.beginPath();
    moveTo(ctx, -20, 0, xx, yy, this.direction);
    lineTo(ctx, -40, 0, xx, yy, this.direction);
    ctx.stroke();

    ctx.strokeStyle = "#d3d4d5";
    ctx.fillStyle = ["rgba(227,228,229,0.8)", this.actualColor][this.inp1.value || 0];
    ctx.lineWidth = correctWidth(1);

    ctx.beginPath();

    moveTo(ctx, -15, -9, xx, yy, this.direction);
    lineTo(ctx, 0, -9, xx, yy, this.direction);
    arc(ctx, 0, 0, 9, (-Math.PI / 2), (Math.PI / 2), xx, yy, this.direction);
    lineTo(ctx, -15, 9, xx, yy, this.direction);
    lineTo(ctx, -18, 12, xx, yy, this.direction);
    arc(ctx, 0, 0, Math.sqrt(468), ((Math.PI / 2) + Math.acos(12 / Math.sqrt(468))), ((-Math.PI / 2) - Math.asin(18 / Math.sqrt(468))), xx, yy, this.direction);
    lineTo(ctx, -15, -9, xx, yy, this.direction);
    ctx.stroke();
    if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";
    ctx.fill();

}
//Use $display
DigitalLed.prototype.generateVerilog = function () {

    var label = this.label ? this.verilogLabel : this.inp1.verilogLabel;
    return `
  always @ (*)
    $display("DigitalLed:${label}=%d", ${this.inp1.verilogLabel});`;
}
/* Outdated, was translating into Output
DigitalLed.prototype.generateVerilog = function () {
    return "assign " + this.label + " = " + this.inp1.verilogLabel + ";"
}
*/
//DigitalLed translated into $display
// DigitalLed.prototype.generateVerilog = function () {
//     var output = "";
//     output += "  always @ (" + this.inp1.verilogLabel + ")\n";
//     output += "    $display(\"" + this.inp1.verilogLabel + " = %d\", "
//         + this.inp1.verilogLabel + ");";
//     return output;
// }


function VariableLed(x, y, scope = globalScope) {
    // Calling base class constructor

    CircuitElement.call(this, x, y, scope, "UP", 8);
    this.rectangleObject = false;
    this.setDimensions(10, 20);
    this.inp1 = new Node(-40, 0, 0, this, 8);
    this.directionFixed = true;
    this.fixedBitWidth = true;


}
VariableLed.prototype = Object.create(CircuitElement.prototype);
VariableLed.prototype.constructor = VariableLed;
VariableLed.prototype.tooltipText = "Variable Led ToolTip: Variable LED inputs an 8 bit value and glows with a proportional intensity."
VariableLed.prototype.helplink = "https://docs.circuitverse.org/#/outputs?id=variable-led";
VariableLed.prototype.customSave = function () {
    var data = {
        nodes: {
            inp1: findNode(this.inp1)
        },
    }
    return data;
}
VariableLed.prototype.customDraw = function () {

    ctx = simulationArea.context;

    var xx = this.x;
    var yy = this.y;

    ctx.strokeStyle = "#353535";
    ctx.lineWidth = correctWidth(3);
    ctx.beginPath();
    moveTo(ctx, -20, 0, xx, yy, this.direction);
    lineTo(ctx, -40, 0, xx, yy, this.direction);
    ctx.stroke();
    var c = this.inp1.value;
    var alpha = c / 255;
    ctx.strokeStyle = "#090a0a";
    ctx.fillStyle = ["rgba(255,29,43," + alpha + ")", "rgba(227, 228, 229, 0.8)"][(c === undefined || c == 0) + 0];
    ctx.lineWidth = correctWidth(1);

    ctx.beginPath();

    moveTo(ctx, -20, -9, xx, yy, this.direction);
    lineTo(ctx, 0, -9, xx, yy, this.direction);
    arc(ctx, 0, 0, 9, (-Math.PI / 2), (Math.PI / 2), xx, yy, this.direction);
    lineTo(ctx, -20, 9, xx, yy, this.direction);
    /*lineTo(ctx,-18,12,xx,yy,this.direction);
    arc(ctx,0,0,Math.sqrt(468),((Math.PI/2) + Math.acos(12/Math.sqrt(468))),((-Math.PI/2) - Math.asin(18/Math.sqrt(468))),xx,yy,this.direction);
    */
    lineTo(ctx, -20, -9, xx, yy, this.direction);
    ctx.stroke();
    if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";
    ctx.fill();

}
VariableLed.prototype.generateVerilog = function () {
    return `
  always @ (*)
    $display("VeriableLed:${this.inp1.verilogLabel}=%d", ${this.inp1.verilogLabel});`;
}

function Button(x, y, scope = globalScope, dir = "RIGHT") {
    CircuitElement.call(this, x, y, scope, dir, 1);
    this.state = 0;
    this.output1 = new Node(30, 0, 1, this);
    this.wasClicked = false;
    this.rectangleObject = false;
    this.setDimensions(10, 10);


}
Button.prototype = Object.create(CircuitElement.prototype);
Button.prototype.constructor = Button;
Button.prototype.tooltipText = "Button ToolTip: High(1) when pressed and Low(0) when released."
Button.prototype.helplink = "https://docs.circuitverse.org/#/inputElements?id=button";
Button.prototype.propagationDelay = 0;
Button.prototype.customSave = function () {
    var data = {
        nodes: {
            output1: findNode(this.output1)
        },
        values: {
            state: this.state
        },
        constructorParamaters: [this.direction, this.bitWidth]
    }
    return data;
}
Button.prototype.resolve = function () {
    if (this.wasClicked) {
        this.state = 1;
        this.output1.value = this.state;
    } else {
        this.state = 0;
        this.output1.value = this.state;
    }
    simulationArea.simulationQueue.add(this.output1);
}
Button.prototype.customDraw = function () {
    ctx = simulationArea.context;
    var xx = this.x;
    var yy = this.y;
    ctx.fillStyle = "#ddd";

    ctx.strokeStyle = "#353535";
    ctx.lineWidth = correctWidth(5);

    ctx.beginPath();

    moveTo(ctx, 10, 0, xx, yy, this.direction);
    lineTo(ctx, 30, 0, xx, yy, this.direction);
    ctx.stroke();

    ctx.beginPath();

    drawCircle2(ctx, 0, 0, 12, xx, yy, this.direction);
    ctx.stroke();

    if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this))
        ctx.fillStyle = "rgba(232, 13, 13,0.6)"

    if (this.wasClicked)
        ctx.fillStyle = "rgba(232, 13, 13,0.8)";
    ctx.fill();
}
Button.verilogInstructions = function() {
    return `Button - Buttons are not natively supported in verilog, consider using Inputs instead\n`;
}
Button.prototype.verilogBaseType = function() {
    return this.verilogName() + (Button.selSizes.length-1);
}
//this code to generate Verilog
Button.prototype.generateVerilog = function () {
    Button.selSizes.push(this.data);
    return CircuitElement.prototype.generateVerilog.call(this);
}
//This code to determine what sizes are used to generate the needed modules
Button.selSizes = [];
//generate the needed modules
Button.moduleVerilog = function () {
    var output = "";

    for (var i = 0; i < Button.selSizes.length; i++) {
         output += `// Skeleton for Button${i}
/*
module Button${i}(out);
  output reg out;

  initial begin
    //do something with the button here
  end
endmodule
*/
`;
    }

    return output;
}
//reset the sized before Verilog generation
Button.resetVerilog = function () {
    Button.selSizes = [];
}

function RGBLed(x, y, scope = globalScope) {
    // Calling base class constructor

    CircuitElement.call(this, x, y, scope, "UP", 8);
    this.rectangleObject = false;
    this.inp = [];
    this.setDimensions(10, 10);
    this.inp1 = new Node(-40, -10, 0, this, 8);
    this.inp2 = new Node(-40, 0, 0, this, 8);
    this.inp3 = new Node(-40, 10, 0, this, 8);
    this.inp.push(this.inp1);
    this.inp.push(this.inp2);
    this.inp.push(this.inp3);
    this.directionFixed = true;
    this.fixedBitWidth = true;


}
RGBLed.prototype = Object.create(CircuitElement.prototype);
RGBLed.prototype.constructor = RGBLed;
RGBLed.prototype.tooltipText = "RGB Led ToolTip: RGB Led inputs 8 bit values for the colors RED, GREEN and BLUE."
RGBLed.prototype.helplink = "https://docs.circuitverse.org/#/outputs?id=rgb-led";
RGBLed.prototype.customSave = function () {
    var data = {
        nodes: {
            inp1: findNode(this.inp1),
            inp2: findNode(this.inp2),
            inp3: findNode(this.inp3),
        },
    }
    return data;
}
RGBLed.prototype.customDraw = function () {

    ctx = simulationArea.context;

    var xx = this.x;
    var yy = this.y;

    ctx.strokeStyle = "green";
    ctx.lineWidth = correctWidth(3);
    ctx.beginPath();
    moveTo(ctx, -20, 0, xx, yy, this.direction);
    lineTo(ctx, -40, 0, xx, yy, this.direction);
    ctx.stroke();

    ctx.strokeStyle = "red";
    ctx.lineWidth = correctWidth(3);
    ctx.beginPath();
    moveTo(ctx, -20, -10, xx, yy, this.direction);
    lineTo(ctx, -40, -10, xx, yy, this.direction);
    ctx.stroke();

    ctx.strokeStyle = "blue";
    ctx.lineWidth = correctWidth(3);
    ctx.beginPath();
    moveTo(ctx, -20, 10, xx, yy, this.direction);
    lineTo(ctx, -40, 10, xx, yy, this.direction);
    ctx.stroke();

    var a = this.inp1.value;
    var b = this.inp2.value;
    var c = this.inp3.value;
    ctx.strokeStyle = "#d3d4d5";
    ctx.fillStyle = ["rgba(" + a + ", " + b + ", " + c + ", 0.8)", "rgba(227, 228, 229, 0.8)"][((a === undefined || b === undefined || c === undefined)) + 0]
    //ctx.fillStyle = ["rgba(200, 200, 200, 0.3)","rgba(227, 228, 229, 0.8)"][((a === undefined || b === undefined || c === undefined) || (a == 0 && b == 0 && c == 0)) + 0];
    ctx.lineWidth = correctWidth(1);

    ctx.beginPath();

    moveTo(ctx, -18, -11, xx, yy, this.direction);
    lineTo(ctx, 0, -11, xx, yy, this.direction);
    arc(ctx, 0, 0, 11, (-Math.PI / 2), (Math.PI / 2), xx, yy, this.direction);
    lineTo(ctx, -18, 11, xx, yy, this.direction);
    lineTo(ctx, -21, 15, xx, yy, this.direction);
    arc(ctx, 0, 0, Math.sqrt(666), ((Math.PI / 2) + Math.acos(15 / Math.sqrt(666))), ((-Math.PI / 2) - Math.asin(21 / Math.sqrt(666))), xx, yy, this.direction);
    lineTo(ctx, -18, -11, xx, yy, this.direction);
    ctx.stroke();
    if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";
    ctx.fill();
}
RGBLed.prototype.generateVerilog = function () {
    return `
  always @ (*)
    $display("RGBLed:{${this.inp1.verilogLabel},${this.inp2.verilogLabel},${this.inp3.verilogLabel}} = {%d,%d,%d}", ${this.inp1.verilogLabel}, ${this.inp2.verilogLabel}, ${this.inp3.verilogLabel});`;
}

function SquareRGBLed(x, y, scope = globalScope, dir = "UP", pinLength = 1) {
    CircuitElement.call(this, x, y, scope, dir, 8);
    this.rectangleObject = false;
    this.setDimensions(15, 15);
    this.pinLength = pinLength === undefined ? 1 : pinLength;
    var nodeX = -10 - 10 * pinLength;
    this.inp1 = new Node(nodeX, -10, 0, this, 8, "R");
    this.inp2 = new Node(nodeX, 0, 0, this, 8, "G");
    this.inp3 = new Node(nodeX, 10, 0, this, 8, "B");
    this.inp = [this.inp1, this.inp2, this.inp3];
    this.labelDirection = "UP";
    this.fixedBitWidth = true;

    this.changePinLength = function (pinLength) {
        if (pinLength == undefined) return;
        pinLength = parseInt(pinLength, 10);
        if (pinLength < 0 || pinLength > 1000) return;

        // Calculate the new position of the LED, so the nodes will stay in the same place.
        var diff = 10 * (pinLength - this.pinLength);
        var diffX = this.direction == "LEFT" ? -diff : this.direction == "RIGHT" ? diff : 0;
        var diffY = this.direction == "UP" ? -diff : this.direction == "DOWN" ? diff : 0;

        // Build a new LED with the new values; preserve label properties too.
        var obj = new window[this.objectType](this.x + diffX, this.y + diffY, this.scope, this.direction, pinLength);
        obj.label = this.label;
        obj.labelDirection = this.labelDirection;

        this.cleanDelete();
        simulationArea.lastSelected = obj;
        return obj;
    }

    this.mutableProperties = {
        "pinLength": {
            name: "Pin Length",
            type: "number",
            max: "1000",
            min: "0",
            func: "changePinLength",
        },
    }
}
SquareRGBLed.prototype = Object.create(CircuitElement.prototype);
SquareRGBLed.prototype.constructor = SquareRGBLed;
SquareRGBLed.prototype.tooltipText = "Square RGB Led ToolTip: RGB Led inputs 8 bit values for the colors RED, GREEN and BLUE."
SquareRGBLed.prototype.helplink = "https://docs.circuitverse.org/#/outputs?id=square-rgb-led";
SquareRGBLed.prototype.customSave = function () {
    var data = {
        constructorParamaters: [this.direction, this.pinLength],
        nodes: {
            inp1: findNode(this.inp1),
            inp2: findNode(this.inp2),
            inp3: findNode(this.inp3),
        },
    }
    return data;
}
SquareRGBLed.prototype.customDraw = function () {
    var ctx = simulationArea.context;
    var xx = this.x;
    var yy = this.y;
    var r = this.inp1.value;
    var g = this.inp2.value;
    var b = this.inp3.value;

    var colors = ["rgb(174,20,20)", "rgb(40,174,40)", "rgb(0,100,255)"];
    for (var i = 0; i < 3; i++) {
        var x = -10 - 10 * this.pinLength;
        var y = i * 10 - 10;
        ctx.lineWidth = correctWidth(3);

        // A gray line, which makes it easy on the eyes when the pin length is large
        ctx.beginPath();
        ctx.lineCap = "butt";
        ctx.strokeStyle = "rgb(227, 228, 229)";
        moveTo(ctx, -15, y, xx, yy, this.direction);
        lineTo(ctx, x + 10, y, xx, yy, this.direction);
        ctx.stroke();

        // A colored line, so people know which pin does what.
        ctx.lineCap = "round";
        ctx.beginPath();
        ctx.strokeStyle = colors[i];
        moveTo(ctx, x + 10, y, xx, yy, this.direction);
        lineTo(ctx, x, y, xx, yy, this.direction);
        ctx.stroke();
    }

    ctx.strokeStyle = "#d3d4d5";
    ctx.fillStyle = (r === undefined && g === undefined && b === undefined) ? "rgb(227, 228, 229)" : "rgb(" + (r || 0) + ", " + (g || 0) + ", " + (b || 0) + ")";
    ctx.lineWidth = correctWidth(1);
    ctx.beginPath();
    rect2(ctx, -15, -15, 30, 30, xx, yy, this.direction);
    ctx.stroke();

    if ((this.hover && !simulationArea.shiftDown) ||
        simulationArea.lastSelected == this ||
        simulationArea.multipleObjectSelections.contains(this)) {
        ctx.fillStyle = "rgba(255, 255, 32)";
    }

    ctx.fill();
}
SquareRGBLed.prototype.generateVerilog = function () {
    return RGBLed.prototype.generateVerilog.call(this);
}

function Demultiplexer(x, y, scope = globalScope, dir = "LEFT", bitWidth = 1, controlSignalSize = 1) {

    CircuitElement.call(this, x, y, scope, dir, bitWidth);
    this.controlSignalSize = controlSignalSize || parseInt(prompt("Enter control signal bitWidth"), 10);
    this.outputsize = 1 << this.controlSignalSize;
    this.xOff = 0;
    this.yOff = 1;
    if (this.controlSignalSize == 1) {
        this.xOff = 10;
    }
    if (this.controlSignalSize <= 3) {
        this.yOff = 2;
    }

    this.changeControlSignalSize = function (size) {
        if (size == undefined || size < 1 || size > 32) return;
        if (this.controlSignalSize == size) return;
        var obj = new window[this.objectType](this.x, this.y, this.scope, this.direction, this.bitWidth, size);
        this.cleanDelete();
        simulationArea.lastSelected = obj;
        return obj;
    }
    this.mutableProperties = {
        "controlSignalSize": {
            name: "Control Signal Size",
            type: "number",
            max: "32",
            min: "1",
            func: "changeControlSignalSize",
        },
    }
    this.newBitWidth = function (bitWidth) {
        this.bitWidth = bitWidth;
        for (var i = 0; i < this.outputsize; i++) {
            this.output1[i].bitWidth = bitWidth
        }
        this.input.bitWidth = bitWidth;
    }

    this.setDimensions(20 - this.xOff, this.yOff * 5 * (this.outputsize));
    this.rectangleObject = false;
    this.input = new Node(20 - this.xOff, 0, 0, this);

    this.output1 = [];
    for (var i = 0; i < this.outputsize; i++) {
        var a = new Node(-20 + this.xOff, +this.yOff * 10 * (i - this.outputsize / 2) + 10, 1, this);
        this.output1.push(a);
    }

    this.controlSignalInput = new Node(0, this.yOff * 10 * (this.outputsize / 2 - 1) + this.xOff + 10, 0, this, this.controlSignalSize, "Control Signal");


}
Demultiplexer.prototype = Object.create(CircuitElement.prototype);
Demultiplexer.prototype.constructor = Demultiplexer;
Demultiplexer.prototype.tooltipText = "DeMultiplexer ToolTip : Multiple outputs and a single line input.";
Demultiplexer.prototype.helplink = "https://docs.circuitverse.org/#/decodersandplexers?id=demultiplexer";
Demultiplexer.prototype.customSave = function () {
    var data = {
        constructorParamaters: [this.direction, this.bitWidth, this.controlSignalSize],
        nodes: {
            output1: this.output1.map(findNode),
            input: findNode(this.input),
            controlSignalInput: findNode(this.controlSignalInput)
        },
    }
    return data;
}
Demultiplexer.prototype.resolve = function () {

    for (var i = 0; i < this.output1.length; i++)
        this.output1[i].value = 0;

    this.output1[this.controlSignalInput.value].value = this.input.value;

    for (var i = 0; i < this.output1.length; i++)
        simulationArea.simulationQueue.add(this.output1[i]);

}
Demultiplexer.prototype.customDraw = function () {

    ctx = simulationArea.context;

    var xx = this.x;
    var yy = this.y;

    ctx.beginPath();
    moveTo(ctx, 0, this.yOff * 10 * (this.outputsize / 2 - 1) + 10 + 0.5 * this.xOff, xx, yy, this.direction);
    lineTo(ctx, 0, this.yOff * 5 * (this.outputsize - 1) + this.xOff, xx, yy, this.direction);
    ctx.stroke();

    ctx.beginPath();
    ctx.strokeStyle = ("rgba(0,0,0,1)");
    ctx.lineWidth = correctWidth(4);
    ctx.fillStyle = "white";
    moveTo(ctx, -20 + this.xOff, -this.yOff * 10 * (this.outputsize / 2), xx, yy, this.direction);
    lineTo(ctx, -20 + this.xOff, 20 + this.yOff * 10 * (this.outputsize / 2 - 1), xx, yy, this.direction);
    lineTo(ctx, 20 - this.xOff, +this.yOff * 10 * (this.outputsize / 2 - 1) + this.xOff, xx, yy, this.direction);
    lineTo(ctx, 20 - this.xOff, -this.yOff * 10 * (this.outputsize / 2) - this.xOff + 20, xx, yy, this.direction);

    ctx.closePath();
    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.beginPath();
    ctx.fillStyle = "black";
    ctx.textAlign = "center";
    //[xFill,yFill] = rotate(xx + this.output1[i].x - 7, yy + this.output1[i].y + 2);
    ////console.log([xFill,yFill])
    for (var i = 0; i < this.outputsize; i++) {
        if (this.direction == "LEFT") fillText(ctx, String(i), xx + this.output1[i].x - 7, yy + this.output1[i].y + 2, 10);
        else if (this.direction == "RIGHT") fillText(ctx, String(i), xx + this.output1[i].x + 7, yy + this.output1[i].y + 2, 10);
        else if (this.direction == "UP") fillText(ctx, String(i), xx + this.output1[i].x, yy + this.output1[i].y - 5, 10);
        else fillText(ctx, String(i), xx + this.output1[i].x, yy + this.output1[i].y + 10, 10);
    }
    ctx.fill();
}
Demultiplexer.prototype.verilogBaseType = function() {
    return this.verilogName() + this.output1.length;
}
//this code to generate Verilog
Demultiplexer.prototype.generateVerilog = function () {
    Demultiplexer.selSizes.add(this.controlSignalSize);
    return CircuitElement.prototype.generateVerilog.call(this);
}
//This code to determine what sizes are used to generate the needed modules
Demultiplexer.selSizes = new Set();
//generate the needed modules
Demultiplexer.moduleVerilog = function () {
    var output = "";

    for (var size of Demultiplexer.selSizes) {
        var numOutput = 1 << size;
        output += "\n";
        output += "module Demultiplexer" + numOutput;
        output += "(";
        for (var j = 0; j < numOutput; j++) {
            output += "out" + j + ", ";
        }
        output += "in, sel);\n";

        output += "  parameter WIDTH = 1;\n";
        output += "  output reg [WIDTH-1:0] ";
        for (var j = 0; j < numOutput-1; j++) {
            output += "out" + j + ", ";
        }
        output += "out" + (numOutput-1) + ";\n";

        output += "  input [WIDTH-1:0] in;\n"
        output += "  input [" + (size-1) +":0] sel;\n";
        output += "  \n";

        output += "  always @ (*) begin\n";
        for (var j = 0; j < numOutput; j++) {
            output += "    out" + j + " = 0;\n";
        }
        output += "    case (sel)\n";
        for (var j = 0; j < numOutput; j++) {
            output += "      " + j + " : out" + j + " = in;\n";
        }
        output += "    endcase\n";
        output += "  end\n";
        output += "endmodule\n";
    }

    return output;
}
//reset the sized before Verilog generation
Demultiplexer.resetVerilog = function () {
    Demultiplexer.selSizes = new Set();
}

function Decoder(x, y, scope = globalScope, dir = "LEFT", bitWidth = 1) {

    CircuitElement.call(this, x, y, scope, dir, bitWidth);
    // this.controlSignalSize = controlSignalSize || parseInt(prompt("Enter control signal bitWidth"), 10);
    this.outputsize = 1 << this.bitWidth;
    this.xOff = 0;
    this.yOff = 1;
    if (this.bitWidth == 1) {
        this.xOff = 10;
    }
    if (this.bitWidth <= 3) {
        this.yOff = 2;
    }

    // this.changeControlSignalSize = function(size) {
    //     if (size == undefined || size < 1 || size > 32) return;
    //     if (this.controlSignalSize == size) return;
    //     var obj = new window[this.objectType](this.x, this.y, this.scope, this.direction, this.bitWidth, size);
    //     this.cleanDelete();
    //     simulationArea.lastSelected = obj;
    //     return obj;
    // }
    // this.mutableProperties = {
    //     "controlSignalSize": {
    //         name: "Control Signal Size",
    //         type: "number",
    //         max: "32",
    //         min: "1",
    //         func: "changeControlSignalSize",
    //     },
    // }
    this.newBitWidth = function (bitWidth) {
        // this.bitWidth = bitWidth;
        // for (var i = 0; i < this.inputSize; i++) {
        //     this.outputs1[i].bitWidth = bitWidth
        // }
        // this.input.bitWidth = bitWidth;
        if (bitWidth == undefined || bitWidth < 1 || bitWidth > 32) return;
        if (this.bitWidth == bitWidth) return;
        var obj = new window[this.objectType](this.x, this.y, this.scope, this.direction, bitWidth);
        this.cleanDelete();
        simulationArea.lastSelected = obj;
        return obj;
    }

    this.setDimensions(20 - this.xOff, this.yOff * 5 * (this.outputsize));
    this.rectangleObject = false;
    this.input = new Node(20 - this.xOff, 0, 0, this);

    this.output1 = [];
    for (var i = 0; i < this.outputsize; i++) {
        var a = new Node(-20 + this.xOff, +this.yOff * 10 * (i - this.outputsize / 2) + 10, 1, this, 1);
        this.output1.push(a);
    }

    // this.controlSignalInput = new Node(0,this.yOff * 10 * (this.outputsize / 2 - 1) +this.xOff + 10, 0, this, this.controlSignalSize,"Control Signal");


}
Decoder.prototype = Object.create(CircuitElement.prototype);
Decoder.prototype.constructor = Decoder;
Decoder.prototype.tooltipText = "Decoder ToolTip : Converts coded inputs into coded outputs.";
Decoder.prototype.helplink = "https://docs.circuitverse.org/#/decodersandplexers?id=decoder";
Decoder.prototype.customSave = function () {
    var data = {
        constructorParamaters: [this.direction, this.bitWidth],
        nodes: {
            output1: this.output1.map(findNode),
            input: findNode(this.input),
        },
    }
    return data;
}
Decoder.prototype.resolve = function () {

    for (var i = 0; i < this.output1.length; i++)
        this.output1[i].value = 0;
    this.output1[this.input.value].value = 1;
    for (var i = 0; i < this.output1.length; i++)
        simulationArea.simulationQueue.add(this.output1[i]);

}
Decoder.prototype.customDraw = function () {

    ctx = simulationArea.context;

    var xx = this.x;
    var yy = this.y;

    // ctx.beginPath();
    // moveTo(ctx, 0,this.yOff * 10 * (this.outputsize / 2 - 1) + 10 + 0.5 *this.xOff, xx, yy, this.direction);
    // lineTo(ctx, 0,this.yOff * 5 * (this.outputsize - 1) +this.xOff, xx, yy, this.direction);
    // ctx.stroke();

    ctx.beginPath();
    ctx.strokeStyle = ("rgba(0,0,0,1)");
    ctx.lineWidth = correctWidth(4);
    ctx.fillStyle = "white";
    moveTo(ctx, -20 + this.xOff, -this.yOff * 10 * (this.outputsize / 2), xx, yy, this.direction);
    lineTo(ctx, -20 + this.xOff, 20 + this.yOff * 10 * (this.outputsize / 2 - 1), xx, yy, this.direction);
    lineTo(ctx, 20 - this.xOff, +this.yOff * 10 * (this.outputsize / 2 - 1) + this.xOff, xx, yy, this.direction);
    lineTo(ctx, 20 - this.xOff, -this.yOff * 10 * (this.outputsize / 2) - this.xOff + 20, xx, yy, this.direction);

    ctx.closePath();
    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.beginPath();
    ctx.fillStyle = "black";
    ctx.textAlign = "center";
    //[xFill,yFill] = rotate(xx + this.output1[i].x - 7, yy + this.output1[i].y + 2);
    ////console.log([xFill,yFill])
    for (var i = 0; i < this.outputsize; i++) {
        if (this.direction == "LEFT") fillText(ctx, String(i), xx + this.output1[i].x - 7, yy + this.output1[i].y + 2, 10);
        else if (this.direction == "RIGHT") fillText(ctx, String(i), xx + this.output1[i].x + 7, yy + this.output1[i].y + 2, 10);
        else if (this.direction == "UP") fillText(ctx, String(i), xx + this.output1[i].x, yy + this.output1[i].y - 5, 10);
        else fillText(ctx, String(i), xx + this.output1[i].x, yy + this.output1[i].y + 10, 10);
    }
    ctx.fill();
}

Decoder.prototype.verilogBaseType = function() {
    return this.verilogName() + this.output1.length;
}
//this code to generate Verilog
Decoder.prototype.generateVerilog = function () {
    Decoder.selSizes.add(this.bitWidth);
    return CircuitElement.prototype.generateVerilog.call(this);
}

Decoder.selSizes = new Set();
//generate the needed modules
Decoder.moduleVerilog = function () {
    var output = "";

    for (var size of Decoder.selSizes) {
        var numOutput = 1 << size;
        output += "\n";
        output += "module Decoder" + numOutput;
        output += "(";
        for (var j = 0; j < numOutput; j++) {
            output += "out" + j + ", ";
        }
        output += "sel);\n";

        output += "  output reg ";
        for (var j = 0; j < numOutput-1; j++) {
            output += "out" + j + ", ";
        }
        output += "out" + (numOutput-1) + ";\n";

        output += "  input [" + (size-1) +":0] sel;\n";
        output += "  \n";

        output += "  always @ (*) begin\n";
        for (var j = 0; j < numOutput; j++) {
            output += "    out" + j + " = 0;\n";
        }
        output += "    case (sel)\n";
        for (var j = 0; j < numOutput; j++) {
            output += "      " + j + " : out" + j + " = 1;\n";
        }
        output += "    endcase\n";
        output += "  end\n";
        output += "endmodule\n";
    }

    return output;
}
//reset the sized before Verilog generation
Decoder.resetVerilog = function () {
    Decoder.selSizes = new Set();
}

function Flag(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1, identifier) {

    CircuitElement.call(this, x, y, scope, dir, bitWidth);
    this.setWidth(60);
    this.setHeight(20);
    this.rectangleObject = false;
    this.directionFixed = true;
    this.orientationFixed = false;
    this.identifier = identifier || ("F" + this.scope.Flag.length);
    this.plotValues = [];

    this.xSize = 10;

    this.inp1 = new Node(40, 0, 0, this);
}

Flag.prototype = Object.create(CircuitElement.prototype);
Flag.prototype.constructor = Flag;
Flag.prototype.tooltipText = "FLag ToolTip: Use this for debugging and plotting."
Flag.prototype.helplink = "https://docs.circuitverse.org/#/timing_diagrams?id=using-flags";
Flag.prototype.setPlotValue = function () {
    var time = plotArea.stopWatch.ElapsedMilliseconds;

    // //console.log("DEB:",time);
    if (this.plotValues.length && this.plotValues[this.plotValues.length - 1][0] == time)
        this.plotValues.pop();

    if (this.plotValues.length == 0) {
        this.plotValues.push([time, this.inp1.value]);
        return;
    }

    if (this.plotValues[this.plotValues.length - 1][1] == this.inp1.value)
        return;
    else
        this.plotValues.push([time, this.inp1.value]);
}
Flag.prototype.customSave = function () {
    var data = {
        constructorParamaters: [this.direction, this.bitWidth],
        nodes: {
            inp1: findNode(this.inp1),
        },
        values: {
            identifier: this.identifier
        }
    }
    return data;
}
Flag.prototype.setIdentifier = function (id = "") {
    if (id.length == 0) return;
    this.identifier = id;
    var len = this.identifier.length;
    if (len == 1) this.xSize = 20;
    else if (len > 1 && len < 4) this.xSize = 10;
    else this.xSize = 0;
}
Flag.prototype.mutableProperties = {
    "identifier": {
        name: "Debug Flag identifier",
        type: "text",
        maxlength: "5",
        func: "setIdentifier",
    },
}
Flag.prototype.customDraw = function () {
    ctx = simulationArea.context;
    ctx.beginPath();
    ctx.strokeStyle = "grey";
    ctx.fillStyle = "#fcfcfc";
    ctx.lineWidth = correctWidth(1);
    var xx = this.x;
    var yy = this.y;


    rect2(ctx, -50 + this.xSize, -20, 100 - 2 * 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 Georgia";
    this.xOff = ctx.measureText(this.identifier).width;

    ctx.beginPath();
    rect2(ctx, -40 + this.xSize, -12, this.xOff + 10, 25, 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, xx - 35 + this.xOff / 2 + this.xSize, yy + 5, 14);
    ctx.fill();

    ctx.beginPath();
    ctx.font = "30px Georgia";
    ctx.textAlign = "center";
    ctx.fillStyle = ["blue", "red"][+(this.inp1.value == undefined)];
    if (this.inp1.value !== undefined)
        fillText(ctx, this.inp1.value.toString(16), xx + 35 - this.xSize, yy + 8, 25);
    else
        fillText(ctx, "x", xx + 35 - this.xSize, yy + 8, 25);
    ctx.fill();

}
Flag.prototype.newDirection = function (dir) {
    if (dir == this.direction) return;
    this.direction = dir;
    this.inp1.refresh();
    if (dir == "RIGHT" || dir == "LEFT") {
        this.inp1.leftx = 50 - this.xSize;
    } else if (dir == "UP") {
        this.inp1.leftx = 20;
    } else {
        this.inp1.leftx = 20;
    }
    // if(this.direction=="LEFT" || this.direction=="RIGHT") this.inp1.leftx=50-this.xSize;
    //     this.inp1.refresh();

    this.inp1.refresh();
}

function MSB(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {

    CircuitElement.call(this, x, y, scope, dir, bitWidth);
    // this.setDimensions(20, 20);
    this.leftDimensionX = 10;
    this.rightDimensionX = 20;
    this.setHeight(30);
    this.directionFixed = true;
    this.bitWidth = bitWidth || parseInt(prompt("Enter bitWidth"), 10);
    this.rectangleObject = false;
    this.inputSize = 1 << this.bitWidth;

    this.inp1 = new Node(-10, 0, 0, this, this.inputSize);
    this.output1 = new Node(20, 0, 1, this, this.bitWidth);
    this.enable = new Node(20, 20, 1, this, 1);



}
MSB.prototype = Object.create(CircuitElement.prototype);
MSB.prototype.constructor = MSB;
MSB.prototype.tooltipText = "MSB ToolTip : The most significant bit or the high-order bit.";
MSB.prototype.helplink = "https://docs.circuitverse.org/#/decodersandplexers?id=most-significant-bit-msb-detector";
MSB.prototype.customSave = function () {
    var data = {

        nodes: {
            inp1: findNode(this.inp1),
            output1: findNode(this.output1),
            enable: findNode(this.enable)
        },
        constructorParamaters: [this.direction, this.bitWidth],
    }
    return data;
}
MSB.prototype.newBitWidth = function (bitWidth) {
    // this.inputSize = 1 << bitWidth
    this.inputSize = bitWidth
    this.inp1.bitWidth = this.inputSize;
    this.bitWidth = bitWidth;
    this.output1.bitWidth = bitWidth;
}
MSB.prototype.resolve = function () {

    var inp = this.inp1.value;
    this.output1.value = (dec2bin(inp).length) - 1
    simulationArea.simulationQueue.add(this.output1);
    if (inp != 0) {
        this.enable.value = 1;
    } else {
        this.enable.value = 0;
    }
    simulationArea.simulationQueue.add(this.enable);
}
MSB.prototype.customDraw = function () {

    ctx = simulationArea.context;
    ctx.beginPath();
    ctx.strokeStyle = "black";
    ctx.fillStyle = "white";
    ctx.lineWidth = correctWidth(3);
    var xx = this.x;
    var yy = this.y;
    rect(ctx, xx - 10, yy - 30, 30, 60);
    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.beginPath();
    ctx.fillStyle = "black";
    ctx.textAlign = "center";
    fillText(ctx, "MSB", xx + 6, yy - 12, 10);
    fillText(ctx, "EN", xx + this.enable.x - 12, yy + this.enable.y + 3, 8);
    ctx.fill();

    ctx.beginPath();
    ctx.fillStyle = "green";
    ctx.textAlign = "center";
    if (this.output1.value != undefined) {
        fillText(ctx, this.output1.value, xx + 5, yy + 14, 13);
    }
    ctx.stroke();
    ctx.fill();
}
MSB.prototype.generateVerilog = function () {
    return `assign ${this.output1.verilogLabel} = (${this.enable.verilogLabel}!=0) ? ${this.inp1.verilogLabel}[${this.inp1.bitWidth-1}] : 0;`;
}

function LSB(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {

    CircuitElement.call(this, x, y, scope, dir, bitWidth);
    this.leftDimensionX = 10;
    this.rightDimensionX = 20;
    this.setHeight(30);
    this.directionFixed = true;
    this.bitWidth = bitWidth || parseInt(prompt("Enter bitWidth"), 10);
    this.rectangleObject = false;
    this.inputSize = 1 << this.bitWidth;

    this.inp1 = new Node(-10, 0, 0, this, this.inputSize);
    this.output1 = new Node(20, 0, 1, this, this.bitWidth);
    this.enable = new Node(20, 20, 1, this, 1);



}
LSB.prototype = Object.create(CircuitElement.prototype);
LSB.prototype.constructor = LSB;
LSB.prototype.tooltipText = "LSB ToolTip : The least significant bit or the low-order bit.";
LSB.prototype.helplink = "https://docs.circuitverse.org/#/decodersandplexers?id=least-significant-bit-lsb-detector";
LSB.prototype.customSave = function () {
    var data = {

        nodes: {
            inp1: findNode(this.inp1),
            output1: findNode(this.output1),
            enable: findNode(this.enable)
        },
        constructorParamaters: [this.direction, this.bitWidth],
    }
    return data;
}
LSB.prototype.newBitWidth = function (bitWidth) {
    // this.inputSize = 1 << bitWidth
    this.inputSize = bitWidth
    this.inp1.bitWidth = this.inputSize;
    this.bitWidth = bitWidth;
    this.output1.bitWidth = bitWidth;
}
LSB.prototype.resolve = function () {

    var inp = dec2bin(this.inp1.value);
    var out = 0;
    for (var i = inp.length - 1; i >= 0; i--) {
        if (inp[i] == 1) {
            out = inp.length - 1 - i;
            break;
        }

    }
    this.output1.value = out;
    simulationArea.simulationQueue.add(this.output1);
    if (inp != 0) {
        this.enable.value = 1;
    } else {
        this.enable.value = 0;
    }
    simulationArea.simulationQueue.add(this.enable);
}
LSB.prototype.customDraw = function () {

    ctx = simulationArea.context;
    ctx.beginPath();
    ctx.strokeStyle = "black";
    ctx.fillStyle = "white";
    ctx.lineWidth = correctWidth(3);
    var xx = this.x;
    var yy = this.y;
    rect(ctx, xx - 10, yy - 30, 30, 60);
    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.beginPath();
    ctx.fillStyle = "black";
    ctx.textAlign = "center";
    fillText(ctx, "LSB", xx + 6, yy - 12, 10);
    fillText(ctx, "EN", xx + this.enable.x - 12, yy + this.enable.y + 3, 8);
    ctx.fill();

    ctx.beginPath();
    ctx.fillStyle = "green";
    ctx.textAlign = "center";
    if (this.output1.value != undefined) {
        fillText(ctx, this.output1.value, xx + 5, yy + 14, 13);
    }
    ctx.stroke();
    ctx.fill();
}
LSB.prototype.generateVerilog = function () {
    return `assign ${this.output1.verilogLabel} = (${this.enable.verilogLabel}!=0) ? ${this.inp1.verilogLabel}[0] : 0;`;
}

function PriorityEncoder(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {

    CircuitElement.call(this, x, y, scope, dir, bitWidth);
    this.bitWidth = bitWidth || parseInt(prompt("Enter bitWidth"), 10);
    this.inputSize = 1 << this.bitWidth;

    this.yOff = 1;
    if (this.bitWidth <= 3) {
        this.yOff = 2;
    }

    this.setDimensions(20, this.yOff * 5 * (this.inputSize));
    this.directionFixed = true;
    this.rectangleObject = false;

    this.inp1 = [];
    for (var i = 0; i < this.inputSize; i++) {
        var a = new Node(-10, +this.yOff * 10 * (i - this.inputSize / 2) + 10, 0, this, 1);
        this.inp1.push(a);
    }

    this.output1 = [];
    for (var i = 0; i < this.bitWidth; i++) {
        var a = new Node(30, +2 * 10 * (i - this.bitWidth / 2) + 10, 1, this, 1);
        this.output1.push(a);
    }

    this.enable = new Node(10, 20 + this.inp1[this.inputSize - 1].y, 1, this, 1);


}
PriorityEncoder.prototype = Object.create(CircuitElement.prototype);
PriorityEncoder.prototype.constructor = PriorityEncoder;
PriorityEncoder.prototype.tooltipText = "Priority Encoder ToolTip : Compresses binary inputs into a smaller number of outputs.";
PriorityEncoder.prototype.helplink = "https://docs.circuitverse.org/#/decodersandplexers?id=priority-encoder";
PriorityEncoder.prototype.customSave = function () {
    var data = {

        nodes: {
            inp1: this.inp1.map(findNode),
            output1: this.output1.map(findNode),
            enable: findNode(this.enable)
        },
        constructorParamaters: [this.direction, this.bitWidth],
    }
    return data;
}
PriorityEncoder.prototype.newBitWidth = function (bitWidth) {
    if (bitWidth == undefined || bitWidth < 1 || bitWidth > 32) return;
    if (this.bitWidth == bitWidth) return;

    this.bitWidth = bitWidth;
    var obj = new window[this.objectType](this.x, this.y, this.scope, this.direction, this.bitWidth);
    this.inputSize = 1 << bitWidth;

    this.cleanDelete();
    simulationArea.lastSelected = obj;
    return obj;
}
PriorityEncoder.prototype.resolve = function () {
    var out = 0;
    var temp = 0;
    for (var i = this.inputSize - 1; i >= 0; i--) {
        if (this.inp1[i].value == 1) {
            out = dec2bin(i);
            break;
        }
    }
    temp = out;

    if (out.length != undefined) {
        this.enable.value = 1;
    } else {
        this.enable.value = 0;
    }
    simulationArea.simulationQueue.add(this.enable);

    if (temp.length == undefined) {
        temp = "0";
        for (var i = 0; i < this.bitWidth - 1; i++) {
            temp = "0" + temp;
        }
    }

    if (temp.length != this.bitWidth) {
        for (var i = temp.length; i < this.bitWidth; i++) {
            temp = "0" + temp;
        }
    }

    for (var i = this.bitWidth - 1; i >= 0; i--) {
        this.output1[this.bitWidth - 1 - i].value = Number(temp[i]);
        simulationArea.simulationQueue.add(this.output1[this.bitWidth - 1 - i]);
    }
}
PriorityEncoder.prototype.customDraw = function () {

    ctx = simulationArea.context;
    ctx.beginPath();
    ctx.strokeStyle = "black";
    ctx.fillStyle = "white";
    ctx.lineWidth = correctWidth(3);
    var xx = this.x;
    var yy = this.y;
    if (this.bitWidth <= 3)
        rect(ctx, xx - 10, yy - 10 - this.yOff * 5 * (this.inputSize), 40, 20 * (this.inputSize + 1));
    else
        rect(ctx, xx - 10, yy - 10 - this.yOff * 5 * (this.inputSize), 40, 10 * (this.inputSize + 3));
    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.beginPath();
    ctx.fillStyle = "black";
    ctx.textAlign = "center";
    for (var i = 0; i < this.inputSize; i++) {
        fillText(ctx, String(i), xx, yy + this.inp1[i].y + 2, 10);
    }
    for (var i = 0; i < this.bitWidth; i++) {
        fillText(ctx, String(i), xx + this.output1[0].x - 10, yy + this.output1[i].y + 2, 10);
    }
    fillText(ctx, "EN", xx + this.enable.x, yy + this.enable.y - 5, 10);
    ctx.fill();

}
PriorityEncoder.prototype.verilogBaseType = function() {
    return this.verilogName() + this.inp1.length;
}

PriorityEncoder.prototype.generateVerilog = function () {
    PriorityEncoder.selSizes.add(this.bitWidth);
    return CircuitElement.prototype.generateVerilog.call(this);
}
PriorityEncoder.selSizes = new Set();
//generate the needed modules
PriorityEncoder.moduleVerilog = function () {
    var output = "";

    for (var size of PriorityEncoder.selSizes) {
        var numInput = 1 << size;
        output += "\n";
        output += "module PriorityEncoder" + numInput;
        output += "(sel, ze, ";
        for (var j = 0; j < numInput-1; j++) {
            output += "in" + j + ", ";
        }
        output += "in" + (numInput-1) + ");\n";

        output += "  output reg [" + (size-1) + ":0] sel;\n";
        output += "  output reg ze;\n";

        output += "  input "
        for (var j = 0; j < numInput-1; j++) {
            output += "in" + j + ", ";
        }
        output += "in" + (numInput-1) + ";\n";
        output += "\n";

        output += "  always @ (*) begin\n";
        output += "    sel = 0;\n";
        output += "    ze = 0;\n";
        output += "    if (in" + (numInput-1) + ")\n";
        output += "      sel = " + (numInput-1) + ";\n";
        for (var j = numInput-2; j <= 0; j++) {
            output += "    else if (in" + j + ")\n";
            output += "      sel = " + j + ";\n";
        }
        output += "    else\n";
        output += "      ze = 1;\n"
        output += "  end\n";
        output += "endmodule\n";
    }

    return output;
}
//reset the sized before Verilog generation
PriorityEncoder.resetVerilog = function () {
    PriorityEncoder.selSizes = new Set
}

function Tunnel(x, y, scope = globalScope, dir = "LEFT", bitWidth = 1, identifier) {

    CircuitElement.call(this, x, y, scope, dir, bitWidth);
    this.rectangleObject = false;
    this.centerElement = true;

    this.xSize = 10;

    this.plotValues = [];
    this.inp1 = new Node(0, 0, 0, this);
    this.setIdentifier(identifier || "T");
    this.setBounds();

}
Tunnel.prototype = Object.create(CircuitElement.prototype);
Tunnel.prototype.constructor = Tunnel;
Tunnel.prototype.tooltipText = "Tunnel ToolTip : Tunnel Selected.";
Tunnel.prototype.helplink = "https://docs.circuitverse.org/#/miscellaneous?id=tunnel";
Tunnel.prototype.newDirection = function (dir) {
    if (this.direction == dir) return;
    this.direction = dir;
    this.setBounds();
}
Tunnel.prototype.overrideDirectionRotation = true;
Tunnel.prototype.setBounds = function () {

    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;
    }

    this.leftDimensionX = Math.abs(-120 + xRotate + this.xSize);
    this.upDimensionY = Math.abs(-20 + yRotate);
    this.rightDimensionX = Math.abs(xRotate)
    this.downDimensionY = Math.abs(20 + yRotate);
    console.log(this.leftDimensionX, this.upDimensionY, this.rightDimensionX, this.downDimensionY);

    // rect2(ctx, -120 + xRotate + this.xSize, -20 + yRotate, 120 - this.xSize, 40, xx, yy, "RIGHT");


}
Tunnel.prototype.setTunnelValue = function (val) {
    this.inp1.value = val;
    for (var i = 0; i < this.inp1.connections.length; i++) {
        if (this.inp1.connections[i].value != val) {
            this.inp1.connections[i].value = val;
            simulationArea.simulationQueue.add(this.inp1.connections[i]);
        }
    }
}
Tunnel.prototype.resolve = function () {
    for (var i = 0; i < this.scope.tunnelList[this.identifier].length; i++) {
        if (this.scope.tunnelList[this.identifier][i].inp1.value != this.inp1.value) {
            this.scope.tunnelList[this.identifier][i].setTunnelValue(this.inp1.value);
        }
    }
}
Tunnel.prototype.updateScope = function (scope) {
    this.scope = scope;
    this.inp1.updateScope(scope);
    this.setIdentifier(this.identifier);
    //console.log("ShouldWork!");
}
Tunnel.prototype.setPlotValue = function () {
    var time = plotArea.stopWatch.ElapsedMilliseconds;
    if (this.plotValues.length && this.plotValues[this.plotValues.length - 1][0] == time)
        this.plotValues.pop();

    if (this.plotValues.length == 0) {
        this.plotValues.push([time, this.inp1.value]);
        return;
    }

    if (this.plotValues[this.plotValues.length - 1][1] == this.inp1.value)
        return;
    else
        this.plotValues.push([time, this.inp1.value]);
}
Tunnel.prototype.customSave = function () {
    var data = {
        constructorParamaters: [this.direction, this.bitWidth, this.identifier],
        nodes: {
            inp1: findNode(this.inp1),
        },
        values: {
            identifier: this.identifier
        }
    }
    return data;
}
Tunnel.prototype.setIdentifier = function (id = "") {
    if (id.length == 0) return;
    if (this.scope.tunnelList[this.identifier]) this.scope.tunnelList[this.identifier].clean(this);
    this.identifier = id;
    if (this.scope.tunnelList[this.identifier]) this.scope.tunnelList[this.identifier].push(this);
    else this.scope.tunnelList[this.identifier] = [this];

    var len = this.identifier.length;
    if (len == 1) this.xSize = 40;
    else if (len > 1 && len < 4) this.xSize = 20;
    else this.xSize = 0;

    this.setBounds();
}
Tunnel.prototype.mutableProperties = {
    "identifier": {
        name: "Debug Flag identifier",
        type: "text",
        maxlength: "5",
        func: "setIdentifier",
    },
}
Tunnel.prototype.delete = function () {
    this.scope.Tunnel.clean(this);
    this.scope.tunnelList[this.identifier].clean(this);
    CircuitElement.prototype.delete.call(this);
}
Tunnel.prototype.customDraw = function () {
    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 Georgia";
    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, xx - 100 + this.xOff / 2 + xRotate + this.xSize, yy + 6 + yRotate, 14);
    ctx.fill();

    ctx.beginPath();
    ctx.font = "30px Georgia";
    ctx.textAlign = "center";
    ctx.fillStyle = ["blue", "red"][+(this.inp1.value == undefined)];
    if (this.inp1.value !== undefined)
        fillText(ctx, this.inp1.value.toString(16), xx - 23 + xRotate, yy + 8 + yRotate, 25);
    else
        fillText(ctx, "x", xx - 23 + xRotate, yy + 8 + yRotate, 25);
    ctx.fill();
}

function ALU(x, y, scope = globalScope, dir = "RIGHT", bitWidth = 1) {
    // //console.log("HIT");
    // //console.log(x,y,scope,dir,bitWidth,controlSignalSize);
    CircuitElement.call(this, x, y, scope, dir, bitWidth);
    this.message = "ALU";

    this.setDimensions(30, 40);
    this.rectangleObject = false;

    this.inp1 = new Node(-30, -30, 0, this, this.bitwidth, "A");
    this.inp2 = new Node(-30, 30, 0, this, this.bitwidth, "B");

    this.controlSignalInput = new Node(-10, -40, 0, this, 3, "Ctrl");
    this.carryOut = new Node(-10, 40, 1, this, 1, "Cout");
    this.output = new Node(30, 0, 1, this, this.bitwidth, "Out");

}
ALU.prototype = Object.create(CircuitElement.prototype);
ALU.prototype.constructor = ALU;
ALU.prototype.tooltipText = "ALU ToolTip: 0: A&B, 1:A|B, 2:A+B, 4:A&~B, 5:A|~B, 6:A-B, 7:SLT "
ALU.prototype.helplink = "https://docs.circuitverse.org/#/miscellaneous?id=alu";
ALU.prototype.newBitWidth = function (bitWidth) {
    this.bitWidth = bitWidth;
    this.inp1.bitWidth = bitWidth;
    this.inp2.bitWidth = bitWidth;
    this.output.bitWidth = bitWidth;
}
ALU.prototype.customSave = function () {
    var data = {
        constructorParamaters: [this.direction, this.bitWidth],
        nodes: {
            inp1: findNode(this.inp1),
            inp2: findNode(this.inp2),
            output: findNode(this.output),
            carryOut: findNode(this.carryOut),
            controlSignalInput: findNode(this.controlSignalInput)
        },
    }
    return data;
}
ALU.prototype.customDraw = function () {
    ctx = simulationArea.context;
    var xx = this.x;
    var yy = this.y;
    ctx.strokeStyle = "black";
    ctx.fillStyle = "white";
    ctx.lineWidth = correctWidth(3);
    ctx.beginPath();
    moveTo(ctx, 30, 10, xx, yy, this.direction);
    lineTo(ctx, 30, -10, xx, yy, this.direction);
    lineTo(ctx, 10, -40, xx, yy, this.direction);
    lineTo(ctx, -30, -40, xx, yy, this.direction);
    lineTo(ctx, -30, -20, xx, yy, this.direction);
    lineTo(ctx, -20, -10, xx, yy, this.direction);
    lineTo(ctx, -20, 10, xx, yy, this.direction);
    lineTo(ctx, -30, 20, xx, yy, this.direction);
    lineTo(ctx, -30, 40, xx, yy, this.direction);
    lineTo(ctx, 10, 40, xx, yy, this.direction);
    lineTo(ctx, 30, 10, xx, yy, this.direction);
    ctx.closePath();
    ctx.stroke();

    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.beginPath();
    ctx.fillStyle = "Black";
    ctx.textAlign = "center"

    fillText4(ctx, "B", -23, 30, xx, yy, this.direction, 6);
    fillText4(ctx, "A", -23, -30, xx, yy, this.direction, 6);
    fillText4(ctx, "CTR", -10, -30, xx, yy, this.direction, 6);
    fillText4(ctx, "Carry", -10, 30, xx, yy, this.direction, 6);
    fillText4(ctx, "Ans", 20, 0, xx, yy, this.direction, 6);
    ctx.fill();
    ctx.beginPath();
    ctx.fillStyle = "DarkGreen";
    fillText4(ctx, this.message, 0, 0, xx, yy, this.direction, 12);
    ctx.fill();

}
ALU.prototype.resolve = function () {
    if (this.controlSignalInput.value == 0) {
        this.output.value = ((this.inp1.value) & (this.inp2.value));
        simulationArea.simulationQueue.add(this.output);
        this.carryOut.value = 0;
        simulationArea.simulationQueue.add(this.carryOut);
        this.message = "A&B";
    } else if (this.controlSignalInput.value == 1) {
        this.output.value = ((this.inp1.value) | (this.inp2.value));

        simulationArea.simulationQueue.add(this.output);
        this.carryOut.value = 0;
        simulationArea.simulationQueue.add(this.carryOut);
        this.message = "A|B";
    } else if (this.controlSignalInput.value == 2) {
        var sum = this.inp1.value + this.inp2.value;
        this.output.value = ((sum) << (32 - this.bitWidth)) >>> (32 - this.bitWidth);
        this.carryOut.value = +((sum >>> (this.bitWidth)) !== 0);
        simulationArea.simulationQueue.add(this.carryOut);
        simulationArea.simulationQueue.add(this.output);
        this.message = "A+B";
    } else if (this.controlSignalInput.value == 3) {
        this.message = "ALU";
        return;
    } else if (this.controlSignalInput.value == 4) {
        this.message = "A&~B";
        this.output.value = ((this.inp1.value) & this.flipBits(this.inp2.value));
        simulationArea.simulationQueue.add(this.output);
        this.carryOut.value = 0;
        simulationArea.simulationQueue.add(this.carryOut);
    } else if (this.controlSignalInput.value == 5) {
        this.message = "A|~B";
        this.output.value = ((this.inp1.value) | this.flipBits(this.inp2.value));
        simulationArea.simulationQueue.add(this.output);
        this.carryOut.value = 0;
        simulationArea.simulationQueue.add(this.carryOut);
    } else if (this.controlSignalInput.value == 6) {
        this.message = "A-B";
        this.output.value = ((this.inp1.value - this.inp2.value) << (32 - this.bitWidth)) >>> (32 - this.bitWidth);
        simulationArea.simulationQueue.add(this.output);
        this.carryOut.value = 0;
        simulationArea.simulationQueue.add(this.carryOut);
    } else if (this.controlSignalInput.value == 7) {
        this.message = "A<B";
        if (this.inp1.value < this.inp2.value)
            this.output.value = 1;
        else
            this.output.value = 0;
        simulationArea.simulationQueue.add(this.output);
        this.carryOut.value = 0;
        simulationArea.simulationQueue.add(this.carryOut);
    }

}
ALU.moduleVerilog = function () {
  return `
module ALU(out, carryOut, inp1, inp2, controlSignalInput);
  parameter WIDTH = 1;
  output reg [WIDTH-1:0] out;
  output reg carryOut;
  input [WIDTH-1:0] inp1, inp2;
  input [2:0] controlSignalInput;

  always @ (*)
    case (controlSignalInput)
      0 :
        begin
          out = inp1 & inp2;
          carryOut = 0;
        end
      1 :
        begin
          out = inp1 | inp2;
          carryOut = 0;
        end
      2 :
        begin
          {carryOut, out} = inp1 + inp2;
        end
      4 :
        begin
          out = inp1 & ~inp2;
          carryOut = 0;
        end
      5 :
        begin
          out = inp1 | ~inp2;
          carryOut = 0;
        end
      6 :
        begin
          out = inp1 < inp2;
          carryOut = 0;
        end
      7 :
        begin
          out = inp1 & inp2;
          carryOut = 0;
        end
      default :
        begin
          out = inp1 & inp2;
          carryOut = 0;
        end
    endcase
endmodule
`;
}

function Rectangle(x, y, scope = globalScope, rows = 15, cols = 20) {
    CircuitElement.call(this, x, y, scope, "RIGHT", 1);
    this.directionFixed = true;
    this.fixedBitWidth = true;
    this.rectangleObject = false;
    this.cols = cols || parseInt(prompt("Enter cols:"));
    this.rows = rows || parseInt(prompt("Enter rows:"));
    this.setSize()

}
Rectangle.prototype = Object.create(CircuitElement.prototype);
Rectangle.prototype.constructor = Rectangle;
Rectangle.prototype.propagationDelayFixed = true;
Rectangle.prototype.tooltipText = "Rectangle ToolTip : Used to Box the Circuit or area you want to highlight.";
Rectangle.prototype.helplink = "https://docs.circuitverse.org/#/annotation?id=rectangle";
Rectangle.prototype.changeRowSize = function (size) {
    if (size == undefined || size < 5 || size > 1000) return;
    if (this.rows == size) return;
    this.rows = parseInt(size)
    this.setSize()
    return this;
}
Rectangle.prototype.changeColSize = function (size) {
    if (size == undefined || size < 5 || size > 1000) return;
    if (this.cols == size) return;
    this.cols = parseInt(size);
    this.setSize()
    return this;
}
Rectangle.prototype.keyDown3 = function (dir) {
    //console.log(dir)
    if (dir == "ArrowRight")
        this.changeColSize(this.cols + 2)
    if (dir == "ArrowLeft")
        this.changeColSize(this.cols - 2)
    if (dir == "ArrowDown")
        this.changeRowSize(this.rows + 2)
    if (dir == "ArrowUp")
        this.changeRowSize(this.rows - 2)
}
Rectangle.prototype.mutableProperties = {
    "cols": {
        name: "Columns",
        type: "number",
        max: "1000",
        min: "5",
        func: "changeColSize",
    },
    "rows": {
        name: "Rows",
        type: "number",
        max: "1000",
        min: "5",
        func: "changeRowSize",
    }
}
Rectangle.prototype.customSave = function () {
    var data = {
        constructorParamaters: [this.rows, this.cols],
    }
    return data;
}
Rectangle.prototype.customDraw = function () {

    ctx = simulationArea.context;
    ctx.beginPath();
    ctx.strokeStyle = "rgba(0,0,0,1)";
    ctx.setLineDash([5 * globalScope.scale, 5 * globalScope.scale])
    ctx.lineWidth = correctWidth(1.5);
    var xx = this.x;
    var yy = this.y;
    rect(ctx, xx, yy, this.elementWidth, this.elementHeight);
    ctx.stroke();

    if (simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) {
        ctx.fillStyle = "rgba(255, 255, 32,0.1)";
        ctx.fill();
    }
    ctx.setLineDash([])


}
Rectangle.prototype.setSize = function () {
    this.elementWidth = this.cols * 10;
    this.elementHeight = this.rows * 10;
    this.upDimensionY = 0;
    this.leftDimensionX = 0;
    this.rightDimensionX = this.elementWidth;
    this.downDimensionY = this.elementHeight;
}


function Arrow(x, y, scope = globalScope, dir = "RIGHT") {

    CircuitElement.call(this, x, y, scope, dir, 8);
    this.rectangleObject = false;
    this.fixedBitWidth = true
    this.setDimensions(30, 20);

}
Arrow.prototype = Object.create(CircuitElement.prototype);
Arrow.prototype.constructor = Arrow;
Arrow.prototype.propagationDelayFixed = true;
Arrow.prototype.tooltipText = "Arrow ToolTip : Arrow Selected.";
Arrow.prototype.helplink = "https://docs.circuitverse.org/#/annotation?id=arrow";
Arrow.prototype.customSave = function () {
    var data = {
        constructorParamaters: [this.direction],
    }
    return data;
}
Arrow.prototype.customDraw = function () {

    ctx = simulationArea.context;
    ctx.lineWidth = correctWidth(3);
    var xx = this.x;
    var yy = this.y;
    ctx.strokeStyle = "red";
    ctx.fillStyle = "white";

    ctx.beginPath();

    moveTo(ctx, -30, -3, xx, yy, this.direction);
    lineTo(ctx, 10, -3, xx, yy, this.direction);
    lineTo(ctx, 10, -15, xx, yy, this.direction);
    lineTo(ctx, 30, 0, xx, yy, this.direction);
    lineTo(ctx, 10, 15, xx, yy, this.direction);
    lineTo(ctx, 10, 3, xx, yy, this.direction);
    lineTo(ctx, -30, 3, xx, yy, this.direction);
    ctx.closePath()
    ctx.stroke();
    if ((this.hover && !simulationArea.shiftDown) || simulationArea.lastSelected == this || simulationArea.multipleObjectSelections.contains(this)) ctx.fillStyle = "rgba(255, 255, 32,0.8)";
    ctx.fill();

}
