use cgmath::Matrix3;
use crate::egl::Texture;
use glium::{program, uniform};
use std::error::Error;
use super::Shader;
pub enum PixOrder {
    RGGB = 0,
    GRBG = 1,
    GBRG = 2,
    BGGR = 3,
}
impl TryFrom<u32> for PixOrder {
    type Error = ();
    fn try_from(v: u32) -> Result<Self, Self::Error> {
        use PixOrder::*;
        match v {
            0 => Ok(RGGB),
            1 => Ok(GRBG),
            2 => Ok(GBRG),
            3 => Ok(BGGR),
            _ => Err(()),
        }
    }
}
pub struct DebayerHq;
impl DebayerHq {
    pub fn new_raw<F: glium::backend::Facade>(facade: &F, out_dims: (u32, u32))
        -> Result<Shader<Self>, Box<dyn Error>>
    {
        Shader::new_with_facade(facade, out_dims)
    }
    pub fn new_raw_rg88<F: glium::backend::Facade>(facade: &F, out_dims: (u32, u32))
        -> Result<Shader<Self>, Box<dyn Error>>
    {
        Shader::new_rg88_with_facade(facade, out_dims)
    }
}
impl Shader<DebayerHq> {
    pub fn new_with_facade<F: glium::backend::Facade>(
        facade: &F,
        out_dims: (u32, u32),
    ) -> Result<Self, Box<dyn Error>> {
        Self::new_with_facade_and_fragment(facade, out_dims, include_str!("bayer_hq/frag.glsl"))
    }
    pub fn new_rg88_with_facade<F: glium::backend::Facade>(
        facade: &F,
        out_dims: (u32, u32),
    ) -> Result<Self, Box<dyn Error>> {
        Self::new_with_facade_and_fragment(facade, out_dims, include_str!("bayer_hq/frag_rg.glsl"))
    }
    
    fn new_with_facade_and_fragment<F: glium::backend::Facade>(
        facade: &F,
        out_dims: (u32, u32),
        fragment: &'static str,
    ) -> Result<Self, Box<dyn Error>> {
        let (vertices, indices) = super::covering_vertices(facade, out_dims)?;
        Ok(Self {
            program: program!(facade,
                120 => {
                    vertex: include_str!("bayer_hq/vert.glsl"),
                    fragment: fragment,
                }
            )?,
            vertices,
            indices,
            _data: Default::default(),
        })
    }
    
    pub fn convert<F: glium::backend::Facade>(
        &self,
        facade: &F,
        source_tex: Texture,
        target: &mut impl glium::Surface,
        data: PixOrder,
        color_matrix: Matrix3<f32>,
    ) -> Result<(), Box<dyn Error>>{
        let color_matrix: [[f32; 3]; 3] = color_matrix.into();
        self.draw_any(
            facade,
            source_tex,
            target,
            uniform! {
                first_red: match data {
                    PixOrder::RGGB => (0f32, 0f32),
                    PixOrder::GRBG => (0f32, 1f32),
                    PixOrder::GBRG => (1f32, 0f32),
                    PixOrder::BGGR => (1f32, 1f32),
                },
                color_matrix: color_matrix,
            },
        )
    }
}