//! Displays an OS-specific message dialog.
//! Display OS-specific dialogs in Windows environment, and GTK dialogs in Linux environment.

use crate::window::Frame;
use std::iter::once;
use crate::natives_and_messaging::*;

#[cfg(windows)]
pub struct MessageBox<'a> {
    /// Message to be displayed
    pub title: &'a str,
    /// Message to be displayed
    pub message: &'a str,
    /// Dialog style
    pub style: windows_sys::Win32::UI::WindowsAndMessaging::MESSAGEBOX_STYLE,
    /// Dialog button style
    pub button_style: windows_sys::Win32::UI::WindowsAndMessaging::MESSAGEBOX_STYLE,
}

#[cfg(unix)]
pub struct MessageBox<'a> {
    /// Message to be displayed
    pub title: &'a str,
    /// Message to be displayed
    pub message: &'a str,
    /// Dialog style
    pub style: gtk::MessageType,
    /// Dialog button style
    pub button_style: gtk::ButtonsType,
}

#[cfg(windows)]
impl<'a> MessageBox<'a> {
    /// Create a new MessageBox.
    pub fn new(
        title: &'a str,
        message: &'a str,
        style: MessageBoxStyle,
        button_style: ButtonStyle,
    ) -> Self {
        Self {
            title,
            message,
            style,
            button_style,
        }
    }

    /// Display the dialog
    /// In Windows environment, returns windows-sys::Win32::UI::WindowsAndMessaging::MESSAGEBOX_RESULT
    /// # Examples
    /// ```
    /// use nxui::messagebox::MessageBox;
    /// use nxui::natives_and_messaging::{DIALOGSTYLE_INFORMATION,BUTTONSTYLE_OK};
    ///
    /// fn main() {
    ///     MessageBox::new("Hello NXUI!".to_string(),"This is a test".to_string(),DIALOGSTYLE_INFORMATION,BUTTONSTYLE_OK).show();
    /// }
    /// ```
    pub fn show(
        &self,
        frame: Frame,
    ) -> windows_sys::Win32::UI::WindowsAndMessaging::MESSAGEBOX_RESULT {
        unsafe {
            use windows_sys::{
                Win32::Foundation::*, Win32::System::Threading::*,
                Win32::UI::WindowsAndMessaging::*,
            };
            let event = CreateEventW(std::ptr::null(), 1, 0, std::ptr::null());
            SetEvent(event);
            WaitForSingleObject(event, 0);
            CloseHandle(event);
            info!("HANDLE: {}", frame.get_window());

            let result = MessageBoxW(
                frame.get_window(),
                self.message
                    .encode_utf16()
                    .chain(once(0))
                    .collect::<Vec<u16>>()
                    .as_mut_ptr(),
                self.title
                    .encode_utf16()
                    .chain(once(0))
                    .collect::<Vec<u16>>()
                    .as_mut_ptr(),
                self.style | self.button_style,
            );
            info!("The Result of MessageBox is {}", result);
            result
        }
    }
}

#[cfg(unix)]
impl<'a> MessageBox<'a> {
    /// Create a new MessageBox.
    pub fn new(
        title: &'a str,
        message: &'a str,
        style: MessageBoxStyle,
        button_style: ButtonStyle,
    ) -> Self {
        Self {
            title,
            message,
            style,
            button_style,
        }
    }

    /// Display the dialog
    /// In Windows environment, returns windows-sys::Win32::UI::WindowsAndMessaging::MESSAGEBOX_RESULT
    /// # Examples
    /// ```
    /// use nxui::messagebox::MessageBox;
    /// use nxui::natives_and_messaging::{DIALOGSTYLE_INFORMATION,BUTTONSTYLE_OK};
    ///
    /// fn main() {
    ///     MessageBox::new("Hello NXUI!".to_string(),"This is a test".to_string(),DIALOGSTYLE_INFORMATION,BUTTONSTYLE_OK).show();
    /// }
    /// ```
    pub fn show(&self, frame: Frame) -> gtk::ResponseType {
        use gtk::prelude::*;
        gtk::init().expect("Failed to initialize gtk.");
        let window = frame.get_window();

        let dialog = gtk::MessageDialog::new(
            Some(&window),
            gtk::DialogFlags::empty(),
            self.style,
            self.button_style,
            self.message,
        );
        let result = dialog.run();
        unsafe {
            dialog.destroy();
        }
        result
    }
}
