use std::ffi::c_void;
use std::ops::{Deref, DerefMut};
use winapi::um::wingdi::DeleteObject;


#[derive(Debug)]
pub struct GdiObject<T>(*mut T);

impl<T> GdiObject<T> {
    pub fn new() -> GdiObject<T> {
        GdiObject(std::ptr::null_mut())
    }

    pub fn as_raw(&mut self) -> *mut T {
        self.0
    }
}

impl<T> Default for GdiObject<T> {
    fn default() -> GdiObject<T> {
        GdiObject::new()
    }
}

impl<T> Deref for GdiObject<T> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &*self.0 }
    }
}

impl<T> DerefMut for GdiObject<T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.0 }
    }
}

impl<T> Drop for GdiObject<T> {
    fn drop(&mut self) {
        unsafe {
            DeleteObject(self.0 as *mut c_void);
        }
    }
}


pub fn gdi_call<TFunction, T>(function: TFunction) -> Result<GdiObject<T>, std::io::Error>
where
    TFunction: FnOnce() -> *mut T,
{
    let pointer = function();

    if !pointer.is_null() {
        Ok(GdiObject(pointer))
    } else {
        Err(std::io::Error::last_os_error())
    }
}