GateOpenLight = "rgb(230,255,230)";
GateOpen = GateOpenLight; //"lightgreen";
GateClosed = "rgb(255,230,240)";
InstrLabel = "rgb(20,20,100)";
Active = "blue";
InActive = "black";
CircuitFrame = "black";
CircuitBackground = "lightsteelblue";
ClockFill = CircuitBackground;
MicroBG = "rgb(240,240,255)";

var Theme = Class("Theme", function(thisClass, Super){
    thisClass.prototype.init=function(circuit){
        this.circuit=circuit;
        circuit.addListener(this);
    }
});

var LineTheme =Class("LineTheme", Theme, function(thisClass, Super){

    thisClass.prototype.init=function(x1, y1, x2, y2, circuit, parentNode){
        Super.prototype.init.call(this, circuit)
        this.x1 = x1;
        this.y1 = y1;
        this.x2 = x2;
        this.y2 = y2;
        
        this.buildTheme(parentNode);
    }
    
    thisClass.prototype.buildTheme = function(parentNode){
        this.lineNode = document.createElement("path");
        this.lineNode.setAttribute("d", "M" + this.x1 + "," + this.y1 + " L" + this.x2 + "," + this.y2);
        this.lineNode.setAttribute("stroke", this.circuit.value ? Active : InActive);
        this.lineNode.setAttribute("stroke-width", "0.25");
        this.lineNode.setAttribute("fill", "none");
        this.lineNode.setAttribute("marker-end", "url(#dot)");
        this.lineNode.setAttribute("marker-start", "url(#dot)");
        this.contentNode = this.lineNode;
        parentNode.appendChild(this.contentNode);
    }
    
    thisClass.prototype.handleEvent = function(evt){
        if (evt.source.value){
            this.lineNode.setAttribute("stroke", Active);
        }else{
            this.lineNode.setAttribute("stroke", InActive);
        }
    }
})

var ClockTheme = Class("ClockTheme",  Theme, function(thisClass, Super){

    thisClass.prototype.init=function(x, y, width, height, circuit, parentNode){
        Super.prototype.init.call(this, circuit)
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.buildTheme(parentNode);
    }
    
    thisClass.prototype.buildTheme = function(parentNode){
        this.contentNode = document.createElement("g");
        this.contentNode.setAttribute("transform", "translate(" + this.x + "," + this.y + ")");
        this.rectNode = document.createElement("rect");
        this.rectNode.setAttribute("x" , 0);
        this.rectNode.setAttribute("y" , 0);
        this.rectNode.setAttribute("rx", 0.5);
        this.rectNode.setAttribute("ry", 0.5);
        this.rectNode.setAttribute("width" , this.width);
        this.rectNode.setAttribute("height" , this.height);
        this.rectNode.setAttribute("fill", CircuitBackground);
        this.rectNode.setAttribute("stroke", CircuitFrame);
        this.rectNode.setAttribute("stroke-width", "0.25");
        
        this.contentNode.appendChild(this.rectNode);
        parentNode.appendChild(this.contentNode);
       
        var r = document.createElement("rect");
        r.setAttribute("x" , 0.5);
        r.setAttribute("y" , 0.5);
        r.setAttribute("rx", 0.5);
        r.setAttribute("ry", 0.5);
        r.setAttribute("width" , this.width * 0.75);
        r.setAttribute("height" , this.height * 0.75);
        r.setAttribute("fill", CircuitBackground);
        r.setAttribute("stroke", CircuitFrame);
        r.setAttribute("stroke-width", "0.1");
        r.setAttribute("transform", "rotate(45,"+this.width / 2 + "," + this.height / 2 + ")");
        this.contentNode.appendChild(r);
        
        var t= document.createElement("text");
        t.setAttribute("font-size","1.5");
        t.setAttribute("text-anchor","middle");
        t.setAttribute("x","2");
        t.setAttribute("y","2.6");
        t.setAttribute("fill", InstrLabel);
        t.appendChild(document.createTextNode("CPG"));
        this.contentNode.appendChild(t);
    }
    
    
    thisClass.prototype.handleEvent = function(evt){
        if (evt.source.value){
            this.rectNode.setAttribute("fill", Active);
        }else{
            this.rectNode.setAttribute("fill", CircuitBackground)//InActive);
        }
    }
})

