
use image::GenericImage;
use std::path::Path;
use crate::shader::shader;
mod mesh;
use tobj;
use cgmath::{vec2, vec3};

#[derive(Default)]
pub struct Model
    {
        pub textures_loaded: Vec<mesh::Texture>,
        pub meshes: Vec<mesh::Mesh>,
        directory: String,
    }

impl Model {
    pub fn new(path: &str) -> Model {
        let mut model = Model::default();
        model.loadModel(path);
        model
    }


    pub fn Draw(&self, shader: &shader) {
        for mesh in &self.meshes {
            unsafe { mesh.Draw(&shader); }
        }
    }

    fn loadModel(&mut self, path: &str) {

        let tempPath: String = format!("{}/model.obj", path);
        let path = Path::new(path);
        let modelPath = Path::new(&tempPath);


        self.directory = path.parent().unwrap_or_else(|| Path::new("")).to_str().unwrap().into();
        let obj = tobj::load_obj(modelPath);

        let (models, materials) = obj.unwrap();
        for model in models {
            let mesh = &model.mesh;
            let num_vertices = mesh.positions.len() / 3;


            let mut vertices: Vec<mesh::Vertex> = Vec::with_capacity(num_vertices);
            let indices: Vec<u32> = mesh.indices.clone();

            let (p, n, t) = (&mesh.positions, &mesh.normals, &mesh.texcoords);
            for i in 0..num_vertices {
                vertices.push(mesh::Vertex {
                    Position:  vec3(p[i*3], p[i*3+1], p[i*3+2]),
                    Normal:    vec3(n[i*3], n[i*3+1], n[i*3+2]),
                    TexCoords: vec2(t[i*2], t[i*2+1]),
                    ..mesh::Vertex::default()
                })
            }

            // process
                let mut textures = Vec::new();
                if let Some(material_id) = mesh.material_id {
                let material = &materials[material_id];
                // 1. diffuse map
                //
                if !material.diffuse_texture.is_empty() {
                    let texture = self.loadMaterialTexture( &path.join(&material.diffuse_texture).display().to_string(), "texture_diffuse");
                    textures.push(texture);
                }
                // 2.specular map
                if !material.specular_texture.is_empty() {
                    let texture = self.loadMaterialTexture(&path.join(&material.specular_texture).display().to_string(), "texture_specular");
                    textures.push(texture);
                }

                // 3.normal
                //
                if !material.normal_texture.is_empty() {
                    let texture = self.loadMaterialTexture(&path.join(&material.normal_texture).display().to_string(), "texture_normal");
                    textures.push(texture);

                }
            }
            self.meshes.push(mesh::Mesh::new(vertices,indices, textures));


        }
    }

    fn loadMaterialTexture(&mut self, path: &str, typeName: &str) -> mesh::Texture {
{
        let texture = self.textures_loaded.iter().find(|t| t.path == path);
        if let Some(texture) = texture {
            return texture.clone();
        }
}
        let texture = mesh::Texture {
            id: TextureFromFile(path),
            type_: typeName.into(),
            path: path.into()
        };
        self.textures_loaded.push(texture.clone());
        texture

    }
}





fn TextureFromFile(path: &str) -> u32
{
    let filename = path;

    let mut textureID = 0;

    unsafe {
        // NOTE might become a problem later on
        gl::GenTextures(1, textureID as *mut u32);
        gl::BindTexture(gl::TEXTURE_2D, textureID);

        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::REPEAT as i32);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::REPEAT as i32);

        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);

        let img = image::open(Path::new(&filename))
            .expect("failed to load texture");
        img.flipv();
        let format = match img {
            image::DynamicImage::ImageLuma8(_) => gl::RED,
            image::DynamicImage::ImageLumaA8(_) => gl::RG,
            image::DynamicImage::ImageRgb8(_) => gl::RGB,
            image::DynamicImage::ImageRgba8(_) => gl::RGBA,
            _ => panic!("What is this image u gave me big man?")
        };
        let data = img.as_bytes();

        gl::TexImage2D(gl::TEXTURE_2D,
                       0,
                       format as i32,
                       img.width() as i32,
                       img.height() as i32,
                       0,
                       format,
                       gl::UNSIGNED_BYTE,
                       &data[0] as *const u8 as *const std::os::raw::c_void);
        gl::GenerateMipmap(gl::TEXTURE_2D);
    }

    textureID



    }
