#!/usr/bin/env python

# Copyright (C) 2019 Cumulus Networks, Inc. all rights reserved
#
# This software is subject to the Cumulus Networks End User License Agreement available
# at the following locations:
#
# Internet: https://cumulusnetworks.com/downloads/eula/latest/view/
# Cumulus Linux systems: /usr/share/cumulus/EULA.txt

"""
Usage:
  qualify_module [PORTS] [--type-map FILE] [--export RESULTS] [--full] [--no-color]

Options:
  PORTS                   Comma separated list of swp ports.  Leave blank for all ports
  --type-map FILE         Specify json filename to import port-to-module-type relationships
  --export RESULTS        Specify json filename to export test results
  --full                  Run all tests on give modules, otherwise just compliance type check
  --no-color              Override automatic compatibility check and disable terminal colors
  -h, --help              Show this screen


"""

import os
import sys
import subprocess
import logging
import re
from docopt import docopt

from module_qualify.qualify_utils import validate, save_results, get_load_funcs, get_port_type_map
from cl_parsers import parse

logger = logging.getLogger("cable-qualification")
logging.basicConfig(level=logging.INFO, format='%(name)s: %(message)s')


def load_local_data(arguments):

    FNULL = open(os.devnull, 'w')

    # Taken from cl-support
    def filter_ports(port):
        port_pattern = re.compile('^sw[0-9]*p[0-9]+(s[0-3])?$')
        if not port_pattern.match(port):
            return False
        return not (os.path.isdir("/sys/class/net/{}/bridge".format(port))
                    or os.path.isdir("/sys/class/net/{}/bonding".format(port)))

    ports = [p for p in list(os.walk("/sys/class/net/"))[0][1] if filter_ports(p)]

    if arguments["PORTS"] is not None:
        ports = list(set(arguments['PORTS'].split(',')).intersection(set(ports)))

    results = {"localhost": {}}

    try:
        cmd = "/usr/lib/cumulus/portmap"
        raw_map = "\n".join([l for l in subprocess.check_output(cmd).split('\n') if l.strip() != ""])
        port_map = parse("cat porttab", raw_map)
    except Exception:
        port_map = None

    cmd = "net show system"
    raw_data = subprocess.check_output(cmd, shell=True)
    system_info = parse(cmd, raw_data)

    results["localhost"]["platform_info"] = system_info

    for port in ports:

        if port_map is not None:
            results["localhost"][port] = {"sdk": port_map[port]["sdk_intf"],
                                          "unit": port_map[port]["unit"],
                                          "meta": {}}
        else:
            results["localhost"][port] = {"meta": {}}

        for func in get_load_funcs():
            parser, command, _, meta = func()

            cmd = command.format(port=port,
                                 sdk=results["localhost"][port].get("sdk", "None"),
                                 unit=results["localhost"][port].get("unit", "0"))
            try:
                out = subprocess.check_output(cmd, shell=True, stderr=FNULL)
            except Exception:
                continue

            val = parser(parse(cmd, out))
            if val != {}:
                if not meta:
                    results["localhost"][port].update(val)
                else:
                    results["localhost"][port]["meta"].update(val)

    return results


def main():

    release_version = 'qualify_module 1.0'

    # Load arguments
    arguments = docopt(__doc__, version=release_version)
    
    # Override color compatibility if needed
    if arguments["--no-color"]: os.environ["NO_TERMCOLOR"] = "TRUE"

    # Determine mechanism to load
    results = load_local_data(arguments)

    # Retrieve port to module type map
    port_type_map, db = get_port_type_map(arguments, results)

    # Validate the data
    val = validate(arguments, port_type_map, db, results)

    # Export results to json
    save_results(arguments, val)


if __name__ == '__main__':
    sys.exit(main())
