# -*- coding:utf-8 -*-
"""
Function: add_logicaldrive.py moudle. This moudle mainly involves the
 creating a Logical Disk function.
Copyright Information: xFusion Digital Technologies Co.,
 Ltd. All Rights Reserved © 2020-2021
"""
import sys
from scripts.common_function import UREST_STATUS_CODE_2
from scripts import common_function

PF = '{0}{1}'


def addlogicaldrive_init(parser, parser_dict):
    """
    Function Description:initializing the Command for
    creating a Logical Disk.
    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('addvdisk',
                                   help='''create virtual disk''')

    sub_parser.add_argument('-I', dest='controllerid',
                            type=int, required=True,
                            help='''controller ID''')

    sub_parser.add_argument('-V', dest='capacitybytes',
                            type=int, required=False,
                            help='''capacitybytes''')

    sub_parser.add_argument('-OV', dest='optsizebytes',
                            type=int,
                            required=False,
                            choices=[65536, 131072, 262144, 524288, 1048576],
                            help='''optsizebytes''')

    sub_parser.add_argument('-CF',
                            dest='cachecadeflag',
                            type=str,
                            required=False,
                            choices=['True', 'False'],
                            help='''cachecadeflag''')

    sub_parser.add_argument('-DI',
                            dest='drives',
                            type=int,
                            required=True,
                            nargs='+',
                            help='''drives, for example:0 1 2''')

    sub_parser.add_argument('-VL',
                            dest='volumeraidlevel',
                            type=str,
                            required=False,
                            choices=['RAID0', 'RAID1', 'RAID5',
                                     'RAID6', 'RAID10',
                                     'RAID50', 'RAID60'],
                            help='''volumeraidlevel''')

    sub_parser.add_argument('-N',
                            dest='volumename',
                            type=str,
                            required=False,
                            help='''volumename''')

    subparser_argument_ot(sub_parser)
    parser_dict['addvdisk'] = sub_parser
    return 'addvdisk'


def subparser_argument_ot(sub_parser):
    """
      功能描述：sub_parser:控制台子命令CLI,对应的参数解析对象
      参数：None
      返回值：None
      异常描述：None
    """
    sub_parser.add_argument('-RP',
                            dest='defaultreadpolicy',
                            type=str,
                            required=False,
                            choices=['NoReadAhead', 'ReadAhead'],
                            help='''defaultreadpolicy''')
    sub_parser.add_argument('-WP',
                            dest='defaultwritepolicy',
                            type=str,
                            required=False,
                            choices=['WriteThrough',
                                     'WriteBackWithBBU', 'WriteBack'],
                            help='''defaultwritepolicy''')
    sub_parser.add_argument('-CP',
                            dest='defaultcachepolicy',
                            type=str,
                            required=False,
                            choices=['CachedIO', 'DirectIO'],
                            help='''defaultcachepolicy''')
    sub_parser.add_argument('-SN',
                            dest='spannumber',
                            type=int,
                            required=False,
                            help='''spannumber''')
    sub_parser.add_argument('-AP',
                            dest='accesspolicy',
                            type=str,
                            required=False,
                            choices=['ReadWrite', 'ReadOnly', 'Blocked'],
                            help='''accesspolicy''')
    sub_parser.add_argument('-DCP',
                            dest='drivecachepolicy',
                            type=str,
                            required=False,
                            choices=['Unchanged', 'Enabled', 'Disabled'],
                            help='''drivecachepolicy''')
    sub_parser.add_argument('-M',
                            dest='initializationmode',
                            type=str,
                            required=False,
                            choices=['UnInit', 'QuickInit', 'FullInit'],
                            help='''initializationmode''')


def full_other_payload(payload, args):
    """
    #=================================================================
    #   @Method:  Fill the body.
    #   @Param:   payload       Body
                  args       Enter parameters.
    #   @Return:  none
    #   @author:
    #=================================================================
    """
    # Default read policy
    payload_vendor = payload['Oem'][common_function.COMMON_KEY]
    if args.defaultreadpolicy is not None:
        payload_vendor['DefaultReadPolicy'] = args.defaultreadpolicy

    # Default write policy
    if args.defaultwritepolicy is not None:
        values = args.defaultwritepolicy
        payload_vendor['DefaultWritePolicy'] = values
    # Default cache policy
    if args.defaultcachepolicy is not None:
        values = args.defaultcachepolicy
        payload_vendor['DefaultCachePolicy'] = values
    # Number of logical disk subgroups
    if args.spannumber is not None:
        payload_vendor['SpanNumber'] = args.spannumber

    # Logical disk access policy
    if args.accesspolicy is not None:
        payload_vendor['AccessPolicy'] = args.accesspolicy

    # Member disk cache policy DriveCachePolicy
    if args.drivecachepolicy is not None:
        payload_vendor['DriveCachePolicy'] = args.drivecachepolicy

    # Logical disk initialization mode
    if args.initializationmode is not None:
        values = args.initializationmode
        payload_vendor['InitializationMode'] = values


def full_payload(payload, args):
    """
    #=================================================================
    #   @Method:  Fill the body
    #   @Param:   payload       Body
    #             args       Enter parameters
    #             parser       sub command argparser.
     Export error messages when parameters are incorrect.
    #   @Return:  none
    #   @author:
    #=================================================================
    """
    # Physical disk list
    payload_vendor = payload['Oem'][common_function.COMMON_KEY]
    if args.drives is not None:
        payload_vendor['Drives'] = args.drives

    # Logical disk level
    if args.volumeraidlevel is not None:
        payload_vendor['VolumeRaidLevel'] = args.volumeraidlevel

    # Logical disk capacity
    if args.capacitybytes is not None:
        payload['CapacityBytes'] = args.capacitybytes

    # Logical disk stripe size
    if args.optsizebytes is not None:
        payload['OptimumIOSizeBytes'] = args.optsizebytes

    # CacheFlag
    if args.cachecadeflag is not None:
        payload_vendor['CreateCacheCadeFlag'] = \
            args.cachecadeflag == str(True)

    # Logical disk name
    if args.volumename is not None:
        payload_vendor['VolumeName'] = args.volumename

    full_other_payload(payload, args)


# Query the task status
def get_taskinfo(client, task_uri):
    """
    #=================================================================
    #   @Method:  Fill the body
    #   @Param:   client       client，RedfishClient object
    #             task_uri     Task url
    #   @Return:  none
    #   @author:
    #=================================================================
    """
    get_resp = client.get_resource(task_uri)
    if get_resp is None or get_resp['status_code'] != 200:
        return get_resp

    # Query the progress.
    resp = client.print_task_prog(get_resp)
    if resp is None:
        return None
    get_resp = client.get_resource(task_uri)
    if get_resp is None or get_resp['status_code'] != 200:
        return get_resp

    # View messageId.
    messageid = get_resp['resource']['Messages']['MessageId']
    if messageid == 'iBMC.1.0.VolumeCreationSuccess':
        return get_resp
    check_info = get_resp['resource']['Messages']['Message']
    # Modify: 2017.9.27 When a user creates a RAID level that is not supported
    # by a cache logical disk, the message displayed is optimized.
    messagebefore = "%s%s" % \
                    (check_info[0].lower(), check_info[1:len(check_info)])
    if messagebefore[-1] == '.':
        messageafter = "%s" % (messagebefore[0:len(messagebefore) - 1])
    else:
        messageafter = messagebefore
    # Modify: 2017.9.27 When a user creates a RAID level that is not supported
    # by a cache logical disk, the message displayed is optimized.
    message = messageafter.replace("Oem/%s/" % common_function.COMMON_KEY, "")
    print(PF.format('Failure: ', message))
    sys.exit(144)


def check_error_info(messages):
    """
    #=====================================================================
    #   @Method:  Process creation failure messages.
    #   @Param:   messages, error message
    #   @Return:
    #   @author:
    #=====================================================================
    """
    index = 0
    while index < len(messages):
        check_info = messages[index]['Message']
        messagebefore = "%s%s" % \
                        (check_info[0].lower(), check_info[1:len(check_info)])
        if messagebefore[-1] == '.':
            message = "%s" % (messagebefore[0:len(messagebefore) - 1])
        else:
            message = messagebefore
        message = message.replace("Oem/%s/" % common_function.COMMON_KEY, "")
        if index == 0:
            print(PF.format('Failure: ', message))
        else:
            print(PF.format('         ', message))
        index += 1


def check_parameter(parser, args):
    """
    Function Description:check CLI command
    Parameter:args object:CLI command
    parser object:subcommand ArgumentParser object
    """
    if not args.drives:
        parser.error('the value of -DI parameter is invalid')


def check_capacitybytes(drive_list, capacitybytes):
    if capacitybytes is None or capacitybytes is None:
        return True
    if drive_list and isinstance(drive_list, list) and capacitybytes < 64 * 1024 * 1024 * len(drive_list):
        return False
    return True


def addlogicaldrive(client, args):
    """
    #==========================================================================
    #   @Method:  Create a logical disk processing function.
    #   @Param:   client, RedfishClient object
                  parser, subcommand argparser.
                          Export error messages when parameters are incorrect.
                  args, parameter list
    #   @Return:
    #   @author:
    #==========================================================================
    """
    slotid = client.get_slotid()
    if slotid is None:
        return None

        # Determine whether a storage system exists.
    systems = "/redfish/v1/Systems/" + slotid
    storage = "/Storages/RAIDStorage" + str(args.controllerid)
    resp = client.check_storages(systems, storage, '-I')
    if resp is None:
        return None
    if resp['status_code'] != 200:
        return resp
    if not check_capacitybytes(args.drives, args.capacitybytes):
        print(PF.format('Failure: ', 'The parameter -V capacitybytes'
                        ' size must not be less than 67108864 * the number of hard drives'))
        return None
    # Fill payload. Construct the payload body.
    payload = {'Oem': {common_function.COMMON_KEY: {}}}
    full_payload(payload, args)
    volumes = storage + "/Volumes"
    url = systems + volumes
    create_resp = client.create_resource(url, payload)
    if create_resp is None:
        return None

    if create_resp['status_code'] == 202:
        # Query tasks.
        task_uri = create_resp['resource']['@odata.id']
        create_resp = get_taskinfo(client, task_uri)

    elif create_resp['status_code'] == 400:
        info = create_resp['message']['error']['@Message.ExtendedInfo']
        check_error_info(info)

    elif create_resp['status_code'] == 404:
        print('Failure: the value of -I parameter is invalid')
        sys.exit(UREST_STATUS_CODE_2)

    return create_resp
