use libc::{c_char, c_int, c_void};

use crate::pyport::Py_ssize_t;
use crate::object::PyObject;

#[repr(C)]
#[derive(Copy)]
pub struct Py_buffer {
    pub buf: *mut c_void,
    pub obj: *mut PyObject,
    pub len: Py_ssize_t,
    pub itemsize: Py_ssize_t,
    pub readonly: c_int,
    pub ndim: c_int,
    pub format: *mut c_char,
    pub shape: *mut Py_ssize_t,
    pub strides: *mut Py_ssize_t,
    pub suboffsets: *mut Py_ssize_t,
    pub internal: *mut c_void,
}
impl Clone for Py_buffer {
    #[inline]
    fn clone(&self) -> Self {
        *self
    }
}
impl Default for Py_buffer {
    #[inline]
    fn default() -> Self {
        unsafe { core::mem::zeroed() }
    }
}

#[cfg_attr(windows, link(name = "pythonXY"))]
extern "C" {
    #[cfg(Py_3_9)]
    pub fn PyObject_CheckBuffer(obj: *mut PyObject) -> c_int;
    pub fn PyObject_GetBuffer(obj: *mut PyObject, view: *mut Py_buffer, flags: c_int) -> c_int;
    pub fn PyBuffer_GetPointer(view: *mut Py_buffer, indices: *mut Py_ssize_t) -> *mut c_void;
    #[cfg(any(Py_3_11, all(not(Py_LIMITED_API), Py_3_9)))]
    pub fn PyBuffer_SizeFromFormat(format: *const c_char) -> Py_ssize_t;
    pub fn PyBuffer_ToContiguous(
        buf: *mut c_void,
        view: *mut Py_buffer,
        len: Py_ssize_t,
        order: c_char,
    ) -> c_int;
    pub fn PyBuffer_FromContiguous(
        view: *mut Py_buffer,
        buf: *mut c_void,
        len: Py_ssize_t,
        order: c_char,
    ) -> c_int;
    pub fn PyObject_CopyData(dest: *mut PyObject, src: *mut PyObject) -> c_int;
    pub fn PyBuffer_IsContiguous(view: *const Py_buffer, fort: c_char) -> c_int;
    pub fn PyBuffer_FillContiguousStrides(
        ndims: c_int,
        shape: *mut Py_ssize_t,
        strides: *mut Py_ssize_t,
        itemsize: c_int,
        fort: c_char,
    ) -> ();
    pub fn PyBuffer_FillInfo(
        view: *mut Py_buffer,
        o: *mut PyObject,
        buf: *mut c_void,
        len: Py_ssize_t,
        readonly: c_int,
        flags: c_int,
    ) -> c_int;
    pub fn PyBuffer_Release(view: *mut Py_buffer) -> ();
}

 /// Maximum number of dimensions
 pub const PyBUF_MAX_NDIM: c_int = 64;

 /* Flags for getting buffers */
 pub const PyBUF_SIMPLE: c_int = 0;
 pub const PyBUF_WRITABLE: c_int = 0x0001;
 /*  we used to include an E, backwards compatible alias  */
#[cfg(not(Py_LIMITED_API))]
 pub const PyBUF_WRITEABLE: c_int = PyBUF_WRITABLE;
 pub const PyBUF_FORMAT: c_int = 0x0004;
 pub const PyBUF_ND: c_int = 0x0008;
 pub const PyBUF_STRIDES: c_int = (0x0010 | PyBUF_ND);
 pub const PyBUF_C_CONTIGUOUS: c_int = (0x0020 | PyBUF_STRIDES);
 pub const PyBUF_F_CONTIGUOUS: c_int = (0x0040 | PyBUF_STRIDES);
 pub const PyBUF_ANY_CONTIGUOUS: c_int = (0x0080 | PyBUF_STRIDES);
 pub const PyBUF_INDIRECT: c_int = (0x0100 | PyBUF_STRIDES);

 pub const PyBUF_CONTIG: c_int = (PyBUF_ND | PyBUF_WRITABLE);
 pub const PyBUF_CONTIG_RO: c_int = (PyBUF_ND);

 pub const PyBUF_STRIDED: c_int = (PyBUF_STRIDES | PyBUF_WRITABLE);
 pub const PyBUF_STRIDED_RO: c_int = (PyBUF_STRIDES);

 pub const PyBUF_RECORDS: c_int = (PyBUF_STRIDES | PyBUF_WRITABLE | PyBUF_FORMAT);
 pub const PyBUF_RECORDS_RO: c_int = (PyBUF_STRIDES | PyBUF_FORMAT);

 pub const PyBUF_FULL: c_int = (PyBUF_INDIRECT | PyBUF_WRITABLE | PyBUF_FORMAT);
 pub const PyBUF_FULL_RO: c_int = (PyBUF_INDIRECT | PyBUF_FORMAT);

 pub const PyBUF_READ: c_int = 0x100;
 pub const PyBUF_WRITE: c_int = 0x200;