//! Utilities for working with egui and winit together.

/// Check if egui can print a character.
pub fn is_egui_printable(chr: char) -> bool {
    let is_in_private_use_area = ('\u{e000}'..='\u{f8ff}').contains(&chr)
        || ('\u{f0000}'..='\u{ffffd}').contains(&chr)
        || ('\u{100000}'..='\u{10fffd}').contains(&chr);

    !is_in_private_use_area && !chr.is_ascii_control()
}

pub trait PlatformUtilExt {}
impl PlatformUtilExt for crate::Platform {}

/// Translating types between egui and winit.
///
/// **e2w**: egui => winit  
/// **w2e**: winit => egui
pub mod translate {
    /// Translate keycode from winit to egui.
    pub fn key_w2e(w: winit::event::VirtualKeyCode) -> Option<egui::Key> {
        use egui::Key as E;
        use winit::event::VirtualKeyCode as W;
        Some(match w {
            W::Down => E::ArrowDown,
            W::Left => E::ArrowLeft,
            W::Right => E::ArrowRight,
            W::Up => E::ArrowUp,

            W::Escape => E::Escape,
            W::Tab => E::Tab,
            W::Back => E::Backspace,
            W::Return => E::Enter,
            W::Space => E::Insert,
            W::Delete => E::Delete,
            W::Home => E::Home,
            W::End => E::End,
            W::PageUp => E::PageUp,
            W::PageDown => E::PageDown,

            W::Key1 | W::Numpad1 => E::Num1,
            W::Key2 | W::Numpad2 => E::Num2,
            W::Key3 | W::Numpad3 => E::Num3,
            W::Key4 | W::Numpad4 => E::Num4,
            W::Key5 | W::Numpad5 => E::Num5,
            W::Key6 | W::Numpad6 => E::Num6,
            W::Key7 | W::Numpad7 => E::Num7,
            W::Key8 | W::Numpad8 => E::Num8,
            W::Key9 | W::Numpad9 => E::Num9,
            W::Key0 | W::Numpad0 => E::Num0,

            W::A => E::A,
            W::B => E::B,
            W::C => E::C,
            W::D => E::D,
            W::E => E::E,
            W::F => E::F,
            W::G => E::G,
            W::H => E::H,
            W::I => E::I,
            W::J => E::J,
            W::K => E::K,
            W::L => E::L,
            W::M => E::M,
            W::N => E::N,
            W::O => E::O,
            W::P => E::P,
            W::Q => E::Q,
            W::R => E::R,
            W::S => E::S,
            W::T => E::T,
            W::U => E::U,
            W::V => E::V,
            W::W => E::W,
            W::X => E::X,
            W::Y => E::Y,
            W::Z => E::Z,

            _ => {
                return None;
            }
        })
    }

    /// Translate modifier keys from winit to egui.
    pub fn modifiers_w2e(w: winit::event::ModifiersState) -> egui::Modifiers {
        egui::Modifiers {
            alt: w.alt(),
            ctrl: w.ctrl(),
            shift: w.shift(),
            mac_cmd: if cfg!(target_os = "macos") {
                w.logo()
            } else {
                false
            },
            command: if cfg!(target_os = "macos") {
                w.logo()
            } else {
                w.ctrl()
            },
        }
    }

    /// Translate mouse button from winit to egui.
    pub fn mouse_button_w2e(w: winit::event::MouseButton) -> Option<egui::PointerButton> {
        use egui::PointerButton as E;
        use winit::event::MouseButton as W;
        Some(match w {
            W::Left => E::Primary,
            W::Right => E::Secondary,
            W::Middle => E::Middle,
            W::Other(_) => {
                return None;
            }
        })
    }

    /// Translate cursor icon from egui to winit.
    pub fn cursor_icon_e2w(e: egui::CursorIcon) -> winit::window::CursorIcon {
        use egui::CursorIcon as E;
        use winit::window::CursorIcon as W;
        match e {
            E::Default => W::Default,
            E::PointingHand => W::Hand,
            E::ResizeHorizontal => W::ColResize,
            E::ResizeNeSw => W::NeswResize,
            E::ResizeNwSe => W::NwseResize,
            E::ResizeVertical => W::RowResize,
            E::Text => W::Text,
            E::Grab => W::Grab,
            E::Grabbing => W::Grabbing,
        }
    }

    /// Translate screen position from winit to egui.
    ///
    /// This function assumnes that the egui screen rect coincides with the winit screen screen
    /// rect.
    pub fn pos_w2e(w: winit::dpi::PhysicalPosition<f64>, scale_factor: f64) -> egui::Pos2 {
        let logical = w.to_logical(scale_factor);
        egui::pos2(logical.x, logical.y)
    }

    /// Translate screen position from egui to winit.
    ///
    /// This function assumnes that the egui screen rect coincides with the winit screen screen
    /// rect.
    pub fn pos_e2w(e: egui::Pos2, scale_factor: f64) -> winit::dpi::PhysicalPosition<f64> {
        winit::dpi::PhysicalPosition::from_logical::<_, f64>([e.x, e.y], scale_factor)
    }
}
