mod imp;
use crate::data::RadarData2d;
use crate::render::Render;
use glib::clone;
use glib::subclass::prelude::*;
use gtk::glib;
use gtk::traits::WidgetExt;
use gtk::{EventControllerScrollFlags, Inhibit};
use num_traits::{AsPrimitive, FromPrimitive, Num};
use proj::{Proj, ProjError};
use std::borrow::Borrow;
use std::fmt::Debug;

glib::wrapper! {
    pub struct Monitor(ObjectSubclass<imp::Monitor>)
    @extends gtk::Box,gtk::Widget;
}

impl Monitor {
    pub fn new(render: Render) -> Self {
        let this: Self = glib::Object::new();
        let pointer_location_detecture = gtk::EventControllerMotion::new();
        pointer_location_detecture.connect_motion(
            clone!(@weak this as s => move |_context, x, y| {
                s.imp().renderer.borrow().change_cfg(
                    |cfg| cfg.pointer_location = (x as f32, y as f32)
                );
            }),
        );

        let scale_detecture = gtk::EventControllerScroll::new(EventControllerScrollFlags::VERTICAL);

        scale_detecture.connect_scroll(clone!(
                @weak this as s  => @default-panic,move |_context, _x, y| {
                    let renderer = s.imp().borrow().renderer.borrow();
                    renderer.change_cfg(|cfg| {
                        let current_scale = cfg.scale;
                        cfg.scale = (current_scale + y as f32 / 100.0).max(1.0).min(5.0);
                    });
                    Inhibit(false)
                }
        ));

        render.add_controller(pointer_location_detecture);
        render.add_controller(scale_detecture);
        render.set_hexpand(true);
        render.set_parent(&this);
        this.imp().renderer.replace(render);

        this
    }

    pub fn load_data_2d<T, Raw>(&self, data: RadarData2d<T, Raw>) -> Result<(), ProjError>
    where
        T: Num
            + Clone
            + PartialEq
            + PartialOrd
            + AsPrimitive<i8>
            + AsPrimitive<f64>
            + Debug
            + FromPrimitive,
        Raw: ndarray::Data<Elem = T> + Clone + ndarray::RawDataClone,
    {
        let renderer = self.imp().renderer.borrow();
        renderer.load_data_2d(data)?;
        Ok(())
    }
}
