"use strict";

import {resize, Slider} from "../../modules/HTMLUtils.js";
import WebGL from "../../modules/WebGLUtils.js";
import M4 from "../../modules/M4.js";
import V3 from "../../modules/V3.js";
import GridXZ from "../../geometry/GridXZ.js";
import {lerp} from "../../modules/MathUtils.js";
import DirectionalLight from "../../materials/DirectionalLight.js";
import GeometryPainter from "../../geometry/GeometryPainter.js";
import { Cone, Cube, Sphere} from "../../geometry/Figure.js";
import Vector3D from "../../geometry/Vector3D.js";
import {TrackballCamera, registerCameraEvents} from "../../modules/Trackballcamera.js";

/**
 * Transformación de la cámara (Animación).
 * @author Melissa Méndez Servín.
 */
window.addEventListener("load", main);

function main(){
    var canvas = document.getElementById("gl_canvas");
    var gl = WebGL.init(canvas);
    if(!gl) return;
    
    //Figuras
    let gridXZ = new GridXZ(gl, 68, 0, null);
    let figuresGeom = [new Cube(), new Sphere(.5, 25, 25), new Cone(.5, 1, 4, false)];
     
    let lightDirection = [0, -4, -2, 0];
    let lightPosition = [0, 2, 0, 0];
    let colors = [[0.780392, 0,0], [0.25, 0.95,0.8], [1, 1,0]];//0.6, 0.8, 0.19
    let material = { ka: [0.2,.2,.2], kd: [0.780392, 0,0], ks: [0.992157, 0.941176, 0.807843], 
                    shininess: 0.21794872*128};
    let light = { direction: lightDirection, la: [.3, .3, .3], ld: [1,1,1], ls: [1.0, 1.0, 1.0]};
    let uniforms = { u_light: light, u_material: material};  

    //Objetos a renderizar 
    let objects = [];
    for(var i= 0; i< figuresGeom.length; i++)
        objects.push(new GeometryPainter(gl, new DirectionalLight(gl, WebGL, figuresGeom[i], uniforms)));                                   
    
    let axis = [ new Vector3D(gl, WebGL, new V3(1,0,0), null, .15, [0,.2,1,1], lightPosition),
                 new Vector3D(gl, WebGL, new V3(0,1,0), null, .15, [0,1,0.2,1], lightPosition),
                 new Vector3D(gl, WebGL, new V3(0,0,1), null, .15, [1,.2,0,1], lightPosition)];
    
    //Transformaciones (multiplicación de izq a der)
    let transformations = [ [M4.scale(2, 2, 2), M4.translate(0,0.5,0), M4.translate(-2.5,0,-1.5)],//Cube
                            [M4.scale(1, 1, 1), M4.translate(0,.5,0), M4.translate(1.5,0,1.5)],//Esfera
                            [M4.scale(3, 1, 3), M4.translate(0,0.5,0), M4.translate(-1.65,2,-1), M4.rotateY(45), M4.identity()]];//Cono
    
    let vecTransformation =[[new V3(2, 2, 2), new V3(0,0.5,0), new V3(-2.5,0,-1.5)],//Cube
                            [new V3(1, 1, 1), new V3(0,.5,0), new V3(1.5,0,1.5)],//Esfera
                            [new V3(3, 1, 3), new V3(0,0.5,0), new V3(-1.65,2,-1), 45]];//Cono
    var modelMatrix;
    var modelViewMatrix;
    resize(canvas);
    
    let zNear = .1;
    let zFar = 200;

    var obj_id = 0;
    var transformation_step = 0;
    var t = 0; 

    let camera = new TrackballCamera(new V3(0,1.2,3.2));
    camera.setZoomConfig(6,1);
    gl.enable(gl.DEPTH_TEST);
    gl.clearColor(0, 0, 0, 0);

    //registerCameraEvents(camera, canvas, draw);
    requestAnimationFrame(draw);
    // Para la ejecución correcta de la animación al hacer un resize.
    window.addEventListener('resize', function(){
        if (!window.requestAnimationFrame){
            window.requestAnimationFrame(draw);
        }
        if (!window.cancelAnimationFrame)
            window.cancelAnimationFrame = function() {
                t = 0;
        };
    });

    function draw(){
        resize(canvas);
        
        var {width, height} = gl.canvas;
        let aspect = width/height;
        var projectionMatrix = M4.perspective(85, aspect, zNear, zFar);
       
        gl.viewport(0, 0, width, height);
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
        
        var viewMatrix = camera.getMatrix();
        var lightDir = M4.multiplyVector(viewMatrix, lightDirection);
        var lightPos = M4.multiplyVector(viewMatrix, lightPosition);
        
        renderLocalScene(obj_id, transformation_step, t, viewMatrix, projectionMatrix, lightDir, lightPos);
     
        if(t >= 1){
            t = 0;
            updateNextIdAndStep(obj_id, transformation_step);
        }else{
            t = t + 0.01;
        }
        requestAnimationFrame(draw);
    }
    function renderLocalScene(id, step,t, viewMatrix, projectionMatrix, lightDir, lightPos){
        gridXZ.draw(gl, viewMatrix, projectionMatrix);

        for(var i=0; i < 3; i++)
            axis[i].draw(gl, viewMatrix, projectionMatrix, lightPos);
        
        for(var i = 0; i < id+1; i++){
            uniforms.u_light.direction = lightDir;
            uniforms.u_material.kd = colors[i];
            uniforms.u_material.ka = colors[i];
            modelMatrix = M4.identity();
            let num_transfromations = (i <= id-1) ? transformations[i].length : step;
            for(var s = 0; s < num_transfromations; s++){
                if(i == id && s == num_transfromations-1)
                    modelMatrix = M4.multiply(modelMatrix, getCurrentT(vecTransformation[i][s],step-1,t));
                else
                    modelMatrix = M4.multiply(modelMatrix, transformations[i][s]);
            }
            modelViewMatrix = M4.multiply(viewMatrix, modelMatrix);
            objects[i].draw(gl, modelViewMatrix, projectionMatrix, uniforms);
        }
    }
    function getCurrentT(goalVector, step, t){
        var initVector, lerpVector, currTransformation;
        if(step == 0){
            initVector = new V3(1,1,1);
            lerpVector = lerp(initVector, goalVector, t);
            currTransformation = M4.scale(lerpVector.x, lerpVector.y, lerpVector.z);
        }else if(step == 3){
            currTransformation = M4.rotateY(45*t);
        }else if(step == 4){
            currTransformation = M4.identity();
        }
        else{
            initVector = new V3(0,0,0);
            lerpVector = lerp(initVector, goalVector, t);
            currTransformation = M4.translate(lerpVector.x, lerpVector.y, lerpVector.z);
        }
        return currTransformation;
    }
    function updateNextIdAndStep(id,step){
        if((step == 3 && id < 2) || (step == 5 && id == 2)){//Reinicia 
            transformation_step = 0;
            obj_id = (id + 1) % 3;
            return;
        }
        transformation_step += 1;
        return;
    }
}