from ctypes import *
from enum import IntEnum

DSCL_RESULT = c_int32

DSCL_SUCCESS = 0
DSCL_INTERNAL_ERROR = -1
DSCL_ERROR_NULL_IMAGE = -2
DSCL_NOT_ENOUGH_SPACE_FOR_ENCODED_IMAGE = -3
DSCL_COMPRESSION_FAILED = -4
DSCL_DECOMPRESSION_FAILED = -5
DSCL_DSC_EXE_NOT_FOUND = -6
DSCL_DP_CRC_EXE_NOT_FOUND = -7
DSCL_PB_EXE_NOT_FOUND = -8
DSCL_CFG_NOT_CREATED = -9
DSCL_CFG_NOT_FOUND = -10
DSCL_FAIL_TO_CREATE_TMP_FOLDER = -11
DSCL_FAIL_TO_CREATE_TMP_FILE = -12

RC_BUF_THRESH_SIZE = 14
RC_RANGE_PARAMETERS_SIZE = 30
RC_RANGE_PARAMETERS_COUNT = int(RC_RANGE_PARAMETERS_SIZE / 2)


class CtypesEnum(IntEnum):
    @classmethod
    def from_param(cls, obj):
        return int(obj)


class DSCL_Colorformat(CtypesEnum):
    Colorformat_RGB = 0,
    Colorformat_YCbCr422 = 1,
    Colorformat_YCbCr444 = 2,
    Colorformat_YCbCr420 = 3,
    Colorformat_Simple422 = 4,
    Colorformat_MaxValue = 5


class DSCL_DscVersion(Structure):
    _fields_ = [
        ('major', c_uint8),
        ('minor', c_uint8),
        ]


DSCL_ColorformatStr = ["RGB",
                       "YCbCr 4:2:2",
                       "YCbCr 4:4:4",
                       "YCbCr 4:2:0",
                       "Simple 4:2:2"]

class DSCL_Image(Structure):
    _fields_ = [
        ('DataPtr', POINTER(c_uint8)),
        ('DataSize', c_uint64),
    ]


class DSCL_Compression(Structure):
    _fields_ = [
        ('bitsPerPixel', c_uint32),
        ('bitsPerComponent', c_uint32),
        ('is422', c_bool),
        ('is420', c_bool),
    ]


class DSCL_CRC16(Structure):
    _fields_ = [
        ('eng0', c_uint16),
        ('eng1', c_uint16),
        ('eng2', c_uint16)
    ]


