/// ## set and get clipboard text
///```rust
///fn main()->doe::DynError<()> {
///    use doe::clipboard::get_clipboard;
///    use doe::clipboard::set_clipboard;
///    set_clipboard("rust").unwrap();
///    let clip = get_clipboard().unwrap();
///    assert_eq!("rust",clip);
///    Ok(())
///}
/// ```
#[allow(warnings)]
#[cfg(feature = "clip")]
pub mod clipboard {
    use clipboard::ClipboardContext;
    use clipboard::ClipboardProvider;
    use std::error::Error;

    pub fn set_clipboard(text: impl ToString) -> Result<(), Box<dyn Error>> {
        let mut ctx: ClipboardContext = ClipboardProvider::new()?;
        ctx.set_contents(text.to_string())?;
        Ok(())
    }

    pub fn get_clipboard() -> Result<String, Box<dyn Error>> {
        let mut ctx: ClipboardContext = ClipboardProvider::new()?;
        let res = ctx.get_contents()?;
        Ok(res)
    }

    #[cfg(target_os = "windows")]
    pub fn set_clipboard_rawdata<T: AsRef<[u8]>>(data: T) -> Result<(), Box<dyn Error>> {
        Ok(())
    }
    #[cfg(target_os = "macos")]
    pub mod macos {
        use {
            cocoa::{
                appkit::{NSImage, NSPasteboard, NSSound},
                base::nil,
                foundation::{NSArray, NSAutoreleasePool, NSData, NSDictionary, NSString},
            },
            objc::{class, msg_send, runtime::Object, sel, sel_impl},
            std::error::Error,
        };

        pub(crate) trait IntoExpected<T> {
            fn into_expected(self) -> T;
        }

        impl IntoExpected<i8> for bool {
            fn into_expected(self) -> i8 {
                if self {
                    1
                } else {
                    0
                }
            }
        }

        impl IntoExpected<bool> for i8 {
            fn into_expected(self) -> bool {
                self > 0
            }
        }

        impl IntoExpected<i8> for i8 {
            fn into_expected(self) -> i8 {
                self
            }
        }

        impl IntoExpected<bool> for bool {
            fn into_expected(self) -> bool {
                self
            }
        }

        pub type Id = *mut Object;
        #[derive(Debug)]
        pub enum Pasteboard {
            String,
            Image,
            Sound,
        }
        impl Pasteboard {
            pub unsafe fn copy(&self, path: &str) {
                let pool = NSAutoreleasePool::new(nil);

                let path = NSString::alloc(pool).init_str(path);

                let data = NSData::dataWithContentsOfFile_(pool, path);

                let object = match self {
                    Pasteboard::String => {
                        let string: Id =
                            msg_send![NSString::alloc(pool), initWithData:data encoding:4];
                        string
                    }
                    Pasteboard::Image => NSImage::initWithData_(NSImage::alloc(pool), data),
                    Pasteboard::Sound => {
                        let alloc: Id = msg_send![class!(NSSound), alloc];
                        NSSound::initWithData_(alloc, data)
                    }
                };

                if object != nil {
                    let pasteboard = NSPasteboard::generalPasteboard(pool);
                    pasteboard.clearContents();
                    pasteboard.writeObjects(NSArray::arrayWithObject(pool, object));
                }
            }

            pub unsafe fn paste(&self, path: &str) {
                let pool = NSAutoreleasePool::new(nil);

                let path = NSString::alloc(pool).init_str(path);

                let class = match self {
                    Pasteboard::String => class!(NSString),
                    Pasteboard::Image => class!(NSImage),
                    Pasteboard::Sound => class!(NSSound),
                };

                let class_array = msg_send![class!(NSArray), arrayWithObject: class];
                let options = NSDictionary::dictionary(pool);

                let pasteboard = NSPasteboard::generalPasteboard(pool);

                let ok = pasteboard.canReadObjectForClasses_options(class_array, options);

                if ok.into_expected() {
                    let objects_to_paste =
                        pasteboard.readObjectsForClasses_options(class_array, options);
                    let object = objects_to_paste.objectAtIndex(0);

                    NSData::writeToFile_atomically_(object, path, ok.into_expected());
                }
            }
        }
        ///set_clipboard_image
        ///```ignore
        /// use doe::clipboard::set_clipboard_image;
        /// set_clipboard_image("/Users/ryanandrew/Downloads/demo.png").unwrap();
        /// ````
        pub fn set_clipboard_image(image_path: &str) -> Result<(), Box<dyn Error>> {
            unsafe {
                Pasteboard::Image.copy(image_path);
            }
            Ok(())
        }
        ///set_clipboard_sound
        ///```ignore
        /// use doe::clipboard::set_clipboard_image;
        /// set_clipboard_image("/Users/ryanandrew/Downloads/demo.mp3").unwrap();
        /// ````
        pub fn set_clipboard_sound(sound_path: &str) -> Result<(), Box<dyn Error>> {
            unsafe {
                Pasteboard::Sound.copy(sound_path);
            }
            Ok(())
        }
        ///set_clipboard_string
        ///```ignore
        /// use doe::clipboard::set_clipboard_image;
        /// set_clipboard_image("/Users/ryanandrew/Downloads/demo.txt").unwrap();
        /// ````
        pub fn set_clipboard_string(string_file_path: &str) -> Result<(), Box<dyn Error>> {
            unsafe {
                Pasteboard::String.copy(string_file_path);
            }
            Ok(())
        }

        pub fn paste_clipboard_image(image_path: &str) -> Result<(), Box<dyn Error>> {
            unsafe {
                Pasteboard::Image.paste(image_path);
            }
            Ok(())
        }
        pub fn paste_clipboard_sound(sound_path: &str) -> Result<(), Box<dyn Error>> {
            unsafe {
                Pasteboard::Sound.paste(sound_path);
            }
            Ok(())
        }
        pub fn paste_clipboard_string(string_file_path: &str) -> Result<(), Box<dyn Error>> {
            unsafe {
                Pasteboard::String.paste(string_file_path);
            }
            Ok(())
        }
    }
    #[cfg(target_os = "macos")]
    pub use macos::*;

    #[cfg(target_os = "linux")]
    pub fn set_clipboard_rawdata<T: AsRef<[u8]>>(data: T) -> Result<(), Box<dyn Error>> {

        Ok(())
    }
}
#[cfg(feature = "clip")]
pub use clipboard::*;
