# pylint: disable=too-many-statements,too-many-branches
"""
Common UEFI parsing and representation code.

"""


import array


class UefiMisc():

    # Returns string corresponding to type value in specified charset.
    @classmethod
    def parse_string(cls, value, type_value, charset):
        index = 0
        data = array.array(type_value)
        try:
            while value[index] != 0:

                # TODO: add more ASCII symbols?
                v = value[index]
                if v == 0x0A:  # \n
                    data.append(0x5C)
                    data.append(0x6E)
                elif v == 0x0D:  # \r
                    data.append(0x5C)
                    data.append(0x72)
                elif v == 0x09:  # \t
                    data.append(0x5C)
                    data.append(0x74)
                elif v == 0x22:  # "
                    data.append(0x5C)
                    data.append(0x22)
                elif v == 0x5C:  # \
                    data.append(0x5C)
                    data.append(0x5C)
                else:
                    data.append(v)
                index += 1
        except IndexError:
            pass
        return data.tobytes().decode(charset)

    # Returns a UTF16 string corresponding to a (CHAR16 *) value in EFI.

    @classmethod
    def parse_utf16(cls, value):
        return cls.parse_string(value, 'H', 'utf-16')

    #
    # Returns a UTF8 string corresponding to a (CHAR8 *) value in EFI.
    #
    @classmethod
    def parse_utf8(cls, value):
        return cls.parse_string(value, 'B', 'utf-8')

    #
    # Returns a printable EFI or RETURN status.
    #
    @classmethod
    def parse_status(cls, value, efi):
        suffix = ''
        err = 0
        val = int(value)
        if val & 0x80000000:
            err = val & ~0x80000000
        elif val & 0x8000000000000000:
            err = val & ~0x8000000000000000

        if err != 0:
            # TODO: make this a collection...
            if err == 1:
                suffix = 'LOAD_ERROR'
            elif err == 2:
                suffix = 'INVALID_PARAMETER'
            elif err == 3:
                suffix = 'UNSUPPORTED'
            elif err == 4:
                suffix = 'BAD_BUFFER_SIZE'
            elif err == 5:
                suffix = 'BUFFER_TOO_SMALL'
            elif err == 6:
                suffix = 'NOT_READY'
            elif err == 7:
                suffix = 'DEVICE_ERROR'
            elif err == 8:
                suffix = 'WRITE_PROTECTED'
            elif err == 9:
                suffix = 'OUT_OF_RESOURCES'
            elif err == 10:
                suffix = 'VOLUME_CORRUPTED'
            elif err == 11:
                suffix = 'VOLUME_FULL'
            elif err == 12:
                suffix = 'NO_MEDIA'
            elif err == 13:
                suffix = 'MEDIA_CHANGED'
            elif err == 14:
                suffix = 'NOT_FOUND'
            elif err == 15:
                suffix = 'ACCESS_DENIED'
            elif err == 16:
                suffix = 'NO_RESPONSE'
            elif err == 17:
                suffix = 'NO_MAPPING'
            elif err == 18:
                suffix = 'TIMEOUT'
            elif err == 19:
                suffix = 'NOT_STARTED'
            elif err == 20:
                suffix = 'ALREADY_STARTED'
            elif err == 21:
                suffix = 'ABORTED'
            elif err == 22:
                suffix = 'ICMP_ERROR'
            elif err == 23:
                suffix = 'TFTP_ERROR'
            elif err == 24:
                suffix = 'PROTOCOL_ERROR'
            elif err == 25:
                suffix = 'INCOMPATIBLE_VERSION'
            elif err == 26:
                suffix = 'SECURITY_VIOLATION'
            elif err == 27:
                suffix = 'CRC_ERROR'
            elif err == 28:
                suffix = 'END_OF_MEDIA'
            elif err == 31:
                suffix = 'END_OF_FILE'
            elif err == 32:
                suffix = 'INVALID_LANGUAGE'
            elif err == 33:
                suffix = 'COMPROMISED_DATA'
            elif err == 35:
                suffix = 'HTTP_ERROR'
            elif efi and err == 100:
                suffix = 'NETWORK_UNREACHABLE'
            elif efi and err == 101:
                suffix = 'HOST_UNREACHABLE'
            elif efi and err == 102:
                suffix = 'PROTOCOL_UNREACHABLE'
            elif efi and err == 103:
                suffix = 'PORT_UNREACHABLE'
            elif efi and err == 104:
                suffix = 'CONNECTION_FIN'
            elif efi and err == 105:
                suffix = 'CONNECTION_RESET'
            elif efi and err == 106:
                suffix = 'CONNECTION_REFUSED'
        else:
            if val == 0:
                suffix = 'SUCCESS'
            elif val == 1:
                suffix = 'WARN_UNKNOWN_GLYPH'
            elif val == 2:
                suffix = 'WARN_DELETE_FAILURE'
            elif val == 3:
                suffix = 'WARN_WRITE_FAILURE'
            elif val == 4:
                suffix = 'WARN_BUFFER_TOO_SMALL'
            elif val == 5:
                suffix = 'WARN_STALE_DATA'
            elif val == 6:
                suffix = 'WARN_FILE_SYSTEM'
        return('EFI_' if efi else 'RETURN_') + suffix if suffix != '' else hex(val)

    # Returns a UTF16 string corresponding to a (CHAR16 *) value in EFI.
    @classmethod
    def parse_guid(cls, value):
        guid = f"<{int(value['Data1']):08X}-{int(value['Data2']):04X}-{int(value['Data3']):04X}-{int(value['Data4'][0]):02X}{int(value['Data4'][1]):02X}-{int(value['Data4'][2]):02X}{int(value['Data4'][3]):02X}{int(value['Data4'][4]):02X}{int(value['Data4'][5]):02X}{int(value['Data4'][6]):02X}{int(value['Data4'][7]):02X}>"
        return guid
