"use strict";

import {resize, Slider, Color, addLabel, DarkMode, Select, rgbNormToHex, TextBox, resizeAndCenterX} from "../../modules/HTMLUtils.js";
import WebGL from "../../modules/WebGLUtils.js";
import M4 from "../../modules/M4.js";
import PhongMaterial from "../../materials/PhongMaterial.js";
import {Cube, Sphere} from "../../geometry/Figure.js";
import GeometryPainter from "../../geometry/GeometryPainter.js";
import {TrackballCamera, registerCameraEvents} from "../../modules/Trackballcamera.js";
import V3 from "../../modules/V3.js";
import Teapot from "../../geometry/Teapot.js";
import Bunny from "../../geometry/Bunny.js";
import Light from "../../geometry/Light.js";

/**
 * Materiales con el Modelo de Iluminación de Phong.
 * @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;
    
    let lightPosition = [3, 1.5, -1.2, 0];
   
    let sphereFigure = new Sphere(1, 30,30);
    let cubeFigure = new Cube(1.5);
    let teapotFigure = new Teapot();
    let bunnyFigure = new Bunny();

    let materials = {  personalizar: { ka: [0.0, 0.0, 0.06], kd: [.55, .55, .55], ks: [0.7, 0.7, 0.7], 
                                        shininess: 0.25*128},
                             perla : { ka: [0.25, 0.20725,	0.20725], kd: [1, 0.829, 0.829], ks: [0.296648,	0.296648, 0.296648], 
                                        shininess: 0.088*128} ,
                               oro :   { ka: [0.24725, 0.1995, 0.0745], kd: [0.75164, 0.60648, 0.22648], ks: [0.628281,0.555802, 0.366065], 
                                          shininess: 0.4*128},
                         esmerarlda : { ka: [0.0215, 0.1745, 0.0215], kd: [0.07568, 0.61424, 0.07568], ks: [0.633, 0.727811, 0.633], 
                                        shininess: 0.6*128},
                             estaño :   { ka: [0.105882, 0.058824, 0.113725], kd: [0.427451, 0.470588, 0.541176], ks: [0.333333, 0.333333, 0.521569], 
                                            shininess: 9.84615*128},
                               ruby : { ka: [0.1745, 0.01175, 0.01175], kd: [0.61424, 0.04136, 0.04136], ks: [0.727811, 0.626959, 0.626959], 
                                        shininess: 0.6*128},
                              bronce: { ka: [0.2125, 0.1275, 0.054], kd: [0.714, 0.4284, 0.18144], ks: [0.393548, 0.271906, 0.166721], 
                                        shininess: 0.2*128},
                               plata: { ka: [0.19225, 0.19225, 0.19225], kd: [0.50754, 0.50754, 0.50754], ks: [0.508273, 0.508273, 0.508273], 
                                        shininess: 0.4*128},
                            plástico: { ka: [0.0, 0.1, 0.06], kd: [0.0, 0.50980392, 0.50980392], ks: [0.50196078, 0.50196078, 0.50196078], 
                                        shininess: 0.25*128},
                            obsidiana:{ ka: [0.05375, 0.05, 0.06625], kd: [0.18275, 0.17, 0.22525], ks: [0.332741, 0.328634, 0.346435], 
                                        shininess: 0.3*128}
                    };
    let light = { position: lightPosition, la: [.3, .3, .3], ld: [1,1,1], ls: [1.0, 1.0, 1.0]};
    let diffuseUniforms = { u_light: light, u_material: materials.perla}; 
    let translate =  M4.translate(0,.5,0);
    let figures = { 
                    tetera: new GeometryPainter(gl, new PhongMaterial(gl, WebGL, teapotFigure, diffuseUniforms), translate),
                    esfera : new GeometryPainter(gl, new PhongMaterial(gl, WebGL, sphereFigure, diffuseUniforms), translate),
                    conejo: new GeometryPainter(gl, new PhongMaterial(gl, WebGL, bunnyFigure, diffuseUniforms), translate),
                    cubo: new GeometryPainter(gl, new PhongMaterial(gl, WebGL, cubeFigure, diffuseUniforms), translate) };
    let selectedFigure = figures.conejo;
    let selectedMaterial = materials.perla;

    //Luz
    let bulb = new Light(gl, WebGL, lightPosition);
  
    var fov = 110;

    let zNear = 1;
    let zFar = 100;
    var pos = new V3(0,1.4,2.7);
    let camera = new TrackballCamera(pos);
    
    // HTML CONTROLS
    let parent_controls = document.getElementById("ui-container");
    parent_controls.className = "big-bottom-box";
    let c_first = document.getElementById("first");
    let c_second = document.getElementById("second");
    let c_third = document.getElementById("third");
    let light_controls = document.getElementById("ui-container-up");
    let right_controls = document.getElementById("right-options");
   
    let ccLabel = new TextBox(container, { left: 20, top: 55, type: "px"}, "", "author-small");
  
    /* Luz Ambiental */
    var ka = new Color(c_first, "k<sub>A</sub>", updateK(0), rgbNormToHex(selectedMaterial.ka));
    var la = new Color(c_first, "L<sub>A</sub>", updateL(0), rgbNormToHex(light.la));
    /* Luz Difusa */
    var kd = new Color(c_second, "k<sub>D</sub>", updateK(1), rgbNormToHex(selectedMaterial.kd));
    var ld = new Color(c_second, "L<sub>D</sub>", updateL(1), rgbNormToHex(light.ld));
    /* Luz Especular */
    var ks = new Color(c_third, "k<sub>S</sub>", updateK(2), rgbNormToHex(selectedMaterial.ks));
    var ls = new Color(c_third, "L<sub>S</sub>", updateL(2), rgbNormToHex(light.ls));
    var shininess_slider = new Slider(c_third, "α", .1, 300, updateK(3), selectedMaterial.shininess, 0.1, ["#4994D0"], "", true);

    addLabel(light_controls, "Posición de la luz");
    var light_pos_x = new Slider(light_controls, "x", -10, 10, updateLPos(0), lightPosition[0], 0.01, ["#4994D0"]);
    var light_pos_y = new Slider(light_controls, "y", -10, 10, updateLPos(1), lightPosition[1], 0.01, ["#4994D0"]);
    var light_pos_z = new Slider(light_controls, "z", -10, 10, updateLPos(2), lightPosition[2], 0.01, ["#4994D0"]);
    
    let controls = [ ka, kd, ks, shininess_slider];
    let all_controls = [parent_controls, light_controls];
    let darkMode = new DarkMode(draw, all_controls);

    /* Selects */
    let selectFigure = new Select(right_controls, "figures", setFigure, figures, "conejo");
    setFigure("conejo");
    let selectMaterial = new Select(right_controls, "materials", setMaterial, materials, "perla");
    //let lastMaterial = selectedMaterial;
    setMaterial("perla");
  
    gl.enable(gl.DEPTH_TEST);
    gl.enable(gl.CULL_FACE);

    window.addEventListener('resize', draw);
    registerCameraEvents(camera, canvas, draw);
    
    draw();

    function draw(){        
        resize(canvas);
        resizeAndCenterX(light_controls, {});
        var {width, height} = gl.canvas;
        
        darkMode.check(gl);

        gl.viewport(0, 0, width, height);
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

        let aspect = width/height;
        var projectionMatrix = M4.perspective(fov, aspect, zNear, zFar);

        let viewMatrix = camera.getMatrix();
        var lightPos = M4.multiplyVector(viewMatrix, lightPosition);
        
        bulb.draw(gl, viewMatrix, projectionMatrix, lightPosition, [light.ld[0], light.ld[1], light.ld[2], 1]);
        
        diffuseUniforms = { u_light: light, u_material: selectedMaterial}; 
        diffuseUniforms.u_light.position = lightPos;
 
        selectedFigure.draw(gl, viewMatrix, projectionMatrix, diffuseUniforms);       
    }

    function setFigure(value){
        if(value == 'conejo'){
            ccLabel.setText("<i>Bunny</i>. Modelo obtenido de <i>Stanford University <br>Computer Graphics Laboratory</i>.");
        }else
            ccLabel.setText("");
        selectedFigure = figures[value];
        draw();
    }
    function setMaterial(value){
        var flag = (value == "personalizar") ? false :true; 
        for(var i= 0; i < controls.length; i++){
            controls[i].disabled(flag);
        }  
        //lastMaterial = selectedMaterial;
        selectedMaterial = materials[value];

        ka.setColor(selectedMaterial.ka);
        kd.setColor(selectedMaterial.kd);
        ks.setColor(selectedMaterial.ks);
        shininess_slider.updateSlider(selectedMaterial.shininess);
        draw();
    }
    function updateK(index){
        return function(value){
            switch(index){
                case 0:
                    materials.personalizar.ka = value;
                    break;
                case 1:
                    materials.personalizar.kd = value;
                    break;
                case 2:
                    materials.personalizar.ks = value;
                    break;
                case 3:
                    materials.personalizar.shininess = value;
                    break;
            } 
            draw();
        }
    }
    function updateL(index){
        return function(value){
            switch(index){
                case 0:
                    light.la = value;
                    break;
                case 1:
                    light.ld = value;
                    break;
                case 2:
                    light.ls = value;
                    break;
            }
            draw();
        }
    }
    function updateLPos(index){
        return function(value){
            lightPosition[index] = value;
            draw();
        }
    }
}