"""
hpa discovery
"""
import traceback
import uuid
import json
import logging
from hpa import base


def ignore_case_get(args, key, def_val=""):
    """
    get the value of key
    """
    if not key:
        return def_val
    if key in args:
        return args[key]
    for old_key in args:
        if old_key.upper() == key.upper():
            return args[old_key]
    return def_val

class HPADiscovery(base.HPADiscoveryBase):
    """HPA Discovery implementation.
    """
    def __init__(self):
        if not hasattr(self, "_logger"):
            self._logger = logging.getLogger("hpa_discovery")
            self.fh = logging.FileHandler('discovery.log')
            self.fh.setLevel(logging.INFO)
            self._logger.addHandler(self.fh)

    def get_hpa_capabilities(self, data):
        hpa_caps = []

        # Basic capabilties
        caps_dict = self._get_hpa_basic_capabilities(data)
        if len(caps_dict) > 0:
            self._logger.debug("basic_capabilities_info: %s" % caps_dict)
            hpa_caps.append(caps_dict)

        # cpupining capabilities
        caps_dict = self._get_cpupining_capabilities(data)
        if len(caps_dict) > 0:
            self._logger.debug("cpupining_capabilities_info: %s" % caps_dict)
            hpa_caps.append(caps_dict)

        # cputopology capabilities
        caps_dict = self._get_cputopology_capabilities(data)
        if len(caps_dict) > 0:
            self._logger.debug("cputopology_capabilities_info: %s" % caps_dict)
            hpa_caps.append(caps_dict)

        # hugepages capabilities
        caps_dict = self._get_hugepages_capabilities(data)
        if len(caps_dict) > 0:
            self._logger.debug("hugepages_capabilities_info: %s" % caps_dict)
            hpa_caps.append(caps_dict)

        # numa capabilities
        caps_dict = self._get_numa_capabilities(data)
        if len(caps_dict) > 0:
            self._logger.debug("numa_capabilities_info: %s" % caps_dict)
            hpa_caps.append(caps_dict)

        # storage capabilities
        caps_dict = self._get_storage_capabilities(data)
        if len(caps_dict) > 0:
            self._logger.debug("storage_capabilities_info: %s" % caps_dict)
            hpa_caps.append(caps_dict)

        # CPU instruction set extension capabilities
        caps_dict = self._get_instruction_set_capabilities(data)
        if len(caps_dict) > 0:
            self._logger.debug("instruction_set_capabilities_info: %s" % caps_dict)
            hpa_caps.append(caps_dict)

        # PCI passthrough capabilities
        caps_dict = self._get_pci_passthrough_capabilities(data)
        if len(caps_dict) > 0:
            self._logger.debug("pci_passthrough_capabilities_info: %s" % caps_dict)
            hpa_caps.append(caps_dict)

        # SRIOV-NIC capabilities
        caps_dict = self._get_sriov_nic_capabilities(data)
        if len(caps_dict) > 0:
            self._logger.debug("sriov_nic_capabilities_info: %s" % caps_dict)
            hpa_caps.append(caps_dict)

        # ovsdpdk capabilities
        caps_dict = self._get_ovsdpdk_capabilities(data)
        if len(caps_dict) > 0:
            self._logger.debug("ovsdpdk_capabilities_info: %s" % caps_dict)
            hpa_caps.append(caps_dict)

        # self._logger.error("hpa_caps: %s" % (hpa_caps))
        return hpa_caps

    def _get_hpa_basic_capabilities(self, data):
        basic_capability = {}
        feature_uuid = uuid.uuid4()
        flavor = data["flavor"]

        try:
            basic_capability['hpa-capability-id'] = str(feature_uuid)
            basic_capability['hpa-feature'] = 'basicCapabilities'
            basic_capability['architecture'] = 'generic'
            basic_capability['hpa-version'] = 'v1'

            basic_capability['hpa-feature-attributes'] = []
            basic_capability['hpa-feature-attributes'].append(
                {'hpa-attribute-key': 'numVirtualCpu',
                 'hpa-attribute-value':
                     '{{\"value\":\"{0}\"}}'.format(flavor['vcpus'])
                 })
            basic_capability['hpa-feature-attributes'].append(
                {'hpa-attribute-key':'virtualMemSize',
                 'hpa-attribute-value':
                     '{{\"value\":\"{0}\",\"unit\":\"{1}\"}}'.format(flavor['ram'], "MB")
                 })
        except Exception as e:
            self._logger.error(traceback.format_exc())
            return (
                11, e.message
            )

        return basic_capability

    def _get_cpupining_capabilities(self, data):
        cpupining_capability = {}
        feature_uuid = uuid.uuid4()
        extra_specs = data["extra_specs"]

        try:
            if 'hw:cpu_policy' in extra_specs\
                    or 'hw:cpu_thread_policy' in extra_specs:
                cpupining_capability['hpa-capability-id'] = str(feature_uuid)
                cpupining_capability['hpa-feature'] = 'cpuPinning'
                cpupining_capability['architecture'] = 'generic'
                cpupining_capability['hpa-version'] = 'v1'

                cpupining_capability['hpa-feature-attributes'] = []
                if 'hw:cpu_thread_policy' in extra_specs:
                    cpupining_capability['hpa-feature-attributes'].append(
                        {'hpa-attribute-key': 'logicalCpuThreadPinningPolicy',
                         'hpa-attribute-value':
                             '{{\"value\":\"{0}\"}}'.format(
                                 extra_specs['hw:cpu_thread_policy'])
                         })
                if 'hw:cpu_policy' in extra_specs:
                    cpupining_capability['hpa-feature-attributes'].append(
                        {'hpa-attribute-key':'logicalCpuPinningPolicy',
                         'hpa-attribute-value':
                             '{{\"value\":\"{0}\"}}'.format(
                                 extra_specs['hw:cpu_policy'])
                         })
        except Exception:
            self._logger.error(traceback.format_exc())

        return cpupining_capability

    def _get_cputopology_capabilities(self, data):
        cputopology_capability = {}
        feature_uuid = uuid.uuid4()
        extra_specs = data["extra_specs"]

        try:
            if 'hw:cpu_sockets' in extra_specs\
                    or 'hw:cpu_cores' in extra_specs\
                    or 'hw:cpu_threads' in extra_specs:
                cputopology_capability['hpa-capability-id'] = str(feature_uuid)
                cputopology_capability['hpa-feature'] = 'cpuTopology'
                cputopology_capability['architecture'] = 'generic'
                cputopology_capability['hpa-version'] = 'v1'

                cputopology_capability['hpa-feature-attributes'] = []
                if 'hw:cpu_sockets' in extra_specs:
                    cputopology_capability['hpa-feature-attributes'].append(
                        {'hpa-attribute-key': 'numCpuSockets',
                         'hpa-attribute-value':
                             '{{\"value\":\"{0}\"}}'.format(extra_specs['hw:cpu_sockets'])
                         })
                if 'hw:cpu_cores' in extra_specs:
                    cputopology_capability['hpa-feature-attributes'].append(
                        {'hpa-attribute-key': 'numCpuCores',
                         'hpa-attribute-value':
                             '{{\"value\":\"{0}\"}}'.format(extra_specs['hw:cpu_cores'])
                         })
                if 'hw:cpu_threads' in extra_specs:
                    cputopology_capability['hpa-feature-attributes'].append(
                        {'hpa-attribute-key': 'numCpuThreads',
                         'hpa-attribute-value':
                             '{{\"value\":\"{0}\"}}'.format(extra_specs['hw:cpu_threads'])
                         })
        except Exception:
            self._logger.error(traceback.format_exc())

        return cputopology_capability

    def _get_hugepages_capabilities(self, data):
        hugepages_capability = {}
        feature_uuid = uuid.uuid4()
        extra_specs = data["extra_specs"]

        try:
            if 'hw:mem_page_size' in extra_specs:
                hugepages_capability['hpa-capability-id'] = str(feature_uuid)
                hugepages_capability['hpa-feature'] = 'hugePages'
                hugepages_capability['architecture'] = 'generic'
                hugepages_capability['hpa-version'] = 'v1'

                hugepages_capability['hpa-feature-attributes'] = []
                if extra_specs['hw:mem_page_size'] == 'large':
                    hugepages_capability['hpa-feature-attributes'].append(
                        {'hpa-attribute-key': 'memoryPageSize',
                         'hpa-attribute-value':
                             '{{\"value\":\"{0}\",\"unit\":\"{1}\"}}'.format(2, "MB")
                         })
                elif extra_specs['hw:mem_page_size'] == 'small':
                    hugepages_capability['hpa-feature-attributes'].append(
                        {'hpa-attribute-key': 'memoryPageSize',
                         'hpa-attribute-value':
                             '{{\"value\":\"{0}\",\"unit\":\"{1}\"}}'.format(4, "KB")
                         })
                elif extra_specs['hw:mem_page_size'] == 'any':
                    self._logger.info("Currently HPA feature did not support 'any'!!")
                else:
                    hugepages_capability['hpa-feature-attributes'].append(
                        {'hpa-attribute-key': 'memoryPageSize',
                         'hpa-attribute-value':
                             '{{\"value\":\"{0}\",\"unit\":\"{1}\"}}'.format(
                                 extra_specs['hw:mem_page_size'], "KB")
                         })
        except Exception:
            self._logger.error(traceback.format_exc())

        return hugepages_capability

    def _get_numa_capabilities(self, data):
        numa_capability = {}
        feature_uuid = uuid.uuid4()
        extra_specs = data["extra_specs"]

        try:
            if 'hw:numa_nodes' in extra_specs:
                numa_capability['hpa-capability-id'] = str(feature_uuid)
                numa_capability['hpa-feature'] = 'numa'
                numa_capability['architecture'] = 'generic'
                numa_capability['hpa-version'] = 'v1'

                numa_capability['hpa-feature-attributes'] = []
                numa_capability['hpa-feature-attributes'].append(
                    {'hpa-attribute-key': 'numaNodes',
                     'hpa-attribute-value':
                         '{{\"value\":\"{0}\"}}'.format(extra_specs['hw:numa_nodes'] or 0)
                     })

                for num in range(0, int(extra_specs['hw:numa_nodes'])):
                    numa_cpu_node = "hw:numa_cpus.%s" % num
                    numa_mem_node = "hw:numa_mem.%s" % num
                    numacpu_key = "numaCpu-%s" % num
                    numamem_key = "numaMem-%s" % num

                    if numa_cpu_node in extra_specs and numa_mem_node in extra_specs:
                        numa_capability['hpa-feature-attributes'].append(
                            {'hpa-attribute-key': numacpu_key,
                             'hpa-attribute-value':
                                 '{{\"value\":\"{0}\"}}'.format(extra_specs[numa_cpu_node])
                             })
                        numa_capability['hpa-feature-attributes'].append(
                            {'hpa-attribute-key': numamem_key,
                             'hpa-attribute-value':
                                 '{{\"value\":\"{0}\",\"unit\":\"{1}\"}}'.format(
                                     extra_specs[numa_mem_node], "MB")
                             })
        except Exception:
            self._logger.error(traceback.format_exc())

        return numa_capability

    def _get_storage_capabilities(self, data):
        storage_capability = {}
        feature_uuid = uuid.uuid4()
        flavor = data["flavor"]

        try:
            storage_capability['hpa-capability-id'] = str(feature_uuid)
            storage_capability['hpa-feature'] = 'localStorage'
            storage_capability['architecture'] = 'generic'
            storage_capability['hpa-version'] = 'v1'

            storage_capability['hpa-feature-attributes'] = []
            storage_capability['hpa-feature-attributes'].append(
                {'hpa-attribute-key': 'diskSize',
                 'hpa-attribute-value':
                     '{{\"value\":\"{0}\",\"unit\":\"{1}\"}}'.format(
                         flavor['disk'] or 0, "GB")
                 })
            storage_capability['hpa-feature-attributes'].append(
                {'hpa-attribute-key': 'swapMemSize',
                 'hpa-attribute-value':
                     '{{\"value\":\"{0}\",\"unit\":\"{1}\"}}'.format(
                         flavor['swap'] or 0, "MB")
                 })
            storage_capability['hpa-feature-attributes'].append(
                {'hpa-attribute-key': 'ephemeralDiskSize',
                 'hpa-attribute-value':
                     '{{\"value\":\"{0}\",\"unit\":\"{1}\"}}'.format(
                         flavor['OS-FLV-EXT-DATA:ephemeral'] or 0, "GB")
                 })
        except Exception:
            self._logger.error(traceback.format_exc())

        return storage_capability

    def _get_instruction_set_capabilities(self, data):
        instruction_capability = {}
        feature_uuid = uuid.uuid4()
        extra_specs = data["extra_specs"]

        try:
            if 'hw:capabilities:cpu_info:features' in extra_specs:
                instruction_capability['hpa-capability-id'] = str(feature_uuid)
                instruction_capability['hpa-feature'] = 'instructionSetExtensions'
                instruction_capability['architecture'] = 'Intel64'
                instruction_capability['hpa-version'] = 'v1'

                instruction_capability['hpa-feature-attributes'] = []
                instruction_capability['hpa-feature-attributes'].append(
                    {'hpa-attribute-key': 'instructionSetExtensions',
                     'hpa-attribute-value':
                         '{{\"value\":\"{0}\"}}'.format(
                             extra_specs['hw:capabilities:cpu_info:features'])
                     })
        except Exception:
            self._logger.error(traceback.format_exc())

        return instruction_capability

    def _get_pci_passthrough_capabilities(self, data):
        pci_passthrough_capability = {}
        feature_uuid = uuid.uuid4()
        extra_specs = data["extra_specs"]

        try:

            if 'pci_passthrough:alias' in extra_specs:
                value1 = extra_specs['pci_passthrough:alias'].split(':')
                value2 = value1[0].split('-')

                pci_passthrough_capability['hpa-capability-id'] = str(feature_uuid)
                pci_passthrough_capability['hpa-feature'] = 'pciePassthrough'
                pci_passthrough_capability['architecture'] = str(value2[2])
                pci_passthrough_capability['hpa-version'] = 'v1'


                pci_passthrough_capability['hpa-feature-attributes'] = []
                pci_passthrough_capability['hpa-feature-attributes'].append(
                    {'hpa-attribute-key': 'pciCount',
                     'hpa-attribute-value':
                         '{{\"value\":\"{0}\"}}'.format(value1[1])
                     })
                pci_passthrough_capability['hpa-feature-attributes'].append(
                    {'hpa-attribute-key': 'pciVendorId',
                     'hpa-attribute-value':
                         '{{\"value\":\"{0}\"}}'.format(value2[3])
                     })
                pci_passthrough_capability['hpa-feature-attributes'].append(
                    {'hpa-attribute-key': 'pciDeviceId',
                     'hpa-attribute-value':
                         '{{\"value\":\"{0}\"}}'.format(value2[4])
                     })
        except Exception:
            self._logger.error(traceback.format_exc())

        return pci_passthrough_capability

    def _get_sriov_nic_capabilities(self, data):
        sriov_capability = {}
        feature_uuid = uuid.uuid4()
        extra_specs = data["extra_specs"]

        try:
            if 'aggregate_instance_extra_specs:sriov_nic' in extra_specs:
                value1 = extra_specs['aggregate_instance_extra_specs:sriov_nic'].split(':')
                value2 = value1[0].split('-', 5)

                sriov_capability['hpa-capability-id'] = str(feature_uuid)
                sriov_capability['hpa-feature'] = 'sriovNICNetwork'
                sriov_capability['architecture'] = str(value2[2])
                sriov_capability['hpa-version'] = 'v1'

                sriov_capability['hpa-feature-attributes'] = []
                sriov_capability['hpa-feature-attributes'].append(
                    {'hpa-attribute-key': 'pciCount',
                     'hpa-attribute-value':
                         '{{\"value\":\"{0}\"}}'.format(value1[1])})
                sriov_capability['hpa-feature-attributes'].append(
                    {'hpa-attribute-key': 'pciVendorId',
                     'hpa-attribute-value':
                         '{{\"value\":\"{0}\"}}'.format(value2[3])})
                sriov_capability['hpa-feature-attributes'].append(
                    {'hpa-attribute-key': 'pciDeviceId',
                     'hpa-attribute-value':
                         '{{\"value\":\"{0}\"}}'.format(value2[4])})
                sriov_capability['hpa-feature-attributes'].append(
                    {'hpa-attribute-key': 'physicalNetwork',
                     'hpa-attribute-value':
                         '{{\"value\":\"{0}\"}}'.format(value2[5])})
        except Exception:
            self._logger.error(traceback.format_exc())

        return sriov_capability

    def _get_ovsdpdk_capabilities(self, data):
        ovsdpdk_capability = {}
        feature_uuid = uuid.uuid4()
        extra_specs = data["extra_specs"]
        viminfo = data["viminfo"]
        vimtype = data["vimtype"]
        libname = "dataProcessingAccelerationLibrary"
        libversion = "12.1"

        try:
            ovsdpdk_capability['hpa-capability-id'] = str(feature_uuid)
            ovsdpdk_capability['hpa-feature'] = 'ovsDpdk'
            ovsdpdk_capability['architecture'] = 'Intel64'
            ovsdpdk_capability['hpa-version'] = 'v1'

            cloud_extra_info_str = viminfo.get('cloud_extra_info')
            if cloud_extra_info_str in [None, '']:
                if vimtype in ["windriver", "starlingx"]:
                    libname = "dataProcessingAccelerationLibrary"
                    libversion = "17.2"
            else:
                if not isinstance(cloud_extra_info_str, dict):
                    try:
                        cloud_extra_info_str = json.loads(cloud_extra_info_str)
                    except Exception as ex:
                        self._logger.error("Can not convert cloud extra info %s %s" % (
                            str(ex), cloud_extra_info_str))
                        return {}
                if cloud_extra_info_str:
                    cloud_dpdk_info = cloud_extra_info_str.get("ovsDpdk")
                    if cloud_dpdk_info:
                        libname = cloud_dpdk_info.get("libname")
                        libversion = cloud_dpdk_info.get("libversion")

            ovsdpdk_capability['hpa-feature-attributes'] = [
                {
                    'hpa-attribute-key': str(libname),
                    'hpa-attribute-value': '{{\"value\":\"{0}\"}}'.format(libversion)
                },]
        except Exception:
            self._logger.error(traceback.format_exc())

        return ovsdpdk_capability
