import unittest
import spydrnet as sdn

from spydrnet.plugins.data_manager import DataManager
from spydrnet.global_state.global_netlist import set_current_netlist, get_current_netlist


class TestDataManager(unittest.TestCase):
    def gen_netlist(self):
        netlist = sdn.Netlist()
        set_current_netlist(netlist)
        return netlist

    def gen_library(self):
        netlist = self.gen_netlist()
        lib = netlist.create_library()
        return lib

    def gen_definition(self):
        lib = self.gen_library()
        defin = lib.create_definition()
        return defin
        

    def test_basic_setup(self):
        netlist = self.gen_netlist()
        dm = DataManager()
        lib1 = netlist.create_library()
        lib2 = netlist.create_library()
        lib1['EDIF.identifier'] = "my_lib1"
        lib2['EDIF.identifier'] = "my_lib2"
        def1 = lib1.create_definition()
        def1['EDIF.identifier'] = "d1"
        def2 = lib2.create_definition()
        def2['EDIF.identifier'] = "d1"
        def3 = lib1.create_definition()
        def3['EDIF.identifier'] = "my_lib1"
        c1 = def1.create_cable()
        p1 = def1.create_port()
        i1 = def1.create_child()
        c2 = def1.create_cable()
        p2 = def1.create_port()
        i2 = def1.create_child()
        c1['EDIF.identifier'] = "1"
        i1['EDIF.identifier'] = "1"
        p1['EDIF.identifier'] = "1"
        c2['EDIF.identifier'] = "2"
        i2['EDIF.identifier'] = "2"
        p2['EDIF.identifier'] = "2"

        

    def test_dont_track_orphaned(self):
        netlist = self.gen_netlist()
        dm = DataManager()
        lib1 = sdn.Library()
        lib2 = sdn.Library()
        lib1['EDIF.identifier'] = "my_lib1"
        lib2['EDIF.identifier'] = "my_lib1"

    @unittest.expectedFailure
    def test_duplicate_library_name(self):
        netlist = self.gen_netlist()
        dm = DataManager()
        lib1 = netlist.create_library()
        lib2 = netlist.create_library()
        lib1['EDIF.identifier'] = "my_lib"
        lib2['EDIF.identifier'] = "my_lib"

    
    @unittest.expectedFailure
    def test_duplicate_definition_name(self):
        lib1 = self.gen_library()
        dm = DataManager()
        def1 = lib1.create_definition()
        def2 = lib1.create_definition()
        def1['EDIF.identifier'] = "my_lib"
        def2['EDIF.identifier'] = "my_lib"

    def test_duplicate_definition_elements(self):
        def1 = self.gen_definition()
        dm = DataManager()
        port = def1.create_port()
        instance = def1.create_child()
        cable = def1.create_cable()
        port['EDIF.identifier'] = "my_lib"
        instance['EDIF.identifier'] = "my_lib"
        cable['EDIF.identifier'] = "my_lib"

    @unittest.expectedFailure
    def test_duplicate_definition_ports(self):
        def1 = self.gen_definition()
        dm = DataManager()
        port = def1.create_port()
        port2 = def1.create_port()
        port['EDIF.identifier'] = "my_lib"
        port2['EDIF.identifier'] = "my_lib"

    @unittest.expectedFailure
    def test_duplicate_definition_cables(self):
        def1 = self.gen_definition()
        dm = DataManager()
        cable = def1.create_cable()
        cable2 = def1.create_cable()
        cable['EDIF.identifier'] = "my_lib"
        cable2['EDIF.identifier'] = "my_lib"

    @unittest.expectedFailure
    def test_duplicate_definition_children(self):
        def1 = self.gen_definition()
        dm = DataManager()
        instance = def1.create_child()
        instance2 = def1.create_child()
        instance['EDIF.identifier'] = "my_lib"
        instance2['EDIF.identifier'] = "my_lib"

    def test_rename(self):
        netlist = self.gen_netlist()
        dm = DataManager()
        lib1 = netlist.create_library()
        lib1['EDIF.identifier'] = "my_lib1"
        lib1['EDIF.identifier'] = "my_lib2"
        lib1['EDIF.identifier'] = "my_lib1"
        lib2 = netlist.create_library()
        lib2['EDIF.identifier'] = "my_lib2"
        def1 = lib1.create_definition()
        def1['EDIF.identifier'] = "my_lib1"
        def1['EDIF.identifier'] = "my_lib2"
        def1['EDIF.identifier'] = "my_lib1"
        def2 = lib1.create_definition()
        def2['EDIF.identifier'] = "my_lib2"
        c = def1.create_cable()
        c['EDIF.identifier'] = "1"
        c['EDIF.identifier'] = "2"
        c['EDIF.identifier'] = "1"
        p = def1.create_port()
        p['EDIF.identifier'] = "1"
        p['EDIF.identifier'] = "2"
        p['EDIF.identifier'] = "1"
        i = def1.create_child()
        i['EDIF.identifier'] = "1"
        i['EDIF.identifier'] = "2"
        i['EDIF.identifier'] = "1"

    def test_remove(self):
        netlist = self.gen_netlist()
        dm = DataManager()
        lib1 = netlist.create_library()
        lib1['EDIF.identifier'] = "my_lib1"
        netlist.remove_library(lib1)
        lib2 = netlist.create_library()
        lib2['EDIF.identifier'] = "my_lib1"
        def1 = lib2.create_definition()
        def1['EDIF.identifier'] = "my_lib1"
        lib2.remove_definition(def1)
        def2 = lib2.create_definition()
        def2['EDIF.identifier'] = "my_lib1"
        c1 = def2.create_cable()
        c2 = def2.create_cable()
        p1 = def2.create_port()
        p2 = def2.create_port()
        i1 = def2.create_child()
        i2 = def2.create_child()
        c1['EDIF.identifier'] = "1"
        def2.remove_cable(c1)
        c2['EDIF.identifier'] = "1"
        p1['EDIF.identifier'] = "1"
        def2.remove_port(p1)
        p2['EDIF.identifier'] = "1"
        i1['EDIF.identifier'] = "1"
        def2.remove_child(i1)
        i2['EDIF.identifier'] = "1"

    def test_orphaned_add(self):
        netlist = self.gen_netlist()
        dm = DataManager()
        lib1 = sdn.Library()
        lib1["EDIF.identifier"] = '1'
        netlist.add_library(lib1)

    @unittest.expectedFailure
    def test_orphaned_add_collision(self):
        netlist = self.gen_netlist()
        dm = DataManager()
        lib1 = sdn.Library()
        lib1["EDIF.identifier"] = '1'
        netlist.add_library(lib1)
        lib2 = sdn.Library()
        lib2["EDIF.identifier"] = '1'
        netlist.add_library(lib2)

    @unittest.expectedFailure
    def test_remove_twice_library(self):
        netlist = self.gen_netlist()
        dm = DataManager()
        lib1 = netlist.create_library()
        lib1['EDIF.identifier'] = "my_lib1"
        netlist.remove_library(lib1)
        netlist.remove_library(lib1)

    @unittest.expectedFailure
    def test_remove_twice_definition(self):
        lib = self.gen_library()
        dm = DataManager()
        d1 = lib.create_definition()
        d1['EDIF.identifier'] = "1"
        lib.remove_definition(d1)
        lib.remove_definition(d1)

    def test_remove_untracked(self):
        netlist = self.gen_netlist()
        dm = DataManager()
        lib1 = netlist.create_library()
        def1 = lib1.create_definition()
        c1 = def1.create_cable()
        p1 = def1.create_port()
        i1 = def1.create_child()
        def1.remove_cable(c1)
        def1.remove_child(i1)
        def1.remove_port(p1)
        lib1.remove_definition(def1)
        netlist.remove_library(lib1)

    def test_remove_tracked(self):
        netlist = self.gen_netlist()
        dm = DataManager()
        lib1 = netlist.create_library()
        lib1["EDIF.identifier"] = "test"
        def1 = lib1.create_definition()
        def1["EDIF.identifier"] = "test"
        c1 = def1.create_cable()
        c1["EDIF.identifier"] = "test"
        p1 = def1.create_port()
        p1["EDIF.identifier"] = "test"
        i1 = def1.create_child()
        i1["EDIF.identifier"] = "test"
        def1.remove_cable(c1)
        def1.remove_child(i1)
        def1.remove_port(p1)
        lib1.remove_definition(def1)
        netlist.remove_library(lib1)

    def test_pop_name(self):
        netlist = self.gen_netlist()
        dm = DataManager()
        lib1 = netlist.create_library()
        lib1['EDIF.identifier'] = "my_lib1"
        lib1.pop('EDIF.identifier')
        lib2 = netlist.create_library()
        lib2['EDIF.identifier'] = "my_lib1"
        def1 = lib2.create_definition()
        def1['EDIF.identifier'] = "my_lib1"
        def1.pop('EDIF.identifier')
        def2 = lib2.create_definition()
        def2['EDIF.identifier'] = "my_lib1"
        c1 = def2.create_cable()
        c2 = def2.create_cable()
        p1 = def2.create_port()
        p2 = def2.create_port()
        i1 = def2.create_child()
        i2 = def2.create_child()
        c1['EDIF.identifier'] = "1"
        c1.pop('EDIF.identifier')
        c2['EDIF.identifier'] = "1"
        p1['EDIF.identifier'] = "1"
        p1.pop('EDIF.identifier')
        p2['EDIF.identifier'] = "1"
        i1['EDIF.identifier'] = "1"
        i1.pop('EDIF.identifier')
        i2['EDIF.identifier'] = "1"


    '''tests TODO:
    rename an object
    orphan an object and see what happens
    ...
    '''