use crate::core::texture::FloatTexture;
use crate::shapes::{BilinearPatchMesh, TriQuadMesh, TriangleMesh};
use crate::utils::{Arena, FileLoc, ParameterDictionary, resolve_filename};
use shared::core::options::get_options;
use shared::core::shape::*;
use shared::shapes::*;
// use shared::spectra::*;
use parking_lot::Mutex;
use shared::utils::Transform;
use std::collections::HashMap;
use std::sync::Arc;

pub static ALL_TRIANGLE_MESHES: Mutex<Vec<Arc<TriangleMesh>>> = Mutex::new(Vec::new());
pub static ALL_BILINEAR_MESHES: Mutex<Vec<Arc<BilinearPatchMesh>>> = Mutex::new(Vec::new());

pub trait CreateShape {
    fn create(
        render_from_object: Transform,
        object_from_render: Transform,
        reverse_orientation: bool,
        parameters: ParameterDictionary,
        float_textures: HashMap<String, FloatTexture>,
        loc: FileLoc,
        arena: &mut Arena,
    ) -> Result<Vec<Shape>, String>;
}

pub trait ShapeFactory {
    fn create(
        name: &str,
        render_from_object: Transform,
        object_from_render: Transform,
        reverse_orientation: bool,
        parameters: ParameterDictionary,
        float_textures: HashMap<String, FloatTexture>,
        loc: FileLoc,
        arena: &mut Arena,
    ) -> Result<Vec<Shape>, String>;
}

impl ShapeFactory for Shape {
    fn create(
        name: &str,
        render_from_object: Transform,
        object_from_render: Transform,
        reverse_orientation: bool,
        parameters: ParameterDictionary,
        float_textures: HashMap<String, FloatTexture>,
        loc: FileLoc,
        arena: &mut Arena,
    ) -> Result<Vec<Shape>, String> {
        match name {
            "sphere" => SphereShape::create(
                render_from_object,
                object_from_render,
                reverse_orientation,
                parameters,
                float_textures,
                loc,
                arena,
            )?,
            "cylinder" => CylinderShape::create(
                render_from_object,
                object_from_render,
                reverse_orientation,
                parameters,
                float_textures,
                loc,
                arena,
            )?,
            "disk" => DiskShape::create(
                render_from_object,
                object_from_render,
                reverse_orientation,
                parameters,
                float_textures,
                loc,
                arena,
            )?,
            "bilinearmesh" => BilinearPatchShape::create(
                render_from_object,
                object_from_render,
                reverse_orientation,
                parameters,
                float_textures,
                loc,
                arena,
            )?,
            "trianglemesh" => TriangleShape::create(
                render_from_object,
                object_from_render,
                reverse_orientation,
                parameters,
                float_textures,
                loc,
                arena,
            )?,
            "plymesh" => {
                let filename = resolve_filename(parameters.get_one_string("filename", ""));
                let ply_mesh = TriQuadMesh::read_ply(filename);
                let mut edge_length = parameters.get_one_float("edgelength", 1.);
                edge_length *= get_options().displacement_edge_scale;
                let displacement_tex_name = parameters.get_texture("displacement");
            }
        }
    }
}
