mod background;
mod foreground;
mod imp;
use crate::coords::Mapper;
use crate::data::{MultiDimensionData, RadarData2d};
use crate::pipeline::ProjPipe;
use crate::pipeline::{Pipeline, ShadePipe};
use std::fmt::Debug;

pub use self::background::{BackgroundConfig, BackgroundWidget};
pub use self::foreground::{ForegroundConfig, ForegroundWidget};
use self::imp::RenderConfig;
use crate::data::DownSampleMeth;
use femtovg::Color;
pub use glib::subclass::prelude::*;
use image::RgbImage;
use ndarray::{self, s, Array2, Axis, Dimension, Ix2, Zip};
use num_traits::{AsPrimitive, FromPrimitive, Num};
use proj::ProjError;

pub(super) type WindowCoord = (f32, f32);

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

impl Default for Render {
    fn default() -> Self {
        Self::new(BackgroundWidget::default(), ForegroundWidget::default())
    }
}

impl Render {
    pub fn new(background: BackgroundWidget, foreground: ForegroundWidget) -> Self {
        let this: Self = glib::Object::new();
        this.imp().background.replace(background);
        this.imp().foreground.replace(foreground);
        {
            let mut configs = this.imp().config.borrow_mut();
            configs.scale = 1.0;
        }
        this
    }

    pub fn change_cfg<F>(&self, mut f: F)
    where
        F: FnMut(&mut RenderConfig),
    {
        let mut cfg = self.imp().config.borrow_mut();
        f(&mut cfg);
    }

    pub fn set_mapper(&self, mapper: Mapper) {
        self.imp().mapper.replace(mapper);
    }

    pub(super) fn load_data_2d<T, Raw>(
        &self,
        mut 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,
    {
        assert!(data.dim1.shape().len() == data.dim2.shape().len());

        let levels: Vec<T> = vec![0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65]
            .into_iter()
            .map(|b| T::from_i8(b).unwrap())
            .collect();
        let colors = vec![
            Color::rgb(0, 172, 164),
            Color::rgb(192, 192, 254),
            Color::rgb(122, 114, 238),
            Color::rgb(30, 38, 208),
            Color::rgb(166, 252, 168),
            Color::rgb(0, 234, 0),
            Color::rgb(16, 146, 26),
            Color::rgb(252, 244, 100),
            Color::rgb(200, 200, 2),
            Color::rgb(140, 140, 0),
            Color::rgb(254, 172, 172),
            Color::rgb(254, 100, 92),
            Color::rgb(238, 2, 48),
            Color::rgb(212, 142, 254),
            Color::rgb(170, 36, 250),
        ];

        let mapper = self.imp().mapper.borrow();

        let pjp = ProjPipe::new(&mapper);
        let rrp = ShadePipe::new(levels, colors.into_iter().map(|v| v.into()).collect());

        let rainbow = pjp.run(&data).unwrap();
        self.imp().foreground.borrow_mut().set_data(rainbow);
        let pbow:Array2<Option<Color>> = rrp.run(&data).unwrap();
        self.imp().foreground.borrow_mut().set_colors(pbow);
        Ok(())
    }
}