# -*- coding:utf-8 -*-
"""
Function: get_bios_all.py moudle. This moudle mainly involves the
querying BIOS configuration function.
Copyright Information: xFusion Digital Technologies Co.,
 Ltd. All Rights Reserved © 2018-2021
"""
import json
import os
import stat
import sys
from json import dumps
from os import path
from scripts import common_function

FAIL = "Failure: insufficient permission for " \
       "the file or file name not specified, " \
       "perform this operation as system administrator/root, " \
       "or specify a file name"

bios_current_dic = None

BIOS_SETTING_INFO_NULL = "the server does not contain information" \
                         " about BIOS setup resource."
BIOS_SETTING_INFO_ATTRIBUTES_NULL = "the server does not contain information" \
                         " about BIOS setup resource Attributes."
SETTING_KEY = "ConfiguredValue"
CURRENT_KEY = "CurrentValue"
setting_attributes_dict = {}
bios_current_dic = {}
content = ""


def getbiosall_init(parser, parser_dict):
    """
    Function Description:initializing the Command for
    querying BIOS configuration.
    Parameter:parser object: action object
    parser_dict dict: dictionary format of subcommand and ArgumentParser
    Modify: 2019.4.28 The help information is optimized.
    Return Value: subcommand
    """
    sub_parser = parser.add_parser('getbiosall',
                                   help='''get BIOS details''')
    sub_parser.add_argument('-F', dest='file',
                            required=False,
                            help='local file used to '
                                 'export the BIOS configuration.')

    parser_dict['getbiosall'] = sub_parser

    return 'getbiosall'


def init_setting_attributes(client, resp):
    """
    Function Description:get bios setting resource
    Parameter:client RefishClient: class object
              resp   dict:redfish result
    """
    try:
        set_url = resp['resource']['@Redfish.Settings']["SettingsObject"][
            "@odata.id"]
    except KeyError:
        return

    setting_resp = client.get_resource(set_url)
    if not setting_resp:
        return

    if setting_resp.get('status_code') != \
            common_function.REDFISH_STATUS_CODE_200:
        return

    setting_resource = setting_resp.get('resource')
    if not setting_resource:
        return

    global setting_attributes_dict
    setting_attributes_dict = setting_resource.get("Attributes", None)


def get_bios(client):
    """
    obtain current value
    :param client:
    :return:
    """
    info = None
    slotid = client.get_slotid()
    if slotid is None:
        return info, None
    url = "/redfish/v1/Systems/%s/Bios" % slotid
    resp = client.get_resource(url)
    if resp is None:
        return info, None

    if resp['status_code'] == 200:
        info = resp['resource'].get('Attributes', None)
        if info is None:
            common_function.print_info('no data available for the resource')
            return info, resp
        return info, resp
    if resp['status_code'] == 404:
        common_function.print_info('Failure: resource was not found')
    else:
        common_function.print_status_code(resp)

    return info, resp


def get_current_value(bios_dic, attribute_name):
    """
    get current value
    :param bios_dic: current bios dic
    :param attribute_name: bios attribute name
    :return: current_value
    """

    current_value = bios_dic[attribute_name]
    if attribute_name == "BMCWDTTimeout" and int(
            bios_dic[attribute_name]) < 15:
        current_value = str(int(bios_dic[attribute_name]) + 15)
    return current_value


def getbiosall(client, args):
    """
    Function Description:BIOS menu item query subcommand processing functions
    Parameter:client refishClient: class object
    args object:CLI command
    Modify: 2018.12.26 Default timeout parameter normalization.
    Return Value: resp dict:result of the redfish interface
    """
    # 检查文件路径是否以 '.txt' 结尾
    if args.file and not args.file.endswith('.txt'):
        common_function.print_info('Failure: -F indicates the path of the BIOS configuration file.'
                                   ' The file name extension must be .txt.')
        return

    if args.file and not os.path.exists(os.path.dirname(args.file)):
        common_function.print_info('Failure: The folder %s does not exist' % os.path.dirname(args.file))
        return
    global bios_current_dic
    bios_current_dic, resp = get_bios(client)
    if bios_current_dic is None:
        return
    init_setting_attributes(client, resp)
    flag, resp = get_subcommand_request(client)
    if flag is True:
        update_resp(resp)
        print_attribute_infor(resp, args)
    if args.file:
        flags = os.O_WRONLY | os.O_CREAT
        modes = stat.S_IWUSR | stat.S_IRUSR
        with os.fdopen(os.open(args.file, flags, modes), 'w') as file:
            file.write(content)
        common_function.print_info('Success: successfully completed request')


def check_resp(resp):
    """
    功能描述: 校验redfish接口返回来的值
    参数：resp (dict):redfish接口返回来的值
    返回值：flag (bool):请求是否成功
        resp (dict):url 请求回来的数据
    """
    if resp is not None and resp['status_code'] == 200:
        return True, resp
    return False, resp


