#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
Introspect and modify settings of the bcm53125m managed switch.
"""
import argparse
import logging
import sys

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

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

def _configure():
    """
    Parses arguments to determine the desired mode of operation.
    """
    parser = argparse.ArgumentParser(
        formatter_class=argparse.RawTextHelpFormatter,
        description=__doc__,
    )
    parser.add_argument('--config', default="/etc/3d-p/mgsw.conf", help="The managed switch config-file to use")
    parser.add_argument('--quiet', '-q', action="store_true", help="Disable info-level logging")
    parser.add_argument('--debug', action="store_true", help="Enable debug-level logging")
    parser.add_argument('--verbose', '-v', action="store_true", help="Enable verbose output and additional data")
    parser.add_argument('action', metavar='ACTION', nargs='*', help="""The action to be carried out
port <number> set allow-auto-negotiation (yes|no)
                      Enable or disable auto-negotiation
                  online (yes|no)
                      Turn the port on or off
                  energy-efficient (yes|no)
                      Whether to allow energy-efficient Ethernet operation
                  speed (10|100|1000)
                      Lock the speed to XMbps; 1000Mbps requires
                      auto-negotiation
                  duplex (f|h)
                      Lock the duplexing mode to f(ull) or h(alf)
              advertise speed (10f|100f|1000f|10h|100h|1000h) [...]
                            Set the list of speed/duplexing modes
                            to advertise
                        pause (yes|no)
                            Advertise pause capability
                        asymmetric-pause (yes|no)
                            Advertise asymmetric pause capability
              auto-negotiate
                  Restart the auto-negotiation process
              reset
                  Resets the port's PHY
              <nil>
                  Display information about the specified port
register read <page> <address> <count>
            Present the value of :count: bytes
         write <page> <address> <byte> [byte...]
            Set the value of bytes starting at the specified address;
            byte offsets are interpreted left-to-right: [0, 8, 16, 24, ...]
        All register commands accept decimal, hex (0x), and binary (0b) notation
<nil>
    Display information about all ports
""".strip())
    args = parser.parse_args()
    CONFIG.read(args.config)
    return args
    
def _render(data, indentation=0):
    for element in data:
        sys.stdout.write(" " * indentation)
        if isinstance(element, bytes):
            element = element.decode('utf-8')
            
        if isinstance(element, str):
            sys.stdout.write(element + "\n")
        else:
            (prefix, data) = element
            sys.stdout.write(prefix + ":")
            if isinstance(data, bytes):
                data = data.decode('utf-8')
                
            if isinstance(data, str):
                sys.stdout.write(" " + data + "\n")
            else:
                sys.stdout.write("\n")
                if data:
                    _render(data, indentation + 4)
                    
if __name__ == '__main__':
    args = _configure()
    
    #Set up logging with appropriate verbosity
    if args.debug:
        log_level = logging.DEBUG
    else:
        log_level = CONFIG.logging
        if log_level < logging.WARN:
            if log_level == logging.INFO and args.quiet:
                log_level = logging.WARN
    logging.basicConfig(
        format="%(asctime)s : %(levelname)s : %(name)s:%(lineno)d : %(message)s",
        level=log_level,
    )
    
    with lib3dp_bcm53125m.devices.USBContextManager() as context_manager:
        with lib3dp_bcm53125m.devices.BCM53125M(context_manager.context) as device:
            _logger.debug("Executing request...")
            try:
                result = lib3dp_bcm53125m.util.evaluate_query(' '.join(args.action), device, verbose=args.verbose)
            except NotImplementedError as e:
                _logger.debug("Invalid request")
                sys.stdout.write(str(e) + "\n")
            else:
                if result is not None:
                    _logger.debug("Rendering result...")
                    _render(result)
                    