var GateGateTheme = Class("GateGateTheme", Theme, function(thisClass, Super){

    thisClass.prototype.init=function(x, y, width, height, circuit, parentNode){
        Super.prototype.init.call(this, circuit)
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.buildTheme(parentNode);
    }
    
    thisClass.prototype.buildTheme = function(parentNode){
        this.contentNode = document.createElement("g");
        this.contentNode.setAttribute("transform", "translate(" + this.x + "," + this.y + ")");
        this.rectNode = document.createElement("rect");
        this.rectNode.setAttribute("x" , 0);
        this.rectNode.setAttribute("y" , 0);
        this.rectNode.setAttribute("rx", 0.5);
        this.rectNode.setAttribute("ry", 0.5);
        this.rectNode.setAttribute("width" , this.width);
        this.rectNode.setAttribute("height" , this.height);
        this.rectNode.setAttribute("fill", GateClosed);
        this.rectNode.setAttribute("stroke", CircuitFrame);
        this.rectNode.setAttribute("stroke-width", "0.25");
        this.contentNode.appendChild(this.rectNode);
        parentNode.appendChild(this.contentNode);
    }
    
    
    thisClass.prototype.handleEvent = function(evt){
        if (this.circuit.gateKeeper.value){
            this.rectNode.setAttribute("fill", GateOpen);
        }else{
            this.rectNode.setAttribute("fill", GateClosed);
        }
    }
})


var BusJoinTheme = Class("BusJoinTheme", Theme, function(thisClass, Super){

    thisClass.prototype.init=function(x, y, width, height, circuit, parentNode){
        Super.prototype.init.call(this, circuit)
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.buildTheme(parentNode);
    }
    
    thisClass.prototype.buildTheme = function(parentNode){
        this.contentNode = document.createElement("g");
        this.contentNode.setAttribute("transform", "translate(" + this.x + "," + this.y + ")");
        this.rectNode = document.createElement("rect");
        this.rectNode.setAttribute("x" , 0);
        this.rectNode.setAttribute("y" , 0);
        this.rectNode.setAttribute("rx", 0.1);
        this.rectNode.setAttribute("ry", 0.1);
        this.rectNode.setAttribute("width" , this.width);
        this.rectNode.setAttribute("height" , this.height);
        this.rectNode.setAttribute("fill", GateClosed);
        this.rectNode.setAttribute("stroke", CircuitFrame);
        this.rectNode.setAttribute("stroke-width", "0.25");
        this.contentNode.appendChild(this.rectNode);
        parentNode.appendChild(this.contentNode);
    }
    
    
    thisClass.prototype.handleEvent = function(evt){
        if (evt.source.gateKeeper.value){
            this.rectNode.setAttribute("fill", GateOpen);
        }else{
            this.rectNode.setAttribute("fill", GateClosed);
        }
    }
})

var RegisterTheme = Class("RegisterTheme", GateGateTheme,  function(thisClass, Super){

    thisClass.prototype.arrayToString = function(a){
        var s="";
        for(var i=0;i<a.length;i++){
            if(i % 4 == 0){
                s=" " + s;
            }
            s = (a[i] ?  "1" : "0") + s;
        }
        return s;
    }
    
    thisClass.prototype.handleEvent = function(evt){
        if (this.circuit.assignmentTrigger.value){
            this.rectNode.setAttribute("fill", GateOpenLight);
        }else{
            this.rectNode.setAttribute("fill", GateClosed);
        }
    }
})