def get_subcommand_request(client):
    """
    Function Description:Obtains the subcommand result from the
     specified Redfish interface.
    Parameter:client refishClient: class object
    Modify: 2019.7.19 Configuring the BIOS Parameters BMCWDTTimeout.
    Return Value: resp dict:result of the redfish interface
    """
    flag, resp = get_registries_uri_resp(client)
    if flag is True:
        flag, resp = get_memmber_uri_resp(client, resp)
        if flag is True:
            flag, resp = get_location_uri_resp(client, resp)
    return flag, resp


def update_resp(resp):
    """
    Function Description:update resp
    Parameter:resp dict:redfish result
    """
    attributes_list = resp['resource']['RegistryEntries'][
        "Attributes"]
    for attribute in attributes_list:
        attribute_name = attribute.get("AttributeName", "")
        if attribute_name in bios_current_dic:
            # Configuring the BIOS Parameters BMCWDTTimeout.
            current_value = get_current_value(bios_current_dic,
                                              attribute_name)
            attribute[CURRENT_KEY] = current_value
            if setting_attributes_dict is not None:
                attribute[SETTING_KEY] = setting_attributes_dict.get(attribute_name)


def print_attribute_infor(resp, args):
    """
    Function Description:displays information about the
     BIOS configuration item name.
    Parameter:resp dict: location uri Obtained Redfish Interface Information
    args object:CLI command
    Return Value: resp dict:result of the redfish interface
    """
    attributes_list = resp['resource']['RegistryEntries']["Attributes"]

    for attribute in attributes_list:
        attribute_name = attribute.get("AttributeName", "")
        print_resource(attribute, attribute_name, args)


def get_registries_uri_resp(client):
    """
    功能描述：从url"/redfish/v1/Registries"的redfish 接口中请求到的结果
    参数：client (redfish_client):redfish接口
    返回值：check_resp(resp)：是否响应成功，已经实际获取到的值
    异常描述：None
    """
    url = "/redfish/v1/Registries"
    resp = client.get_resource(url)
    return check_resp(resp)


def get_location_uri_resp(client, resp):
    """
    功能描述：从url"/redfish/v1/RegistryStore/AttributeRegistries/en/
    BiosAttributeRegistry.vx_x_x.json"的redfish 接口中请求到的结果中取出id
    参数：client (redfish_client):redfish接口
          resp (dict):上级 get_memmber_uri_resp(client, resp)得到的结果
    返回值：check_resp(resp)：是否响应成功，已经实际获取到的值
    异常描述：None
    """
    location_uri = resp['resource']['Location'][0]["Uri"]
    resp = client.get_resource(location_uri, headers=None,
                               timeout=common_function.TIMEOUT_THIRTY)
    return check_resp(resp)


def get_memmber_uri_resp(client, resp):
    """
    功能描述：从url'"/redfish/v1/Registries/BiosAttributeRegistry.vx_x_x"'的
    redfish 接口中请求到的结果中取出id
    参数：resp (dict):上级url'/redfish/v1/Registries'的redfish 接口中请求到的结果
    返回值：check_resp(resp)：是否响应成功，已经实际获取到的值
    异常描述：None
    """
    memmbers = resp['resource']['Members']
    memmber_uri = ''
    for memmber in memmbers:
        if "BiosAttributeRegistry" in memmber["@odata.id"]:
            memmber_uri = memmber["@odata.id"]
            break
    resp = client.get_resource(memmber_uri)
    return check_resp(resp)


def print_or_write(args, message):
    if args.file:
        global content
        content = content + message + "\n"
    else:
        common_function.print_info(message)


def print_resource(attribute, attribute_name, args):
    """
    #=====================================================================
    #   @Method:  Display the returned BIOS data.
    #   @Param:   info, BIOS message dictionary
    #             args, command parameter
    #   @Return:
    #   @author:
    #=====================================================================
    """
    display_name = attribute.get("DisplayName", "")
    help_text = attribute.get("HelpText", "")
    values_list = attribute.get("Value", [])
    format_str = "%-28s%-2s%-s"
    print_or_write(args, "-" * 100)
    print_or_write(args, format_str % ('Attribute', ":", attribute_name))
    print_or_write(args, format_str % (CURRENT_KEY, ":", attribute.get(CURRENT_KEY, "")))
    print_or_write(args, format_str % (SETTING_KEY, ":", attribute.get(SETTING_KEY, "")))
    if values_list:
        value_list = []
        for value in values_list:
            if "ValueName" in list(value.keys()):
                value_name = value["ValueName"]
                value_list.append(value_name)
        optional_values = str(json.dumps(value_list))
        print_or_write(args, format_str % ('Value', ":", optional_values))
    else:
        if "Type" in list(attribute.keys()):
            attribute_type = attribute["Type"]
            if attribute_type == "Integer":
                lower_bound = str(attribute.get("LowerBound", 0))
                upper_bound = str(attribute.get("UpperBound", 0))
                print_or_write(args, format_str % ('UpperBound', ":", upper_bound))
                print_or_write(args, format_str % ('LowerBound', ":", lower_bound))
    print_or_write(args, format_str % ('DisplayName', ":", display_name))
    print_or_write(args, format_str % ('HelpText', ":", help_text))

