pub mod polar;
pub mod position;
pub mod trackball;
pub mod viewport;
use crate::components::{Program, Snippet};

use super::AttaWithProgram;

pub struct ChainedTransform {
    snippet: Snippet,
    chain: Vec<Box<dyn Transform>>,
}

impl ChainedTransform {
    pub fn from<T: Transform + Clone + 'static>(transform: &T) -> Self {
        let snippet = transform.snippet().clone();
        // let snippet = transform.snippet().to_owned();
        Self {
            snippet,
            chain: vec![Box::new(transform.clone())],
        }
    }

    pub fn chain<P: Transform + 'static + Clone>(mut self, other: &P) -> Self {
        let new_snippet = self.snippet.clone().chain(other.snippet().to_owned());
        self.snippet = new_snippet;
        self.chain.push(Box::new(other.clone()));
        self
    }
}

impl Transform for ChainedTransform {
    fn snippet(&self) -> &Snippet {
        &self.snippet
    }
}

impl AttaWithProgram for ChainedTransform {
    fn attach_with_program(&self, gl: &glow::Context, program: &Program) -> super::Result<()> {
        for transform in &self.chain {
            transform.attach_with_program(gl, program)?;
        }

        Ok(())
    }
}
pub trait Transform: AttaWithProgram {
    fn snippet(&self) -> &Snippet;
}

mod test {
    use super::*;

    #[test]
    fn test_transform() {
        let polar = polar::Polar::new().unwrap();
        // let trackball = trackball::Trackball::new().unwrap();

        // let chained = ChainedTransform::from(polar).chain(trackball);

        // println!("{}", chained.snippet().prepare_code());
        // println!("{}", chained.snippet().call(&vec![]).unwrap());
    }
}