var  InstrRegTheme = Class("InstrRegTheme", RegisterTheme, function(thisClass, Super){
    thisClass.prototype.buildTheme = function(parentNode){
        Super.prototype.buildTheme.call(this, parentNode);
        
        //label
        var tn = document.createElement("text");
        tn.setAttribute("font-size","1.25");
        tn.setAttribute("fill",InstrLabel);
        tn.setAttribute("x","0.3");
        tn.setAttribute("y","1.4");
        this.contentNode.appendChild(tn);
        
        var n = document.createElement("tspan");
        n.setAttribute("x",.7);
        n.appendChild(document.createTextNode("case"));
        tn.appendChild(n);
        
        n = document.createElement("tspan");
        n.setAttribute("x",5.2);
        n.appendChild(document.createTextNode("then"));
        tn.appendChild(n);
        
        n = document.createElement("tspan");
        n.setAttribute("x",15.5);
        n.appendChild(document.createTextNode("else"));
        tn.appendChild(n);
        
        n = document.createElement("tspan");
        n.setAttribute("x",22);
        n.appendChild(document.createTextNode("switch signals"));
        tn.appendChild(n);
        
        n = document.createElement("tspan");
        n.setAttribute("x",34);
        n.appendChild(document.createTextNode("pulse signals"));
        tn.appendChild(n);
        
        
        //values
        this.txtNode = document.createElement("text");
        this.txtNode.setAttribute("font-size","2");
        this.txtNode.setAttribute("x","0.3");
        this.txtNode.setAttribute("y","3.5");
        
        this.contentNode.appendChild(this.txtNode);

        this.caseNode = document.createElement("tspan");
        this.caseNode.setAttribute("text-anchor","middle");
        this.caseNode.setAttribute("x",2);
        this.caseNode.appendChild(document.createTextNode("0"));
        this.txtNode.appendChild(this.caseNode);
        
        this.thenNode = document.createElement("tspan");
        this.thenNode.setAttribute("text-anchor","middle");
        this.thenNode.setAttribute("x",6.5);
        this.thenNode.appendChild(document.createTextNode("0"));
        this.txtNode.appendChild(this.thenNode);
        
        this.elseNode = document.createElement("tspan");
        this.elseNode.setAttribute("text-anchor","middle");
        this.elseNode.setAttribute("x",16.5);
        this.elseNode.appendChild(document.createTextNode("0"));
        this.txtNode.appendChild(this.elseNode);
        
        this.switchNodes = new Array();
        for(var i=0;i<12;i++){
            this.switchNodes[i] = document.createElement("tspan");
            this.switchNodes[i].setAttribute("x",31.5 - i);
            this.switchNodes[i].appendChild(document.createTextNode("0"));
            this.txtNode.appendChild(this.switchNodes[i]);
        }
        
        this.pulseNodes = new Array();
        for(var i=0;i<9;i++){
            this.pulseNodes[i] = document.createElement("tspan");
            this.pulseNodes[i].setAttribute("x",41.5-i);
            this.pulseNodes[i].appendChild(document.createTextNode("0"));
            this.txtNode.appendChild(this.pulseNodes[i]);
        }
    }
    
    thisClass.prototype.updateText = function(){
        var a=this.circuit.value;
        for(var i=0;i<9;i++){
            this.pulseNodes[i].firstChild.replaceData(0,1,a[i] ? "1" : "0" );
        }
        for(var i=0;i<12;i++){
            this.switchNodes[i].firstChild.replaceData(0,1,a[i+9] ? "1" : "0" );
        }
        var val = bin2Int(a.slice(21,27));
        this.elseNode.firstChild.replaceData(0,10, "" + val)
        
        var val = bin2Int(a.slice(27,33));
        this.thenNode.firstChild.replaceData(0,10, "" + val)
        
        var val = bin2Int(a.slice(33,36));
        this.caseNode.firstChild.replaceData(0,10, "" + val)
    }
    
    thisClass.prototype.handleEvent = function(evt){
       Super.prototype.handleEvent.call(this, evt); 
       
        this.updateText();
    }
})

var  AddrRegTheme = Class("AddrRegTheme", RegisterTheme, function(thisClass, Super){
    thisClass.prototype.buildTheme = function(parentNode){
        Super.prototype.buildTheme.call(this, parentNode);
        
        //values
        var t= document.createElement("text");
        t.setAttribute("font-size","1.5");
        t.setAttribute("x","1");
        t.setAttribute("y","2.6");
        t.setAttribute("fill", InstrLabel);
        t.appendChild(document.createTextNode("address"));
        this.contentNode.appendChild(t);
        this.txtNode = document.createElement("text");
        this.txtNode.setAttribute("font-size","2");
        this.txtNode.setAttribute("text-anchor","end");
        this.txtNode.setAttribute("x","9");
        this.txtNode.setAttribute("y","2.6");
        this.txtNode.appendChild(document.createTextNode("0"));
        this.contentNode.appendChild(this.txtNode);
    }
    
    thisClass.prototype.updateText = function(){
        var val = bin2Int(this.circuit.value);
        this.txtNode.firstChild.replaceData(0,10, "" + val)
    }
    
    thisClass.prototype.handleEvent = function(evt){
        Super.prototype.handleEvent.call(this, evt);
        this.updateText();
    }
})