class DSCL_PPS(Structure):
    _fields_ = [
        ('dsc_version_minor', c_uint8, 4),
        ('dsc_version_major', c_uint8, 4),
        ('pps_identifier', c_uint8, 8),
        ('', c_uint8, 8),
        ('linebuf_depth', c_uint8, 4),
        ('bits_per_component', c_uint8, 4),
        ('bits_per_pixel_high', c_uint8, 2),
        ('vbr_enable', c_uint8, 1),
        ('simple_422', c_uint8, 1),
        ('convert_rgb', c_uint8, 1),
        ('block_pred_enable', c_uint8, 1),
        ('', c_uint8, 2),
        ('bits_per_pixel_low', c_uint8, 8),
        ('pic_height_high', c_uint8, 8),
        ('pic_height_low', c_uint8, 8),
        ('pic_width_high', c_uint8, 8),
        ('pic_width_low', c_uint8, 8),
        ('slice_height_high', c_uint8, 8),
        ('slice_height_low', c_uint8, 8),
        ('slice_width_high', c_uint8, 8),
        ('slice_width_low', c_uint8, 8),
        ('chunk_size_high', c_uint8, 8),
        ('chunk_size_low', c_uint8, 8),
        ('initial_xmit_delay_high', c_uint8, 2),
        ('', c_uint8, 6),
        ('initial_xmit_delay_low', c_uint8, 8),
        ('initial_dec_delay_high', c_uint8, 8),
        ('initial_dec_delay_low', c_uint8, 8),
        ('', c_uint8, 8),
        ('initial_scale_value', c_uint8, 6),
        ('', c_uint8, 2),
        ('scale_increment_interval_high', c_uint8, 8),
        ('scale_increment_interval_low', c_uint8, 8),
        ('scale_decrement_interval_high', c_uint8, 4),
        ('', c_uint8, 4),
        ('scale_decrement_interval_low', c_uint8, 8),
        ('', c_uint8, 8),
        ('first_line_bpg_offset', c_uint8, 5),
        ('', c_uint8, 3),
        ('nfl_bpg_offset_high', c_uint8, 8),
        ('nfl_bpg_offset_low', c_uint8, 8),
        ('slice_bpg_offset_high', c_uint8, 8),
        ('slice_bpg_offset_low', c_uint8, 8),
        ('initial_offset_high', c_uint8, 8),
        ('initial_offset_low', c_uint8, 8),
        ('final_offset_high', c_uint8, 8),
        ('final_offset_low', c_uint8, 8),
        ('flatness_min_qp', c_uint8, 5),
        ('', c_uint8, 3),
        ('flatness_min_qp', c_uint8, 5),
        ('', c_uint8, 3),
        ('rc_model_size_high', c_uint8, 8),
        ('rc_model_size_low', c_uint8, 8),
        ('rc_edge_factor', c_uint8, 4),
        ('', c_uint8, 4),
        ('rc_quant_incr_limit0', c_uint8, 5),
        ('', c_uint8, 3),
        ('rc_quant_incr_limit1', c_uint8, 5),
        ('', c_uint8, 3),
        ('rc_tgt_offset_lo', c_uint8, 4),
        ('rc_tgt_offset_hi', c_uint8, 4),
        ('rc_buf_thresh', c_uint8 * RC_BUF_THRESH_SIZE),
        ('rc_range_parameters', c_uint8 * RC_RANGE_PARAMETERS_SIZE),
        ('native_422', c_uint8, 1),
        ('native_420', c_uint8, 1),
        ('', c_uint8, 6),
        ('second_line_bpg_offset', c_uint8, 5),
        ('', c_uint8, 3),
        ('nsl_bpg_offset_high', c_uint8, 8),
        ('nsl_bpg_offset_low', c_uint8, 8),
        ('second_line_offset_adj_high', c_uint8, 8),
        ('second_line_offset_adj_low', c_uint8, 8),
        ('', c_uint8 * 34)
    ]

    def width(self) -> int:
        return (self.pic_width_high << 8) | self.pic_width_low

    def height(self) -> int:
        return (self.pic_height_high << 8) | self.pic_height_low

    def is_yuv(self) -> bool:
        return self.convert_rgb == 0

    def bpp(self) -> int:
        if self.native_422 == 1 or self.native_420 == 1:
            return int((((self.bits_per_pixel_high & 0x3) << 8) | self.bits_per_pixel_low) / 2)
        else:
            return ((self.bits_per_pixel_high & 0x3) << 8) | self.bits_per_pixel_low

    def bpc(self) -> int:
        return self.bits_per_component & 0x0F

    def is_422(self) -> bool:
        return self.native_422 != 0

    def is_420(self) -> bool:
        return self.native_420 != 0

    def is_simple_422(self) -> bool:
        return self.simple_422 != 0

    def v_slice(self) -> int:
        return (self.slice_height_high << 8) | self.slice_height_low

    def h_slice(self) -> int:
        return (self.slice_width_high << 8) | self.slice_width_low

    def buffer_bit_depth(self) -> int:
        return self.linebuf_depth

    def is_block_prediction_enabled(self) -> bool:
        return self.block_pred_enable != 0

    def dsc_version(self) -> tuple:
        return self.dsc_version_major, self.dsc_version_minor


class DSCL_EncoderConfig(Structure):
    _fields_ = [
        # ('log_buffer', c_char * 2048),
    ]


class DSCL_DecoderConfig(Structure):
    _fields_ = [
        ('decodeSimple422to444', c_bool),
    ]
