import * as MU from "../../modules/MathUtils.js";
import {resize, MathBox, Button, createButton} from "../../modules/HTMLUtils.js";
import WebGL from "../../modules/WebGLUtils.js";
import M3 from "../../modules/M3.js";
import V2 from "../../modules/V2.js";
import Vector2D from "../../geometry/Vector2D.js";
import Figure2D from "../../geometry/Figure2D.js";
import Line2D from "../../geometry/Line2D.js";
import { MouseVector, registerMouseEvents2DVec } from "../../modules/MouseEvents.js";

/**
 * Cálculo del vector de reflexión perfecta.
 * @author Melissa Méndez Servín.
 */
window.addEventListener("load", main);

var step = 0;
function main(){
    document.body.style.backgroundColor = "white"; 
    var canvas = document.getElementById("gl_canvas");
    var gl = WebGL.init(canvas);
    if(!gl) return;
    
    resize(canvas);

    let controls = document.getElementById("ui-container");
    controls.className = "bottom-box";

    //HTML CONTROLS
    let buttons = [ new Button(controls, upadateStep(-1), "Prev", "blue-bg", true),
                    new Button(controls, reset, "Reset", "blue-bg"),
                    new Button(controls, upadateStep(1), "Sig", "blue-bg")];
    buttons[0].disabled = true;

    const {width, height} = gl.canvas;
    var unit = 29;  
    const scale = .013 * height;
    //Vectors
    const normalColor = [255, 0, 0, 255];
    const lightColor = [255, 215, 0, 255];
    const rColor = [0, 215, 200, 255];
    const projColor = [0, 255, 0, 255];
    const opaqueColor = [97, 100, 112, 200]; 
    const sizeVec = 2.8;
    let sPoint  = new V2(0,0);
    //Normal N
    let N  = new V2(0, scale * 1);
    let normal = new Vector2D(gl, WebGL, sPoint, N, unit, sizeVec, normalColor);
    //Dirección de la luz incidente L
    let L  = new V2(-scale * 1.5, scale * .8);
    let light = new Vector2D(gl, WebGL, sPoint, L, unit, sizeVec, lightColor);
    //Proyección
    let proj_n = L.projection(N);
    let vector = new Vector2D(gl, WebGL, sPoint, proj_n, unit, sizeVec, projColor);
    //-L
    let l_neg = new Vector2D(gl, WebGL, sPoint, -L, unit, sizeVec, lightColor);
    //R
    let nL, R, upProj;
    //Superficie
    let surface = new Line2D(gl, WebGL, new V2(-2*scale,0), new V2(1, 0), 4 *scale, unit, 2, [0,0,0,255]);
    
    //Etiquetas vectores
    let n_label = new MathBox(container, {}, "\\mathbf{N}", "math-label");
    let l_label = new MathBox(container, {}, "\\mathbf{L}", "math-label");
    let proj_n_label = new MathBox(container, {}, "\\mathbf{N}(\\mathbf{N}\\cdot \\mathbf{L})", "math-label");
    let l_neg_label = new MathBox(container, {}, "\\mathbf{-L}", "math-label");
    let r_label = new MathBox(container, {}, "\\mathbf{R}", "math-label");
 
    const radiusRegion = 0.45;
    //Circunferencia para señalar el área/región para mover la flecha
    var cparams = { center: sPoint, r: radiusRegion, thickness: 0.15, numPoints: 10};
    let uCRegion = new Figure2D(gl, WebGL, 'circumference', unit, opaqueColor, cparams);
    let vCRegion = new Figure2D(gl, WebGL, 'circumference', unit, opaqueColor, cparams);

    //Límites de la proyección
    let projectionLimits = { l : -.5, r: .5, t: .48, b: -.52};
    //Constructor auxiliar para  el manejador de eventos con el ratón
    let l_MV = new MouseVector(gl, radiusRegion, unit, L, projectionLimits);
    let mouseVectors = [l_MV];

    //Descripción
    let description = new MathBox(container, {top:0, left:0});
    let infoByIndex = [ "\\text{Se definen los vectores }\\mathbf{N} \\text{ y } \\mathbf{L}",
                        "(\\text{Normalizamos})",
                        "\\text{Tomamos al vector }\\mathbf{-L}",
                        "\\text{Calculamos la proyección de } \\mathbf{L} \\text{ sobre } \\mathbf{N}",
                        "\\text{Sumamos dos veces a la proyección } \\mathbf{P}_{\\mathbf{N}}\\mathbf{L}",
                        "\\text{Finalmente obtenemos }\\mathbf{R}"];
    gl.clearColor(0, 0, 0, 0);
    //Transparecia
    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
    
    draw();
    window.addEventListener('resize', draw);
    registerMouseEvents2DVec(canvas, mouseVectors, draw);

    function draw(){
        resize(canvas);
        const {width, height} = gl.canvas;
        gl.viewport(0, 0, width, height);
        
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
                
        let projectionMatrix = M3.projection(projectionLimits.l * width, 
                                             projectionLimits.r * width, 
                                             projectionLimits.t * height, 
                                             projectionLimits.b * height); 

        
        proj_n_label.hideLabel();
        l_neg_label.hideLabel();
        r_label.hideLabel();
        description.setText(infoByIndex[step]);

        let labelPos = MU.getVectorLabelMidPosition(projectionMatrix, width, height, unit, N);
        n_label.setPosition(labelPos);
        
        labelPos = MU.getVectorLabelMidPosition(projectionMatrix, width, height, unit, L);
        l_label.setPosition(labelPos);
        
        //Verificamos la posición del mouse para mostrar o no la región
        if(step == 0){
              if(l_MV.showRegion){
                  vCRegion.draw(gl, M3.translate(L.x, L.y), projectionMatrix);
                }
                L = l_MV.vector;
        }
        else if(step == 1){ //Normalizamos
            L = L.normalize().scale(scale);
        }

        surface.draw(gl, projectionMatrix);
        normal.draw(gl, projectionMatrix, null, N);
        light.draw(gl, projectionMatrix, null, L);
        if(step > 1){
            nL = L.scale(-1);
            labelPos = MU.getVectorLabelMidPosition(projectionMatrix, width, height, unit, nL);
            l_neg_label.setPosition(labelPos);
            l_neg.draw(gl, projectionMatrix, null, nL);
        }
        if(step > 2){
            proj_n = L.projection(N);  
            labelPos = MU.getVectorLabelMidPosition(projectionMatrix, width, height, unit, proj_n);
            proj_n_label.setPosition(labelPos);
            vector.draw(gl, projectionMatrix, projColor, proj_n, sPoint);
        }
        if(step > 3){
            upProj = nL.add(proj_n);
            vector.draw(gl, projectionMatrix, projColor, proj_n, nL);
            vector.draw(gl, projectionMatrix, projColor, proj_n, upProj);
            labelPos = MU.getVectorLabelMidPosition(projectionMatrix, width, height, unit, proj_n, upProj);
            proj_n_label.setPosition(labelPos);
        }
        if(step > 4){//Vector de reflexión perfecta
            R = proj_n.scale(2).sub(L);
            labelPos = MU.getVectorLabelMidPosition(projectionMatrix, width, height, unit, R);
            r_label.setPosition(labelPos);
            vector.draw(gl, projectionMatrix, rColor, R, sPoint);
        }
    }

    function upadateStep(button){
        return function(){
            if (step + button < 0 || step + button > 5)
                return;
            step += button;
            buttons[0].updateState(step, 1, 5);//Prev
            buttons[2].updateState(step, 0, 4);//Sig
            draw(); 
        }
    }
    function reset(){
        step = 0;
        buttons[0].updateState(step, 1, 5);//Prev
        buttons[2].updateState(step, 0, 4);//Sig
        L = new V2(-scale * 1.5, scale * .8);
        l_MV.vector = L;
        draw();
    }
}