var PulseGateTheme=Class("PulseGateTheme", GateGateTheme, function(thisClass, Super){
    thisClass.prototype.buildTheme = function(parentNode){
        Super.prototype.buildTheme.call(this, parentNode);
        var t= document.createElement("text");
        t.setAttribute("font-size","1.5");
        t.setAttribute("text-anchor","middle");
        t.setAttribute("x","6");
        t.setAttribute("y","2.6");
        t.setAttribute("fill", InstrLabel);
        t.appendChild(document.createTextNode("pulse gate"));
        this.contentNode.appendChild(t);
    }
})

var SelectionTheme = Class("SelectionTheme", Theme, function(thisClass, Super){

    thisClass.prototype.init=function(x, y, width, height, circuit, parentNode){
        Super.prototype.init.call(this, circuit)
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.buildTheme(parentNode);
    }
    
    thisClass.prototype.buildTheme = function(parentNode){
        this.contentNode = document.createElement("g");
        this.contentNode.setAttribute("transform", "translate(" + this.x + "," + this.y + ")");
        this.rectNode = document.createElement("rect");
        this.rectNode.setAttribute("x" , 0);
        this.rectNode.setAttribute("y" , 0);
        this.rectNode.setAttribute("rx" , 0.2);
        this.rectNode.setAttribute("ry" , 0.2);
        this.rectNode.setAttribute("width" , this.width);
        this.rectNode.setAttribute("height" , this.height);
        this.rectNode.setAttribute("fill", CircuitBackground);
        this.rectNode.setAttribute("stroke", CircuitFrame);
        this.rectNode.setAttribute("stroke-width", "0.25");
        
        
        this.contentNode.appendChild(this.rectNode);
        parentNode.appendChild(this.contentNode);
        
        var t= document.createElement("text");
        t.setAttribute("font-size","1.5");
        t.setAttribute("text-anchor","middle");
        t.setAttribute("x","4");
        t.setAttribute("y","2.6");
        t.setAttribute("fill", InstrLabel);
        t.appendChild(document.createTextNode("selection"));
        this.contentNode.appendChild(t);
    }
    
    
    thisClass.prototype.handleEvent = function(evt){
        
    }
 })

var RomTheme = Class("RomTheme", Theme, function(thisClass, Super){
    
    thisClass.prototype.init=function(x, y, width, height, circuit, parentNode){
        Super.prototype.init.call(this, circuit)
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.buildTheme(parentNode);
    }
    
    thisClass.prototype.buildTheme = function(parentNode){
        this.contentNode = document.createElement("g");
        this.contentNode.setAttribute("transform", "translate(" + this.x + "," + this.y + ")");
        this.rectNode = document.createElement("rect");
        this.rectNode.setAttribute("x" , 0);
        this.rectNode.setAttribute("y" , 0);
        this.rectNode.setAttribute("rx" , 0.5);
        this.rectNode.setAttribute("ry" , 0.5);
        this.rectNode.setAttribute("width" , this.width);
        this.rectNode.setAttribute("height" , this.height);
        this.rectNode.setAttribute("fill", CircuitBackground);
        this.rectNode.setAttribute("stroke", CircuitFrame);
        this.rectNode.setAttribute("stroke-width", "0.25");
        this.txNode = document.createElement("text");
        this.txNode.setAttribute("x", this.width / 2 );
        this.txNode.setAttribute("y", this.height / 2);
        this.txNode.setAttribute("text-anchor","middle");
        this.txNode.setAttribute("font-size","2");
        this.txNode.appendChild(document.createTextNode("read only memory"))
        this.contentNode.appendChild(this.rectNode);
        this.contentNode.appendChild(this.txNode);
        parentNode.appendChild(this.contentNode);
    }
    
    
    thisClass.prototype.handleEvent = function(evt){
        
    }
})

