import pytest
from skidl import *
from .setup_teardown import *

def test_subcircuit_1():

    class Resistor(Part):
        def __init__(self, value, ref=None, footprint='Resistors_SMD:R_0805'):
            super().__init__('device', 'R', value=value, ref=ref, footprint=footprint)

    @subcircuit
    def resdiv():
        gnd = Net('GND') # Ground reference.
        vin = Net('VI')  # Input voltage to the divider.
        vout = Net('VO')  # Output voltage from the divider.

        r1 = Resistor('1k')
        r2 = Resistor('500')

        cap = Part('device','C', dest=TEMPLATE)
        c1 = cap()
        c2 = cap(value='1uF')

        bus1 = Bus('BB',10)

        r1[1] += vin  # Connect the input to the first resistor.
        r2[2] += gnd  # Connect the second resistor to ground.
        vout += r1[2], r2[1]  # Output comes from the connection of the two resistors.

    circuit1 = Circuit()
    circuit2 = Circuit()
    resdiv(circuit=circuit2)
    resdiv()
    resdiv(circuit=circuit1)
    resdiv(circuit=circuit1)
    resdiv(circuit=circuit2)
    resdiv(circuit=circuit2)

    assert len(default_circuit.parts) == 4
    assert len(default_circuit.get_nets()) == 3
    assert len(default_circuit.buses) == 1

    assert len(circuit1.parts) == 8
    assert len(circuit1.get_nets()) == 6
    assert len(circuit1.buses) == 2

    assert len(circuit2.parts) == 12
    assert len(circuit2.get_nets()) == 9
    assert len(circuit2.buses) == 3

    ERC()
    generate_netlist()
    generate_xml()

    circuit1.ERC()
    circuit1.generate_netlist()
    circuit1.generate_xml()

    circuit2.ERC()
    circuit2.generate_netlist()
    circuit2.generate_xml()

def test_subcircuit_2():

    class Resistor(Part):
        def __init__(self, value, ref=None, footprint='Resistors_SMD:R_0805'):
            super().__init__('device', 'R', value=value, ref=ref, footprint=footprint)

    @subcircuit    
    def resdiv_1():
        gnd = Net('GND') # Ground reference.
        vin = Net('VI')  # Input voltage to the divider.
        vout = Net('VO')  # Output voltage from the divider.

        r1 = Resistor('1k')
        r2 = Resistor('500')

        cap = Part('device','C', dest=TEMPLATE)
        c1 = cap()
        c2 = cap(value='1uF')
        c1[1] += NC
        c2[1,2] += NC

        bus1 = Bus('BB',10)

        r1[1] += vin  # Connect the input to the first resistor.
        r2[2] += gnd  # Connect the second resistor to ground.
        vout += r1[2], r2[1]  # Output comes from the connection of the two resistors.

    @subcircuit    
    def resdiv_2():
        resdiv_1()
        resdiv_1()

        a = Net('GND') # Ground reference.
        b = Net('VI')  # Input voltage to the divider.
        c = Net('VO')  # Output voltage from the divider.

        r1 = Resistor('1k')
        r2 = Resistor('500')

        cap = Part('device','C', dest=TEMPLATE)
        c1 = cap()
        c2 = cap(value='1uF')

        bus1 = Bus('BB',10)

        r1[1] += a  # Connect the input to the first resistor.
        r2[2] += b  # Connect the second resistor to ground.
        c += r1[2], r2[1]  # Output comes from the connection of the two resistors.

    default_circuit.name = 'DEFAULT'
    circuit1 = Circuit(name='CIRCUIT1')
    circuit2 = Circuit(name='CIRCUIT2')
    resdiv_2(circuit=circuit2)
    resdiv_2()
    resdiv_2(circuit=circuit1)
    resdiv_2(circuit=circuit1)
    resdiv_2(circuit=circuit2)
    resdiv_2(circuit=circuit2)

    assert len(default_circuit.parts) == 12
    assert len(default_circuit.get_nets()) == 9
    assert len(default_circuit.buses) == 3
    assert len(NC.pins) == 6

    assert len(circuit1.parts) == 24
    assert len(circuit1.get_nets()) == 18
    assert len(circuit1.buses) == 6
    assert len(circuit1.NC.pins) == 12

    assert len(circuit2.parts) == 36
    assert len(circuit2.get_nets()) == 27
    assert len(circuit2.buses) == 9
    assert len(circuit2.NC.pins) == 18

    ERC()
    generate_netlist()
    generate_xml()

    circuit1.ERC()
    circuit1.generate_netlist()
    circuit1.generate_xml()

    circuit2.ERC()
    circuit2.generate_netlist()
    circuit2.generate_xml()

def test_circuit_add_rmv_1():
    circuit1 = Circuit()
    circuit2 = Circuit()
    r1 = Part('device','R')
    n1 = Net('N1')
    circuit1 += r1
    circuit1 += n1
    assert len(circuit1.parts) == 1
    assert len(circuit2.parts) == 0
    assert len(circuit1.nets) == 2 # Add 1 for NC
    assert len(circuit2.nets) == 1 # Add 1 for NC
    circuit2 += r1
    circuit2 += n1
    assert len(circuit1.parts) == 0
    assert len(circuit2.parts) == 1
    assert len(circuit1.nets) == 1 # Add 1 for NC
    assert len(circuit2.nets) == 2 # Add 1 for NC
    n1 += r1[1]
    with pytest.raises(Exception):
        circuit1 += r1

def test_circuit_add_rmv_2():
    circuit1 = Circuit()
    circuit2 = Circuit()
    r1 = Part('device','R')
    bus = Bus('B', 8)
    circuit1 += bus
    assert len(circuit1.nets) == len(bus) + 1 # Add 1 for NC
    assert len(circuit2.nets) == 1 # Add 1 for NC
    circuit2 += bus
    assert len(circuit1.nets) == 1 # Add 1 for NC
    assert len(circuit2.nets) == len(bus) + 1 # Add 1 for NC

def test_circuit_add_rmv_3():
    circuit = Circuit()
    r = Part('device', 'R')
    c = Part('device', 'C')
    n = Net('N')
    bus = Bus('B', 8)
    circuit += r, c, bus, n
    circuit += r, c, bus, n  # Shouldn't do anything since these are already in the circuit.
    assert len(circuit.nets) == len(bus) + 1 + 1 # Add 1 for NC
    assert len(circuit.parts) == 2
    assert len(circuit.buses) == 1

def test_circuit_connect_btwn_circuits_1():
    circuit1 = Circuit()
    circuit2 = Circuit()
    r1 = Part(tool=SKIDL, name='R')
    r1 += Pin(num=1), Pin(num=2)
    n1 = Net('N1')
    circuit1 += r1
    circuit2 += n1
    with pytest.raises(Exception):
        n1 += r1[1]

def test_circuit_NC_1():
    circuit1 = Circuit()
    circuit2 = Circuit()
    res = Part(tool=SKIDL, name='res', dest=TEMPLATE, pins=[Pin(num=1),Pin(num=2)])
    r1 = res()
    r2 = res(circuit=circuit1)
    r3 = res()
    circuit2 += r3
    r2[1,2] += circuit1.NC
    r3[1] += circuit2.NC
    assert len(NC.pins) == 0
    assert len(circuit1.NC.pins) == 2
    assert len(circuit2.NC.pins) == 1
