use super::skin::Skin;
use crate::prelude::*;

use gltf;

use std::cmp::Ordering;
use utilities::prelude::cgmath::{Matrix4, One};

#[derive(Debug)]
pub struct Mesh {
    pub index: usize,
    pub node_index: usize,
    pub name: Option<String>,
    primitives: Vec<Primitive>,
    model_matrix: Matrix4<f32>,
}

impl Mesh {
    pub fn new(
        gltf_mesh: gltf::Mesh<'_>,
        buffers: &Vec<gltf::buffer::Data>,
        skin: Option<&Skin>,
        node_index: usize,
    ) -> Mesh {
        let mut primitives = Vec::new();

        for gltf_primitive in gltf_mesh.primitives() {
            primitives.push(Primitive::new(gltf_primitive, buffers, skin));
        }

        Mesh {
            index: gltf_mesh.index(),
            node_index,
            name: gltf_mesh.name().map(|name| name.to_string()),
            primitives,
            model_matrix: Matrix4::one(),
        }
    }

    pub fn primitives(&self) -> &[Primitive] {
        &self.primitives
    }

    pub fn model_matrix(&self) -> Matrix4<f32> {
        self.model_matrix
    }

    pub fn set_model_matrix(&mut self, model_matrix: Matrix4<f32>) {
        self.model_matrix = model_matrix;

        for primitive in &mut self.primitives {
            primitive.scale_bb(model_matrix);
        }
    }
}

impl Ord for Mesh {
    fn cmp(&self, other: &Self) -> Ordering {
        self.index.cmp(&other.index)
    }
}

impl PartialOrd for Mesh {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialEq for Mesh {
    fn eq(&self, other: &Self) -> bool {
        self.index == other.index
    }
}

impl Eq for Mesh {}