import json, logging, time
from common.database.api.Database import Database
from common.database.api.context.Constants import DEFAULT_CONTEXT_ID, DEFAULT_TOPOLOGY_ID
from common.database.api.context.service.ServiceState import ServiceState
from common.database.api.context.service.ServiceType import ServiceType
from common.database.api.context.topology.device.OperationalStatus import OperationalStatus

LOGGER = logging.getLogger(__name__)

def populate_example(
    database : Database, context_uuid : str = DEFAULT_CONTEXT_ID, topology_uuid : str = DEFAULT_TOPOLOGY_ID,
    add_devices : bool = True, add_links : bool = True, add_services : bool = True):

    if add_links:
        if not add_devices: raise Exception('add_links requires add_devices')

    if add_services:
        if not add_devices: raise Exception('add_services requires add_devices')
        if not add_links: raise Exception('add_services requires add_links')

    with database:
        database.clear_all()

        context = database.context(context_uuid).create()
        topology = context.topology(topology_uuid).create()

        if add_devices:
            dev_1 = topology.device('DEV1').create(
                device_type='ROADM', device_config='<config/>', device_operational_status=OperationalStatus.ENABLED)
            dev1_ep2 = dev_1.endpoint('EP2').create(port_type='WDM')
            dev1_ep3 = dev_1.endpoint('EP3').create(port_type='WDM')
            dev1_ep4 = dev_1.endpoint('EP4').create(port_type='WDM')
            dev1_ep5 = dev_1.endpoint('EP5').create(port_type='OCH')
            dev1_ep6 = dev_1.endpoint('EP6').create(port_type='OCH')
            dev1_ep7 = dev_1.endpoint('EP7').create(port_type='OCH')

            dev_2 = topology.device('DEV2').create(
                device_type='ROADM', device_config='<config/>', device_operational_status=OperationalStatus.ENABLED)
            dev2_ep1 = dev_2.endpoint('EP1').create(port_type='WDM')
            dev2_ep3 = dev_2.endpoint('EP3').create(port_type='WDM')
            dev2_ep4 = dev_2.endpoint('EP4').create(port_type='WDM')
            dev2_ep5 = dev_2.endpoint('EP5').create(port_type='OCH')
            dev2_ep6 = dev_2.endpoint('EP6').create(port_type='OCH')
            dev2_ep7 = dev_2.endpoint('EP7').create(port_type='OCH')

            dev_3 = topology.device('DEV3').create(
                device_type='ROADM', device_config='<config/>', device_operational_status=OperationalStatus.ENABLED)
            dev3_ep1 = dev_3.endpoint('EP1').create(port_type='WDM')
            dev3_ep2 = dev_3.endpoint('EP2').create(port_type='WDM')
            dev3_ep4 = dev_3.endpoint('EP4').create(port_type='WDM')
            dev3_ep5 = dev_3.endpoint('EP5').create(port_type='OCH')
            dev3_ep6 = dev_3.endpoint('EP6').create(port_type='OCH')
            dev3_ep7 = dev_3.endpoint('EP7').create(port_type='OCH')

            dev_4 = topology.device('DEV4').create(
                device_type='ROADM', device_config='<config/>', device_operational_status=OperationalStatus.ENABLED)
            dev4_ep1 = dev_4.endpoint('EP1').create(port_type='WDM')
            dev4_ep2 = dev_4.endpoint('EP2').create(port_type='WDM')
            dev4_ep3 = dev_4.endpoint('EP3').create(port_type='WDM')
            dev4_ep5 = dev_4.endpoint('EP5').create(port_type='OCH')
            dev4_ep6 = dev_4.endpoint('EP6').create(port_type='OCH')
            dev4_ep7 = dev_4.endpoint('EP7').create(port_type='OCH')

        if add_links:
            link_dev1_to_dev2 = topology.link('DEV1/EP2 ==> DEV2/EP1').create()
            link_dev1_to_dev2.endpoint('DEV1/EP2').create(dev1_ep2)
            link_dev1_to_dev2.endpoint('DEV2/EP1').create(dev2_ep1)

            link_dev1_to_dev3 = topology.link('DEV1/EP3 ==> DEV3/EP1').create()
            link_dev1_to_dev3.endpoint('DEV1/EP3').create(dev1_ep3)
            link_dev1_to_dev3.endpoint('DEV3/EP1').create(dev3_ep1)

            link_dev1_to_dev4 = topology.link('DEV1/EP4 ==> DEV4/EP1').create()
            link_dev1_to_dev4.endpoint('DEV1/EP4').create(dev1_ep4)
            link_dev1_to_dev4.endpoint('DEV4/EP1').create(dev4_ep1)

            link_dev2_to_dev1 = topology.link('DEV2/EP1 ==> DEV1/EP2').create()
            link_dev2_to_dev1.endpoint('DEV2/EP1').create(dev2_ep1)
            link_dev2_to_dev1.endpoint('DEV1/EP2').create(dev1_ep2)

            link_dev2_to_dev3 = topology.link('DEV2/EP3 ==> DEV3/EP2').create()
            link_dev2_to_dev3.endpoint('DEV2/EP3').create(dev2_ep3)
            link_dev2_to_dev3.endpoint('DEV3/EP2').create(dev3_ep2)

            link_dev2_to_dev4 = topology.link('DEV2/EP4 ==> DEV4/EP2').create()
            link_dev2_to_dev4.endpoint('DEV2/EP4').create(dev2_ep4)
            link_dev2_to_dev4.endpoint('DEV4/EP2').create(dev4_ep2)

            link_dev3_to_dev1 = topology.link('DEV3/EP1 ==> DEV1/EP3').create()
            link_dev3_to_dev1.endpoint('DEV3/EP1').create(dev3_ep1)
            link_dev3_to_dev1.endpoint('DEV1/EP3').create(dev1_ep3)

            link_dev3_to_dev2 = topology.link('DEV3/EP2 ==> DEV2/EP3').create()
            link_dev3_to_dev2.endpoint('DEV3/EP2').create(dev3_ep2)
            link_dev3_to_dev2.endpoint('DEV2/EP3').create(dev2_ep3)

            link_dev3_to_dev4 = topology.link('DEV3/EP4 ==> DEV4/EP3').create()
            link_dev3_to_dev4.endpoint('DEV3/EP4').create(dev3_ep4)
            link_dev3_to_dev4.endpoint('DEV4/EP3').create(dev4_ep3)

            link_dev4_to_dev1 = topology.link('DEV4/EP1 ==> DEV1/EP4').create()
            link_dev4_to_dev1.endpoint('DEV4/EP1').create(dev4_ep1)
            link_dev4_to_dev1.endpoint('DEV1/EP4').create(dev1_ep4)

            link_dev4_to_dev2 = topology.link('DEV4/EP2 ==> DEV2/EP4').create()
            link_dev4_to_dev2.endpoint('DEV4/EP2').create(dev4_ep2)
            link_dev4_to_dev2.endpoint('DEV2/EP4').create(dev2_ep4)

            link_dev4_to_dev3 = topology.link('DEV4/EP3 ==> DEV3/EP4').create()
            link_dev4_to_dev3.endpoint('DEV4/EP3').create(dev4_ep3)
            link_dev4_to_dev3.endpoint('DEV3/EP4').create(dev3_ep4)

        if add_services:
            service = context.service('S01').create(ServiceType.L3NM, '<config/>', ServiceState.PLANNED)
            service.endpoint('S01/EP01').create(dev1_ep5)
            service.endpoint('S01/EP02').create(dev2_ep5)
            service.endpoint('S01/EP03').create(dev3_ep5)
            service.endpoint('S01/EP04').create(dev4_ep5)

            service = context.service('S02').create(ServiceType.L3NM, '<config/>', ServiceState.PLANNED)
            service.endpoint('S02/EP01').create(dev1_ep6)
            service.endpoint('S02/EP02').create(dev2_ep6)
            service.endpoint('S02/EP03').create(dev3_ep6)
            service.endpoint('S02/EP04').create(dev4_ep6)

            service = context.service('S03').create(ServiceType.L3NM, '<config/>', ServiceState.PLANNED)
            service.endpoint('S03/EP01').create(dev1_ep7)
            service.endpoint('S03/EP02').create(dev2_ep7)
            service.endpoint('S03/EP03').create(dev3_ep7)
            service.endpoint('S03/EP04').create(dev4_ep7)

def sequence(database : Database):
    populate_example(database)

    with database:
        LOGGER.info('Dump:')
        for entry in database.dump():
            LOGGER.info('  {}'.format(entry))

    with database:
        t0 = time.time()
        context = database.context(DEFAULT_CONTEXT_ID).create()
        json_context = context.dump()
        t1 = time.time()
        LOGGER.info(json.dumps(json_context))
        LOGGER.info('Dump elapsed: {}'.format(1000.0 * (t1-t0)))

    with database:
        database.context(DEFAULT_CONTEXT_ID).delete()
        LOGGER.info('Dump:')
        for entry in database.dump():
            LOGGER.info('  {}'.format(entry))
