//! Minimal `OpenJPEG` 2.5 public ABI used by this crate.
//!
//! These declarations follow `openjpeg.h` from `OpenJPEG` 2.5.4. Keeping the
//! bindings here avoids requiring libclang merely to enable the codec.

use std::ffi::{c_char, c_int, c_uint, c_void};

pub type OPJ_BOOL = c_int;
pub type OPJ_CHAR = c_char;
pub type OPJ_UINT16 = u16;
pub type OPJ_INT32 = i32;
pub type OPJ_UINT32 = u32;
pub type OPJ_UINT64 = u64;
pub type OPJ_OFF_T = i64;
pub type OPJ_SIZE_T = usize;

pub type OPJ_RSIZ_CAPABILITIES = u32;
pub type OPJ_CINEMA_MODE = u32;
pub type OPJ_PROG_ORDER = i32;

#[repr(transparent)]
#[derive(Debug, Copy, Clone)]
pub struct OPJ_COLOR_SPACE(i32);

impl OPJ_COLOR_SPACE {
    pub const OPJ_CLRSPC_SRGB: Self = Self(1);
    pub const OPJ_CLRSPC_GRAY: Self = Self(2);
}

#[repr(transparent)]
#[derive(Debug, Copy, Clone)]
pub struct OPJ_CODEC_FORMAT(i32);