var MS1321Theme = Class("MS1321Theme", Theme, function(thisClass, Super){

    
    thisClass.prototype.init=function(x, y, circuit, parentNode){
        Super.prototype.init.call(this, circuit)
        this.x = x;
        this.y = y;
        this.buildTheme(parentNode);
    }    
    
    thisClass.prototype.buildTheme = function(parentNode){
        this.contentNode = document.createElement("g");
        this.contentNode.setAttribute("transform", "translate(" + this.x + "," + this.y + ")");
        this.rectNode = document.createElement("rect");
        this.rectNode.setAttribute("x" , 0);
        this.rectNode.setAttribute("y" , 0);
        this.rectNode.setAttribute("rx" , 0.5);
        this.rectNode.setAttribute("ry" , 0.5);
        this.rectNode.setAttribute("width" , 55);
        this.rectNode.setAttribute("height" , 45);
        this.rectNode.setAttribute("fill", MicroBG);
        this.rectNode.setAttribute("stroke", CircuitFrame);
        this.rectNode.setAttribute("stroke-width", "0.25");
        this.contentNode.appendChild(this.rectNode);
        
        this.rom = new RomTheme(9, 1, 43, 12, this.circuit.rom, this.contentNode);
        this.addrReg = new AddrRegTheme(1, 15, 10, 4, this.circuit.addrReg, this.contentNode);
        
        this.clock =  new ClockTheme(45, 20, 4, 4, this.circuit.clock, this.contentNode);
        
        this.instrReg = new InstrRegTheme(9, 26, 43, 4, this.circuit.instrReg, this.contentNode);
        
        this.pulseGate = new PulseGateTheme(42, 34, 12, 4, this.circuit.pulseGate, this.contentNode);
                
        //clock -> instrReg, addrReg, pulseGate
        this.clock2addr = new LineTheme(53, 17, 11, 17, this.circuit.clock2addr, this.contentNode);
        this.clock2pulse = new LineTheme(53, 17, 53, 34, this.circuit.clock2addr, this.contentNode);
        this.clock2pulse2 = new LineTheme(53, 22, 49, 22, this.circuit.clock2addr, this.contentNode);
        
        this.clock2instrReg = new LineTheme(45, 22, 41, 22, this.circuit.clock2instrReg, this.contentNode);
        this.clock2instrReg = new LineTheme(41, 22, 41, 26, this.circuit.clock2instrReg, this.contentNode);
        
        //rom2instrReg
        for(var i=0;i<36;i++){
            var name ="rom2instrReg" + i;
            var x = 39 - i * 0.5;
            this[name] = new LineTheme(x, 13,  x, 26, this.circuit[name], this.contentNode);
        }
        
        //instrReg -> pulseGate 
        for(var i=0;i<=8;i++){
            var name ="instrReg2pulseGate" + i;
            var x = 51 - i; 
            this[name] = new LineTheme(x, 30,  x, 34, this.circuit[name], this.contentNode);
        }
       
        //pulseGate -> pulsePins 
        for(var i=0;i<=8;i++){
            var name ="pulseGate2pulsePin" + i;
            var x = 51 - i;
            this[name] = new LineTheme(x, 38,  x, 45, this.circuit[name], this.contentNode);
        }
        
        
        //instrReg -> switchPins
        for(var i=9;i<=20;i++){
            var name ="instrReg2switchPin" + i;
            var x = 50 - i;
            this[name] = new LineTheme(x, 30, x, 45, this.circuit[name], this.contentNode);
        }
        
        //else -> elseGate
        this.elseGate = new BusJoinTheme(24,35, 3.5,4, this.circuit.elseGate, this.contentNode);
        for(var i=0;i<6;i++){
            var name ="else2elseGate" + i;
            var x = 27 - i*0.5;
            this[name] = new LineTheme(x, 30, x, 35, this.circuit[name], this.contentNode);
        }
        //elseGate -> addrBusJoin
        for(var i=0;i<6;i++){
            var name ="elseGate2addrBusJoin" + i;
            var y =  36 + i*0.5;
            this[name] = new LineTheme(24, y, 22, y, this.circuit[name], this.contentNode);
        }
        
                                
        //inAddrPins -> addrBusJoin
        this.addrBusJoin = new BusJoinTheme(19,35, 3.5,4, this.circuit.addrBusJoin, this.contentNode);
        for(var i=0;i<6;i++){
            var name ="inAddrPins2addrBusJoin" + i;
            var x = 22 - i*0.5;
            this[name] = new LineTheme(x, 39, x, 45, this.circuit[name], this.contentNode);
        }
        
        //addrBusJoin -> thenBusJoin
        for(var i=0;i<6;i++){
            var name ="addrBusJoin2thenBusJoin" + i;
            var y =  36 + i*0.5;
            this[name] = new LineTheme(19, y, 17.5, y, this.circuit[name], this.contentNode);
        }
                
        //then -> thenBusJoin
        this.thenBusJoin = new BusJoinTheme(14,35, 3.5,4, this.circuit.thenBusJoin, this.contentNode);
        for(var i=0;i<6;i++){
            var name ="then2thenBusJoin" + i;
            var x = 17 - i*0.5;
            this[name] = new LineTheme(x, 30, x, 35, this.circuit[name], this.contentNode);
        }
        
        //thenBusJoin -> addrReg
        for(var i=0;i<6;i++){
            var name = "thenBusJoin2addrReg" + i;
            var y =  36 + i*0.5;
            var x = 7 - i*0.5;
            this[name] = new LineTheme(14, y, x, y, this.circuit[name], this.contentNode);
        }
        for(var i=0;i<6;i++){
            var name = "thenBusJoin2addrReg" + i;
            var y =  36 + i*0.5;
            var x = 7 - i*0.5;
            this["thenBusJoin2addrReg2" + i] = new LineTheme(x, 19, x, y, this.circuit[name], this.contentNode);
        }
        
        //addrReg -> rom
        for(var i=0;i<6;i++){
            var name = "addrReg2rom" + i;
            var y =  8 - i*0.5;
            var x = 7 - i*0.5;
            this[name] = new LineTheme(x, 15, x, y, this.circuit[name], this.contentNode);
        }
        for(var i=0;i<6;i++){
            var name = "addrReg2rom" + i;
            var y =  8 - i*0.5;
            var x = 7 - i*0.5;
            this["addrReg2rom2" + i] = new LineTheme(x, y, 9, y, this.circuit[name], this.contentNode);
        }
        
        //case -> selection
        this.selection = new SelectionTheme(5, 40, 8, 4, this.circuit.selection, this.contentNode)
        for(var i=0;i<3;i++){
            var name =  "case2selection" + i;
            var x = 11.5 - i*0.5;
            this[name] = new LineTheme(x, 30, x, 40, this.circuit[name], this.contentNode);
        }
               
        //selection -> testPin
        for(var i=0;i<=6;i++){
            var name = "selection2testPin" + i;
            var x = 12 - i;
            this[name] = new LineTheme(x, 45, x, 44, this.circuit[name], this.contentNode);
        }
        
        //selection -> thenBusJoin
        this.selection2thenBusJoin = new LineTheme(13, 41, 15, 41, this.circuit.selection2thenBusJoin, this.contentNode);
        this.selection2thenBusJoin2 = new LineTheme(15, 41, 15, 39, this.circuit.selection2thenBusJoin, this.contentNode);
        
        this.selection2elseGate = new LineTheme(13, 42, 25, 42, this.circuit.selection2elseGate, this.contentNode);
        this.selection2elseGate2 = new LineTheme(25, 42, 25, 39, this.circuit.selection2elseGate, this.contentNode);
        
        this.selection2addrBusJoin = new LineTheme(13, 43, 28.5, 43, this.circuit.selection2addrBusJoin, this.contentNode);
        this.selection2addrBusJoin2 = new LineTheme(28.5, 43, 28.5, 33, this.circuit.selection2addrBusJoin, this.contentNode);
        this.selection2addrBusJoin3 = new LineTheme(20, 33, 28.5, 33, this.circuit.selection2addrBusJoin, this.contentNode);
        this.selection2addrBusJoin4 = new LineTheme(20, 33, 20, 35, this.circuit.selection2addrBusJoin, this.contentNode);
                 
        parentNode.appendChild(this.contentNode);
        
    }
})
    
