import {getDisconnectedVertices, getNormalsFromIndices, getNormalsFromVertices, getTexCoordinates, getDisconnectedTexcoords} from "../geometry/Figure.js";
/**
 * Clase auxiliar para ejemplo de Tierra.
 * @author Melissa Méndez Servín.
 */
export default class TextureMapping{
    /**
     * Programa de sombreado Texture Mapping.
     * @param {WebGLRenderingContext} gl 
     * @param {*} WebGL 
     * @param {*} attributes 
     */
    constructor(gl, WebGL, figure, srcTextures, draw_callback, initialUniforms){
        var vsh = `#version 300 es
        uniform mat4 u_PVM_matrix;
        uniform mat4 u_VM_matrix;
        uniform mat4 u_VMN_matrix;
  
        in vec4 a_position;
        in vec3 a_normal;
    
        out vec3 v_position; 
        out vec3 v_local_position; 
        out vec3 v_normal;

        void main(){
            v_normal = (u_VMN_matrix * vec4(a_normal, 0)).xyz;
            v_local_position = normalize(a_position.xyz);
            v_position = (u_VM_matrix * a_position).xyz;

            gl_Position = u_PVM_matrix * a_position;

        }`;
var fsh = `#version 300 es
        precision highp float;
        
        struct Material{    
            sampler2D diffuse_map;
            sampler2D specular_map;
            sampler2D normal_map;
            float shininess;
        };
        
        struct Light{
            vec4 position;
            vec3 la;
            vec3 ld;
            vec3 ls;
        };

        uniform Light u_light;
        uniform Material u_material; 

        in vec3 v_position;
        in vec3 v_normal;
        in vec3 v_local_position;

        out vec4 glColor;
    
        void main(){
            float u = atan(v_local_position.z, v_local_position.x)/(2.0*3.14159);
            float v = asin(v_local_position.y)/3.14159;
            vec2 v_texcoord = vec2(u,v) + vec2(0.5);

            vec3 L = normalize(u_light.position.xyz - v_position);
            vec3 N = normalize(v_normal);

            float cos_angle = max(dot(N, L), 0.0);
            vec3 diffuse_color = texture(u_material.diffuse_map, v_texcoord).rgb;
            
            float specular_intensity = texture(u_material.specular_map, v_texcoord).r;
            float specular = 0.0;

            if(cos_angle > 0.0){
                    vec3 R = reflect(-L,N);
                    vec3 V = normalize(-v_position);
                    float spec_angle = max(dot(R,V),0.0);
                    specular = pow(spec_angle, u_material.shininess);
            }
            vec3 ambient = vec3(0.5);
            vec3 contribution = vec3(diffuse_color * ambient * u_light.la + 
                                    (diffuse_color * u_light.ld * cos_angle +
                                    specular_intensity * u_light.ls * specular));
            glColor = vec4(contribution, 1.0);
            //glColor = vec4(diffuse_color ,1.0);
        }`; 

        if (WebGL.programs["TM"])
            this.program = WebGL.programs["TM"];
        else
            this.program = WebGL.createProgram(gl, vsh, fsh, "MM");
        
            this.vertices = (figure.byIndices || figure.getNormals) ?  figure.getVertices() : getDisconnectedVertices(figure.getVertices(), figure.getFaces());
        if(figure.getNormals)
            this.normals = figure.getNormals();
        else
            this.normals = (figure.byIndices) ? getNormalsFromIndices(figure.getFaces(), this.vertices) : getNormalsFromVertices(this.vertices);
           

         let attributes = {  position: { numComponents: 3, 
                                                 data: this.vertices},
                              normal: { numComponents: 3, 
                                                 data: this.normals}
                         };
        if(figure.byIndices){
            let vaoAndIndices = WebGL.setVAOAndAttributes(gl, this.program, attributes, figure.getFaces());
            this.vao = vaoAndIndices.vao;
            this.indexBuffer = vaoAndIndices.indexBuffer;
            this.numIndices = figure.numIndices;
        }else{
            this.vao = WebGL.setVAOAndAttributes(gl, this.program, attributes);  
            this.numElements = this.vertices.length/3;
        }
        this.setUniforms = WebGL.setUniforms(gl, this.program);

        this.texture = WebGL.loadImages(srcTextures, createTextures);
        this.uniforms = Object.assign({ texture_factor: 1.5}, initialUniforms);
        var filters = { filters: {min: gl.NEAREST, mag: gl.NEAREST, wrap_s: gl.REPEAT, wrap_t: gl.REPEAT}};
        function createTextures(images){
            WebGL.createTextures(gl, images, srcTextures, draw_callback, filters);
        }
    }
}