impl OPJ_CODEC_FORMAT {
    pub const OPJ_CODEC_J2K: Self = Self(0);
    pub const OPJ_CODEC_JP2: Self = Self(2);
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct opj_poc_t {
    pub resno0: OPJ_UINT32,
    pub compno0: OPJ_UINT32,
    pub layno1: OPJ_UINT32,
    pub resno1: OPJ_UINT32,
    pub compno1: OPJ_UINT32,
    pub layno0: OPJ_UINT32,
    pub precno0: OPJ_UINT32,
    pub precno1: OPJ_UINT32,
    pub prg1: OPJ_PROG_ORDER,
    pub prg: OPJ_PROG_ORDER,
    pub progorder: [OPJ_CHAR; 5],
    pub tile: OPJ_UINT32,
    pub tx0: OPJ_INT32,
    pub tx1: OPJ_INT32,
    pub ty0: OPJ_INT32,
    pub ty1: OPJ_INT32,
    pub layS: OPJ_UINT32,
    pub resS: OPJ_UINT32,
    pub compS: OPJ_UINT32,
    pub prcS: OPJ_UINT32,
    pub layE: OPJ_UINT32,
    pub resE: OPJ_UINT32,
    pub compE: OPJ_UINT32,
    pub prcE: OPJ_UINT32,
    pub txS: OPJ_UINT32,
    pub txE: OPJ_UINT32,
    pub tyS: OPJ_UINT32,
    pub tyE: OPJ_UINT32,
    pub dx: OPJ_UINT32,
    pub dy: OPJ_UINT32,
    pub lay_t: OPJ_UINT32,
    pub res_t: OPJ_UINT32,
    pub comp_t: OPJ_UINT32,
    pub prc_t: OPJ_UINT32,
    pub tx0_t: OPJ_UINT32,
    pub ty0_t: OPJ_UINT32,
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct opj_cparameters_t {
    pub tile_size_on: OPJ_BOOL,
    pub cp_tx0: c_int,
    pub cp_ty0: c_int,
    pub cp_tdx: c_int,
    pub cp_tdy: c_int,
    pub cp_disto_alloc: c_int,
    pub cp_fixed_alloc: c_int,
    pub cp_fixed_quality: c_int,
    pub cp_matrice: *mut c_int,
    pub cp_comment: *mut c_char,
    pub csty: c_int,
    pub prog_order: OPJ_PROG_ORDER,
    pub POC: [opj_poc_t; 32],
    pub numpocs: OPJ_UINT32,
    pub tcp_numlayers: c_int,
    pub tcp_rates: [f32; 100],
    pub tcp_distoratio: [f32; 100],
    pub numresolution: c_int,
    pub cblockw_init: c_int,
    pub cblockh_init: c_int,
    pub mode: c_int,
    pub irreversible: c_int,
    pub roi_compno: c_int,
    pub roi_shift: c_int,
    pub res_spec: c_int,
    pub prcw_init: [c_int; 33],
    pub prch_init: [c_int; 33],
    pub infile: [c_char; 4096],
    pub outfile: [c_char; 4096],
    pub index_on: c_int,
    pub index: [c_char; 4096],
    pub image_offset_x0: c_int,
    pub image_offset_y0: c_int,
    pub subsampling_dx: c_int,
    pub subsampling_dy: c_int,
    pub decod_format: c_int,
    pub cod_format: c_int,
    pub jpwl_epc_on: OPJ_BOOL,
    pub jpwl_hprot_MH: c_int,
    pub jpwl_hprot_TPH_tileno: [c_int; 16],
    pub jpwl_hprot_TPH: [c_int; 16],
    pub jpwl_pprot_tileno: [c_int; 16],
    pub jpwl_pprot_packno: [c_int; 16],
    pub jpwl_pprot: [c_int; 16],
    pub jpwl_sens_size: c_int,
    pub jpwl_sens_addr: c_int,
    pub jpwl_sens_range: c_int,
    pub jpwl_sens_MH: c_int,
    pub jpwl_sens_TPH_tileno: [c_int; 16],
    pub jpwl_sens_TPH: [c_int; 16],
    pub cp_cinema: OPJ_CINEMA_MODE,
    pub max_comp_size: c_int,
    pub cp_rsiz: OPJ_RSIZ_CAPABILITIES,
    pub tp_on: c_char,
    pub tp_flag: c_char,
    pub tcp_mct: c_char,
    pub jpip_on: OPJ_BOOL,
    pub mct_data: *mut c_void,
    pub max_cs_size: c_int,
    pub rsiz: OPJ_UINT16,
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct opj_dparameters_t {
    pub cp_reduce: OPJ_UINT32,
    pub cp_layer: OPJ_UINT32,
    pub infile: [c_char; 4096],
    pub outfile: [c_char; 4096],
    pub decod_format: c_int,
    pub cod_format: c_int,
    pub DA_x0: OPJ_UINT32,
    pub DA_x1: OPJ_UINT32,
    pub DA_y0: OPJ_UINT32,
    pub DA_y1: OPJ_UINT32,
    pub m_verbose: OPJ_BOOL,
    pub tile_index: OPJ_UINT32,
    pub nb_tile_to_decode: OPJ_UINT32,
    pub jpwl_correct: OPJ_BOOL,
    pub jpwl_exp_comps: c_int,
    pub jpwl_max_tiles: c_int,
    pub flags: c_uint,
}

pub type opj_codec_t = *mut c_void;
pub type opj_stream_t = *mut c_void;

pub type opj_stream_read_fn =
    Option<unsafe extern "C" fn(*mut c_void, OPJ_SIZE_T, *mut c_void) -> OPJ_SIZE_T>;
pub type opj_stream_write_fn =
    Option<unsafe extern "C" fn(*mut c_void, OPJ_SIZE_T, *mut c_void) -> OPJ_SIZE_T>;
pub type opj_stream_skip_fn = Option<unsafe extern "C" fn(OPJ_OFF_T, *mut c_void) -> OPJ_OFF_T>;
pub type opj_stream_seek_fn = Option<unsafe extern "C" fn(OPJ_OFF_T, *mut c_void) -> OPJ_BOOL>;
pub type opj_stream_free_user_data_fn = Option<unsafe extern "C" fn(*mut c_void)>;

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct opj_image_comp_t {
    pub dx: OPJ_UINT32,
    pub dy: OPJ_UINT32,
    pub w: OPJ_UINT32,
    pub h: OPJ_UINT32,
    pub x0: OPJ_UINT32,
    pub y0: OPJ_UINT32,
    pub prec: OPJ_UINT32,
    pub bpp: OPJ_UINT32,
    pub sgnd: OPJ_UINT32,
    pub resno_decoded: OPJ_UINT32,
    pub factor: OPJ_UINT32,
    pub data: *mut OPJ_INT32,
    pub alpha: OPJ_UINT16,
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct opj_image_t {
    pub x0: OPJ_UINT32,
    pub y0: OPJ_UINT32,
    pub x1: OPJ_UINT32,
    pub y1: OPJ_UINT32,
    pub numcomps: OPJ_UINT32,
    pub color_space: OPJ_COLOR_SPACE,
    pub comps: *mut opj_image_comp_t,
    pub icc_profile_buf: *mut u8,
    pub icc_profile_len: OPJ_UINT32,
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct opj_image_cmptparm_t {
    pub dx: OPJ_UINT32,
    pub dy: OPJ_UINT32,
    pub w: OPJ_UINT32,
    pub h: OPJ_UINT32,
    pub x0: OPJ_UINT32,
    pub y0: OPJ_UINT32,
    pub prec: OPJ_UINT32,
    pub bpp: OPJ_UINT32,
    pub sgnd: OPJ_UINT32,
}

unsafe extern "C" {
    pub fn opj_version() -> *const c_char;
    pub fn opj_stream_default_create(is_input: OPJ_BOOL) -> *mut opj_stream_t;
    pub fn opj_stream_destroy(stream: *mut opj_stream_t);
    pub fn opj_stream_set_read_function(stream: *mut opj_stream_t, function: opj_stream_read_fn);
    pub fn opj_stream_set_write_function(stream: *mut opj_stream_t, function: opj_stream_write_fn);
    pub fn opj_stream_set_skip_function(stream: *mut opj_stream_t, function: opj_stream_skip_fn);
    pub fn opj_stream_set_seek_function(stream: *mut opj_stream_t, function: opj_stream_seek_fn);
    pub fn opj_stream_set_user_data(
        stream: *mut opj_stream_t,
        data: *mut c_void,
        free_function: opj_stream_free_user_data_fn,
    );
    pub fn opj_stream_set_user_data_length(stream: *mut opj_stream_t, length: OPJ_UINT64);

    pub fn opj_create_decompress(format: OPJ_CODEC_FORMAT) -> *mut opj_codec_t;
    pub fn opj_create_compress(format: OPJ_CODEC_FORMAT) -> *mut opj_codec_t;
    pub fn opj_destroy_codec(codec: *mut opj_codec_t);
    pub fn opj_set_default_decoder_parameters(parameters: *mut opj_dparameters_t);
    pub fn opj_setup_decoder(
        codec: *mut opj_codec_t,
        parameters: *mut opj_dparameters_t,
    ) -> OPJ_BOOL;
    pub fn opj_decoder_set_strict_mode(codec: *mut opj_codec_t, strict: OPJ_BOOL) -> OPJ_BOOL;
    pub fn opj_read_header(
        stream: *mut opj_stream_t,
        codec: *mut opj_codec_t,
        image: *mut *mut opj_image_t,
    ) -> OPJ_BOOL;
    pub fn opj_decode(
        codec: *mut opj_codec_t,
        stream: *mut opj_stream_t,
        image: *mut opj_image_t,
    ) -> OPJ_BOOL;
    pub fn opj_end_decompress(codec: *mut opj_codec_t, stream: *mut opj_stream_t) -> OPJ_BOOL;

    pub fn opj_image_create(
        component_count: OPJ_UINT32,
        component_parameters: *mut opj_image_cmptparm_t,
        color_space: OPJ_COLOR_SPACE,
    ) -> *mut opj_image_t;
    pub fn opj_image_destroy(image: *mut opj_image_t);
    pub fn opj_set_default_encoder_parameters(parameters: *mut opj_cparameters_t);
    pub fn opj_setup_encoder(
        codec: *mut opj_codec_t,
        parameters: *mut opj_cparameters_t,
        image: *mut opj_image_t,
    ) -> OPJ_BOOL;
    pub fn opj_start_compress(
        codec: *mut opj_codec_t,
        image: *mut opj_image_t,
        stream: *mut opj_stream_t,
    ) -> OPJ_BOOL;
    pub fn opj_encode(codec: *mut opj_codec_t, stream: *mut opj_stream_t) -> OPJ_BOOL;
    pub fn opj_end_compress(codec: *mut opj_codec_t, stream: *mut opj_stream_t) -> OPJ_BOOL;
}
