//! Dialog type window.

use crate::window::{AdvancedOptions, Attributes, Frame};

pub trait Dialog {
    fn attributes(&self) -> Attributes;

    fn frame(&self) -> Frame;

    fn advanced_options(&self) -> AdvancedOptions {
        AdvancedOptions::default()
    }

    fn ui(&self, frame: Frame);
}

#[cfg(windows)]
pub fn create_dialog(dialog: Box<dyn Dialog>) {
    let attributes = dialog.attributes();
    let advanced_options = dialog.advanced_options();
    let frame = dialog.frame();
    use windows_sys::{
        Win32::Foundation::*, Win32::System::LibraryLoader::GetModuleHandleA,
        Win32::UI::WindowsAndMessaging::*,
    };
    extern "system" fn wndproc(
        window: HWND,
        message: u32,
        wparam: WPARAM,
        lparam: LPARAM,
    ) -> LRESULT {
        unsafe {
            match message as u32 {
                WM_DESTROY => {
                    println!("WM_DESTROY");
                    PostQuitMessage(0);
                    0
                }
                _ => DefWindowProcA(window, message, wparam, lparam),
            }
        }
    }

    unsafe {
        let instance = GetModuleHandleA(std::ptr::null_mut());
        debug_assert!(instance != 0);

        let wc = WNDCLASSA {
            hCursor: LoadCursorW(0, IDC_ARROW),
            hInstance: instance,
            lpszClassName: "window".as_ptr(),
            style: CS_HREDRAW | CS_VREDRAW,
            lpfnWndProc: Some(wndproc),
            cbClsExtra: 0,
            cbWndExtra: 0,
            hIcon: 0,
            hbrBackground: 5,
            lpszMenuName: std::ptr::null_mut(),
        };

        let _atom = RegisterClassA(&wc);

        let win = CreateWindowExA(
            0,
            "window".as_ptr(),
            attributes.title.as_ptr(),
            WS_SYSMENU,
            attributes.x,
            attributes.y,
            attributes.width,
            attributes.height,
            frame.get_window(),
            0,
            instance,
            std::ptr::null_mut(),
        );

        let dialog_frame = Frame::new(win);
        dialog.ui(dialog_frame);

        let mut message = std::mem::zeroed();

        while GetMessageA(&mut message, 0, 0, 0) != 0 {
            DispatchMessageA(&message);
        }
    }
}

#[cfg(unix)]
pub fn create_dialog(dialog: Box<dyn Dialog>) {
    let attributes = dialog.attributes();
    let frame = dialog.frame();
    use gtk::prelude::*;

    let app = gtk::Application::new(Option::from(attributes.app_id.as_str()), Default::default());

    let window = gtk::ApplicationWindow::new(&app);

    window.set_title(attributes.title.as_str());
    window.set_default_size(attributes.width, attributes.height);
    window.set_window_position(gtk::WindowPosition::Center);
    window.set_type_hint(gtk::gdk::WindowTypeHint::Utility);

    let dialog_frame = Frame::new(window.clone(), window.application());

    dialog.ui(dialog_frame);

    window.show_all();

    app.run();
}
