# Copyright (C) 2020 Intel Corporation. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#

import os
import sys
import common
import getopt


ERR_LIST = {}
N_Y = ['n', 'y']
SCHEDULER_TYPE = ['SCHED_NOOP', 'SCHED_IORR', 'SCHED_BVT']

RANGE_DB = {
    'LOG_LEVEL':{'min':0,'max':6},
    'LOG_DESTINATION_BITMAP':{'min':0,'max':7},
    'EMULATED_MMIO_REGIONS':{'min':0,'max':128},
    'PT_IRQ_ENTRIES':{'min':0,'max':256},
    'IOAPIC_NUM':{'min':1,'max':10},
    'IOAPIC_LINES':{'min':1,'max':120},
    'PCI_DEV_NUM':{'min':1,'max':1024},
    'MSIX_TABLE_NUM':{'min':1,'max':2048},
}


def empty_check(val, prime_item, item):
    if not val or val == None:
        key = 'hv,{},{}'.format(prime_item, item)
        ERR_LIST[key] = "{} should not empty".format(item)
        return True

    return False


def is_numeric_check(str_value, prime_item, item):

    # to skip for strip 0x/0X
    if str_value == '0':
        return True
    str_hex_0x = str_value.lstrip('0x')
    str_hex_0X = str_value.lstrip('0X')

    if not str_hex_0x.isnumeric() and not str_hex_0X.isnumeric():
        if not isinstance(int(str_hex_0x, 16), int) and not isinstance(int(str_hex_0X, 16), int):
            key = 'hv,{},{}'.format(prime_item, item)
            ERR_LIST[key] = "{} should be a numeric".format(item)
            return False
    return True


def range_check(str_value, prime_item, item, range_val):

    value = common.num2int(str_value)
    if value < range_val['min'] or value > range_val['max']:
        key = 'hv,{},{}'.format(prime_item, item)
        ERR_LIST[key] = "{} should be in range[{},{}]".format(item, range_val['min'], range_val['max'])


def release_check(sel_str, dbg_opt, rel_str):
    if empty_check(sel_str, dbg_opt, rel_str):
        return
    if sel_str not in N_Y:
        key = 'hv,{},{}'.format(dbg_opt, rel_str)
        ERR_LIST[key] = "{} should be in {}".format(rel_str, N_Y)


def hv_range_check(str_val, branch_tag, item, range_db):

    if empty_check(str_val, branch_tag, item):
        return
    if not is_numeric_check(str_val, branch_tag, item):
        return
    range_check(str_val, branch_tag, item, range_db)


def hv_size_check(str_val, branch_tag, item):

    if empty_check(str_val, branch_tag, item):
        return
    if not is_numeric_check(str_val, branch_tag, item):
        return


def ir_entries_check(str_num, cap, cap_ir_entries):
    hv_size_check(str_num, cap, cap_ir_entries)
    val = common.num2int(str_num)
    if val % 2 != 0:
        key = 'hv,{},{}'.format(cap, cap_ir_entries)
        ERR_LIST[key] = "{} should be a value of 2^n".format(cap_ir_entries)


def uefi_load_name_check(str_name, mis, mis_uefi_name):
    if empty_check(str_name, mis, mis_uefi_name):
        return
    name_len = len(str_name)
    if name_len > 256 or name_len < 1:
        key = 'hv,{},{}'.format(mis, mis_uefi_name)
        ERR_LIST[key] = "{} length should be in range[1, 256]".format(mis_uefi_name)


def ny_support_check(sel_str, feat, feat_item):
    if empty_check(sel_str, feat, feat_item):
        return
    if sel_str not in N_Y:
        key = 'hv,{},{}'.format(feat, feat_item)
        ERR_LIST[key] = "{} should be in {}".format(feat_item, N_Y)


def scheduler_check(sel_str, feat, feat_scheduler):
    if empty_check(sel_str, feat, feat_scheduler):
        return
    if sel_str not in SCHEDULER_TYPE:
        key = 'hv,{},{}'.format(feat, feat_scheduler)
        ERR_LIST[key] = "{} should be in {}".format(feat_scheduler, SCHEDULER_TYPE)


def get_select_range(branch_tag, range_key):

    range_list = []
    if range_key not in RANGE_DB.keys():
        key = "hv,{},{}".format(branch_tag, range_key)
        ERR_LIST[key] = "It is invalid for {}.".format(range_key)
        return range_list

    for range_i in range(RANGE_DB[range_key]['min'], RANGE_DB[range_key]['max'] + 1):
        range_list.append(str(range_i))

    return range_list
