#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
Apply configuration profile to the bcm53125m managed switch.
"""
import argparse
import logging
import os
import subprocess

from lib3dp_bcm53125m.config import BCM53125_CONFIG as CONFIG
import lib3dp_bcm53125m.init
import lib3dp_bcm53125m.devices

_SWITCH_NAME = 'mgsw0'

_IPV6_LINK_LEAD = 0x3d70 #3d + hex(ord('p'))

_logger = logging.getLogger('bcm53125m-config')

_devnull = open('/dev/null', 'w')

def _configure():
    """
    Parses arguments to determine the desired mode of operation.
    """
    parser = argparse.ArgumentParser(description=__doc__,)
    parser.add_argument('--config', default="/etc/3d-p/mgsw.conf", help="The managed switch config-file to use")
    args = parser.parse_args()
    CONFIG.read(args.config)
    return args
    
def _map_vlan(vid):
    for vconfig_candidate in ('/usr/sbin/vconfig', '/sbin/vconfig'):
        if os.access(vconfig_candidate, os.X_OK):
            subprocess.check_call((vconfig_candidate, 'add', _SWITCH_NAME, str(vid),), stdout=_devnull, stderr=subprocess.STDOUT)
            break
    else:
        raise EnvironmentError("vconfig is not available")
        
def _rename_iface(old, new):
    subprocess.check_call(('/sbin/ip', 'link', 'set', 'dev', old, 'name', new,), stdout=_devnull, stderr=subprocess.STDOUT)
    
def _set_iface_online(iface, online):
    subprocess.check_call(('/sbin/ip', 'link', 'set', 'dev', iface, online and 'up' or 'down',), stdout=_devnull, stderr=subprocess.STDOUT)
    
if __name__ == '__main__':
    args = _configure()
    
    #Set up logging with appropriate verbosity
    logging.basicConfig(
        format="%(asctime)s : %(levelname)s : %(name)s:%(lineno)d : %(message)s",
        level=CONFIG.logging,
    )
    
    with lib3dp_bcm53125m.devices.USBContextManager() as context_manager:
        with lib3dp_bcm53125m.devices.BCM53125M(context_manager.context) as device:
            if CONFIG.mode == CONFIG.MODE_BRIDGE:
                lib3dp_bcm53125m.init.bridge(device)
                
                #Bring the switch interface online, so that it may be used
                _set_iface_online(_SWITCH_NAME, True)
                
                #Report the available interfaces
                print(_SWITCH_NAME)
            elif CONFIG.mode == CONFIG.MODE_SWITCH:
                lib3dp_bcm53125m.init.switch(device)
                
                port_map = CONFIG.port_map
                for port_mapping in port_map:
                    _map_vlan(port_mapping.vlan)
                #Ensure the switch interface is offline, so that its members may be renamed
                _set_iface_online(_SWITCH_NAME, False)
                for port_mapping in reversed(port_map):
                    iface = _SWITCH_NAME + '.' + str(port_mapping.vlan)
                    _rename_iface(iface, port_mapping.interface)
                #Bring the switch interface online, so that it may be used
                _set_iface_online(_SWITCH_NAME, True)
                
                #Report the available interfaces
                for port_mapping in port_map:
                    print(port_mapping.interface)
            else:
                raise NotImplementedError("{mode} not yet supported".format(mode=CONFIG.mode))
                
