
import struct
from enum import Enum


class DataType(Enum):
    UINT16T = 0
    INT16T = 1
    UINT32T = 2
    INT32T = 3
    UINT64T = 4
    INT64T = 5
    UINT128T = 6
    INT128T = 7


class Utility:
    @staticmethod
    def uint16_to_uint32(registers):
        tmp = struct.pack("HH", registers[0], registers[1])
        return struct.unpack('L', tmp)[0]

    @staticmethod
    def uint16_to_int32(registers):
        tmp = struct.pack("HH", registers[0], registers[1])
        return struct.unpack('l', tmp)[0]

    @staticmethod
    def uint16_to_uint64(registers):
        tmp = struct.pack("HHHH", registers[0], registers[1], registers[2], registers[3])
        return struct.unpack('Q', tmp)[0]

    @staticmethod
    def uint16_to_int64(registers):
        tmp = struct.pack("HHHH", registers[0], registers[1], registers[2], registers[3])
        return struct.unpack('q', tmp)[0]

    @staticmethod
    def uint16_to_uint128(registers):
        tmp = struct.pack("HHHHHHHH", registers[0], registers[1], registers[2], registers[3], registers[4], registers[5], registers[6], registers[7])
        return struct.unpack('Q', tmp)[0]

    @staticmethod
    def uint16_to_int128(registers):
        tmp = struct.pack("HHHHHHHH", registers[0], registers[1], registers[2], registers[3], registers[4], registers[5], registers[6], registers[7])
        return struct.unpack('q', tmp)[0]

    @staticmethod
    def uint16_to_xx(data_type, registers):
        if data_type == DataType.UINT16T or data_type == DataType.INT16T:
            return registers[0]
        elif data_type == DataType.UINT32T:
            return Utility.uint16_to_uint32(registers)
        elif data_type == DataType.INT32T:
            return Utility.uint16_to_int32(registers)
        elif data_type == DataType.UINT64T:
            return Utility.uint16_to_uint64(registers)
        elif data_type == DataType.INT64T:
            return Utility.uint16_to_int64(registers)
        elif data_type == DataType.UINT128T:
            return Utility.uint16_to_uint128(registers)
        elif data_type == DataType.INT128T:
            return Utility.uint16_to_int128(registers)

    @staticmethod
    def u16_to_hex(u16_val):
        return format(u16_val, "04x")

    @staticmethod
    def u32_to_hex(u32_val):
        return format(u32_val, "08x")

    @staticmethod
    def u64_to_hex(u64_val):
        return format(u64_val, "08x")

    @staticmethod
    def show_val(message, value):
        print('{} = {}'.format(message, value))

    @staticmethod
    def show_u16_hex(message, u16_value):
        print('{} = {}'.format(message, "0x" + Utility.u16_to_hex(u16_value)))

    @staticmethod
    def show_u32_hex(message, u32_value):
        print('{} = {}'.format(message, "0x" + Utility.u32_to_hex(u32_value)))

    @staticmethod
    def show_u64_hex(message, u64_value):
        print('{} = {}'.format(message, "0x" + Utility.u64_to_hex(u64_value)))

    @staticmethod
    def show_u64(message, u64_value):
        print('{} = {}'.format(message, u64_value))

    @staticmethod
    def get_bit(val, bit_index):
        return (val >> bit_index) & 1

