"use strict";

import {resize, Slider, addLabel, resizeAndCenterX, DarkMode, Select, TextBox} from "../../modules/HTMLUtils.js";
import WebGL from "../../modules/WebGLUtils.js";
import M4 from "../../modules/M4.js";
import PhongTMaterial from "../../materials/PhongTMaterial.js";
import {Sphere, Cube, RectangularPrism, Plane} 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";

/**
 * Transparencia en dos objetos.
 * @author Melissa Méndez Servín.
 */
window.addEventListener("load", main);

function main(){
    var canvas = document.getElementById("gl_canvas");
    var gl = WebGL.init(canvas, { premultipliedAlpha: false, alpha: false});
    if(!gl) return;
    
    let sphereFigure = new Sphere(.9, 30,30);
    let cubeFigure = new Cube(1.35);
    let teapotFigure = new Teapot();
    let bunnyFigure = new Bunny();
    
    let height = -1.5;
    let lightPosition = [0, 1, 0, 0];
    const ialpha = 0.3;
    let blueMaterial =  { ka: [0.1, 0.18725, 0.1745, ialpha], kd: [0.196, 0.4151, 0.69102,ialpha], 
                        shininess: 12.8};
    let yellowMaterial ={ka: [0.24725, 0.1995, 0.0745,ialpha], kd: [0.75164, 0.60648, 0.22648,ialpha],
                        shininess: 0.4*128};

    let figures = { 
        tetéra: new GeometryPainter(gl, new PhongTMaterial(gl, WebGL, teapotFigure), M4.multiply(M4.scale(.9,.9,.9), M4.translate(0,-.4,0))),
        cubo: new GeometryPainter(gl, new PhongTMaterial(gl, WebGL, cubeFigure),  M4.translate(0,-.3,0)) ,
        esfera : new GeometryPainter(gl, new PhongTMaterial(gl, WebGL, sphereFigure), M4.translate(0,-.1,0)),
        conejo: new GeometryPainter(gl, new PhongTMaterial(gl, WebGL, bunnyFigure),  M4.translate(0,-.3,0))};

    let figure = figures.cubo;          
    
    //Piso 
    var rect = new RectangularPrism(25,1,25,true);
    const floorMaterial = { ka: [0.105882, 0.058824, 0.113725, 1], kd: [0.427451, 0.470588, 0.541176, 1], ks: [0,0,0,1], 
                            shininess: 1};
    let floor = new GeometryPainter(gl, new PhongTMaterial(gl, WebGL, rect, {u_material: floorMaterial}), M4.translate(0,height,-3.5)); 

    let bluePosition = [-1.5,0,-.5];
    let yellowPosition = [1.5,0,-.5];
 
    var fov = 90;
    let zNear = .1;
    let zFar = 100;
    var pos = new V3(0,.2,2.9);
    let camera = new TrackballCamera(pos);
    
    let controlPos = document.getElementById("ui-container-up");
    let controlAlpha = document.getElementById("ui-container-center");
    addLabel(controlPos, "Objeto Azul");
    var blue_obj_x = new Slider(controlPos, "x", -5, 5, upadateBluePosition(0), bluePosition[0], 0.1, ["#4994D0"]);
    var blue_obj_y = new Slider(controlPos, "y",  0, 2.5, upadateBluePosition(1), bluePosition[1], 0.1, ["#4994D0"]);
    var blue_obj_z = new Slider(controlPos, "z", -15, 5, upadateBluePosition(2), bluePosition[2], 0.1, ["#4994D0"]);
    
    addLabel(controlPos, "Objeto Amarillo");
    var yellow_ob_x = new Slider(controlPos, "x", -5, 5, upadateYellowPosition(0), yellowPosition[0], 0.1, ["#4994D0"]);
    var yellow_ob_y = new Slider(controlPos, "y",  0, 2.5, upadateYellowPosition(1), yellowPosition[1], 0.1, ["#4994D0"]);
    var yellow_ob_z = new Slider(controlPos, "z", -5, 2.5, upadateYellowPosition(2), yellowPosition[2], 0.1, ["#4994D0"]);

    let right_controls = document.getElementById("right-options");
    //let darkMode = new DarkMode(draw, [controlPos]);
   
    let transparencyMode = { "mezcla":  gl.ONE_MINUS_SRC_ALPHA, "mezcla aditiva":  gl.ONE};
    let selectTransparencyMode = new Select(right_controls, "figures", setBlendingMode, transparencyMode, "mezcla");
    var blendingMode =  gl.ONE_MINUS_SRC_ALPHA;
    var blendingSRC =  gl.SRC_ALPHA;
   
    let selectFigure = new Select(right_controls, "figures", setFigure, figures, "cubo");
    
    controlAlpha.setAttribute("obscure-mode", true);
    controlPos.setAttribute("obscure-mode", true);
    var alphaBlue = new Slider(controlAlpha, "α<sub>B</sub>", 0, 1, upadateAlpha(0), ialpha, .01, ["#4994D0"]);
    var alphaYellow = new Slider(controlAlpha, "α<sub>Y</sub>", 0, 1, upadateAlpha(1), ialpha, .01, ["#4994D0"]);
    
    let ccLabel = new TextBox(container, { left: 5, top: 16}, "", "author-small");
    
   // gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);

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

    function draw(){        
        resize(canvas);
        resizeAndCenterX(controlPos, {top:0});
        resizeAndCenterX(controlAlpha, {bottom:5});
        var {width, height} = gl.canvas;
        
        /*darkMode.check(gl);
        if(darkMode.checkbox.checked())
            gl.clearColor(0,0,0,1);
        else
            gl.clearColor(1,1,1,1);*/

        gl.enable(gl.DEPTH_TEST);
        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);
        
        gl.disable(gl.BLEND);
        gl.disable(gl.CULL_FACE);
        gl.depthMask(true);
        floor.draw(gl, viewMatrix, projectionMatrix, {u_light_position : lightPos});
        
        //Transparecia
        gl.enable(gl.BLEND);
        
        gl.blendFunc(blendingSRC, blendingMode);
        
        gl.depthMask(false);
        gl.enable(gl.CULL_FACE);
        let modelViewMatrixB = M4.multiply(viewMatrix, M4.translate(bluePosition[0], bluePosition[1], bluePosition[2]));
        let modelViewMatrixY = M4.multiply(viewMatrix, M4.translate(yellowPosition[0], yellowPosition[1], yellowPosition[2]));

        var uniforms = {u_light_position : lightPos};
        var firstToRender =  {}; 
        var secondToRender = {};

        if(modelViewMatrixB[14] >= modelViewMatrixY[14]){
            firstToRender.mvm = modelViewMatrixY;
            firstToRender.material = yellowMaterial;
            secondToRender.mvm = modelViewMatrixB;
            secondToRender.material = blueMaterial;
        }else{
            firstToRender.mvm = modelViewMatrixB;
            firstToRender.material = blueMaterial;
            secondToRender.mvm = modelViewMatrixY;
            secondToRender.material = yellowMaterial;
        }

        uniforms.u_material = firstToRender.material;
        gl.cullFace(gl.FRONT);
        figure.draw(gl, firstToRender.mvm, projectionMatrix, uniforms);
        gl.cullFace(gl.BACK);
        figure.draw(gl, firstToRender.mvm, projectionMatrix, uniforms);

        uniforms.u_material = secondToRender.material;
        gl.cullFace(gl.FRONT);
        figure.draw(gl, secondToRender.mvm, projectionMatrix, uniforms);
        gl.cullFace(gl.BACK);
        figure.draw(gl, secondToRender.mvm, projectionMatrix, uniforms);

    }
    function upadateYellowPosition(index){
        return function(value){
            yellowPosition[index] = value;
            draw();
        }
    }
    function upadateBluePosition(index){
        return function(value){
            bluePosition[index] = value;
            draw();
        }
    }
    function setBlendingMode(value){
        blendingMode = transparencyMode[value];
        blendingSRC =  gl.SRC_ALPHA;
        draw();
    }
    function upadateAlpha(index){
        return function(a){
            if(!index){
                blueMaterial.ka[3]  = a;
                blueMaterial.kd[3]  = a;
            }else{
                yellowMaterial.ka[3]  = a;
                yellowMaterial.kd[3]  = a;
            }
            draw();
        }
    }
    function setFigure(value){
        if(value == 'conejo'){
            ccLabel.setText( "<i>Bunny</i>. Modelo obtenido de <i>Stanford <br> University Computer Graphics Laboratory</i>.");
        }else
            ccLabel.setText("");
        figure = figures[value];
        draw();
    }
}