use crate::{
    core::{math::vec2::Vec2, pool::Handle},
    event::{MouseButton, VirtualKeyCode},
    gui::UINode
};
use std::any::Any;

pub enum UIEventKind {
    /// Generated when some mouse button was pressed.
    MouseDown {
        pos: Vec2,
        button: MouseButton,
    },

    /// Generated when some mouse button was released.
    MouseUp {
        pos: Vec2,
        button: MouseButton,
    },

    /// Generated when mouse cursor was moved in bounds of widget.
    MouseMove {
        pos: Vec2
    },

    /// Generated when some text was entered.
    Text {
        symbol: char
    },

    /// Generated when some key was pressed.
    KeyDown {
        code: VirtualKeyCode
    },

    /// Generated when some key was released.
    KeyUp {
        code: VirtualKeyCode
    },

    /// Generated when mouse wheel was rolled while cursor was in bounds of widget.
    MouseWheel {
        pos: Vec2,
        amount: f32,
    },

    /// Generated once when mouse leaves bounds of widget.
    MouseLeave,

    /// Generated once when mouse enters bounds of widget.
    MouseEnter,

    /// Generated by clickable widgets such as buttons.
    ///
    /// # Notes
    /// This event differs from [`MouseDown`] event! [`Click`] event will be generated only
    /// if button (or any other "clickable" widget) was previously pressed and mouse button
    /// was released right inside widget bounds.
    Click,

    /// Generated by widgets that has some numeric value that can change.
    NumericValueChanged {
        old_value: f32,
        new_value: f32,
    },

    /// Generated by any widget that has max numeric value (scroll bar for example).
    MaxValueChanged(f32),

    /// Generated by any widget that has min numeric value (scroll bar for example).
    MinValueChanged(f32),

    /// Generated by any ItemsControl that has selection behaviour.
    SelectionChanged(Option<usize>),

    /// Generated by opened window.
    Opened,

    /// Generated by closed window.
    Closed,

    /// Widget just got keyboard focus.
    GotFocus,

    /// Widget lost keyboard focus.
    LostFocus,

    /// Generated by window that has become minimized.
    Minimized(bool),

    /// Generated by window that has changed its ability to minimize.
    CanMinimizeChanged(bool),

    /// Generated by window that has changed its ability to close.
    CanCloseChanged(bool),

    /// Generated by checkbox that has changed its checked state.
    Checked(Option<bool>),

    /// Any kind of user-defined event.
    User(Box<dyn Any>),
}

/// Event is basic communication element that is used to deliver information to UI nodes
/// or some other places.
pub struct UIEvent {
    /// Flag which allows to mark event as handled. This can be useful if multiple listeners
    /// can handle event but event should be handled only once.
    ///
    /// # Notes
    ///
    /// This value does not have effect on event dispatcher.
    pub handled: bool,

    pub kind: UIEventKind,

    /// Handle of node for which this event was produced. Can be NONE if target is undefined,
    /// this is the case when user click a button, button produces Click event but it does
    /// not case who will handle it. Targeted events are useful to send some data to specific
    /// nodes.
    ///
    /// # Notes
    ///
    /// Even if event has `target` it still will be available to all other event handlers and
    /// listeners.
    pub target: Handle<UINode>,

    /// Source of event.
    pub(in crate::gui) source: Handle<UINode>,
}

impl UIEvent {
    pub fn targeted(target: Handle<UINode>, kind: UIEventKind) -> Self {
        Self {
            kind,
            handled: false,
            source: Handle::NONE,
            target,
        }
    }

    pub fn new(kind: UIEventKind) -> Self {
        Self {
            kind,
            handled: false,
            source: Handle::NONE,
            target: Handle::NONE,
        }
    }

    pub fn source(&self) -> Handle<UINode> {
        self.source
    }
}