import * as MU from "../../modules/MathUtils.js";
import {resize, Slider, resizeAndCenterX, MathBox, } 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";

/**
 * Cono Spotlight. Verificación de un punto dentro del cono.
 * @author Melissa Méndez Servín.
 */
window.addEventListener("load", main);

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

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

    var theta = 45;
    var D_rotation = 0;
    //HTML CONTROLS
    let rotation = new Slider(controls, "Rota <b>D</b>", -90, 90,  updateRD, D_rotation, 1, ["#4994D0"]);
    let cutt_off = new Slider(controls, "θ", 0, 90,  updateCuttOff, theta, 1, ["#4994D0"]);
    const unit = 25;   
    
    resize(canvas);
    //Vectores
    const colorCone = [70, 130, 180, 255]; 
    const colorLight = [255, 215, 0, 255];

    const {width, height} = gl.canvas;
    var scale = Math.floor(width/unit/6);
    
    let P = new V2(0,1.6*scale);
    let Q = new V2(2,-scale);
    const D_const  = new V2(0,-2.6*scale);
    const x_basis = new V2(1,0);
    const y_basis = new V2(0,1);
    let D = D_const;
    let lEdge = getEdge(-theta);
    let rEdge = getEdge(theta);
    let D_arrow = new Vector2D(gl, WebGL, P, D, unit, 2.5, colorCone);
    let el_arrow = new Vector2D(gl, WebGL, P, lEdge, unit, 2.5, colorCone);
    let er_arrow = new Vector2D(gl, WebGL, P, rEdge, unit, 2.5, colorCone);
    let L = Q.sub(P);
    let L_arrow = new Vector2D(gl, WebGL, P, L, unit, 3, colorLight);
    //Puntos de los vectores
    var vparams = { center: P, r: 0.2, numPoints: 10};
    let P_point = new Figure2D(gl, WebGL, 'circle', unit, colorCone, vparams);
    vparams.center = Q;
    let Q_point = new Figure2D(gl, WebGL, 'circle', unit, colorLight, vparams);
    
    //Atributos del arco
    var arcparamsT = { center: P, sAngle : 0, eAngle: .25 * Math.PI, r: 2.7 , numPoints: 50};
    var arcparams = { center: P, sAngle : 0, eAngle: .25 * Math.PI, r: 2.7, thickness: 0.2 , numPoints: 50};
    
    //Superficie
    let surface = new Line2D(gl, WebGL, new V2(-4*scale,Q.y), x_basis, 8 *scale, unit, 2, [0,0,0,255]);
   
    //Etiquetas vectores
    let dLabel = new MathBox(container, {}, "\\mathbf{D}");
    let lLabel = new MathBox(container, {}, "\\mathbf{L}");
    let pLabel = new MathBox(container, {}, "P");
    let qLabel = new MathBox(container, {}, "Q");
 
    gl.clearColor(0, 0, 0, 0);
    
    draw();
    window.addEventListener('resize', draw);
    
    function draw(){
        resize(canvas);
        resizeAndCenterX(controls, {bottom:5});

        const {width, height} = gl.canvas;
        gl.viewport(0, 0, width, height);
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
        
        var projectionMatrix = M3.projection(-width/2, width/2, height/2, -height/2);
        
        surface.draw(gl, projectionMatrix);
        lEdge = getEdge(-theta);
        rEdge = getEdge(theta);
        //Cálculos para el arco del ángulo theta
        var dAngle = Math.acos(D.normalize().dotProduct(x_basis));
        dAngle = (D.dotProduct(y_basis) < 0) ? 2*Math.PI - dAngle : dAngle;
        var edge;
        if(D_rotation <= 10)
            edge = rEdge;
        else
            edge = lEdge;
        var eAngle = Math.acos(edge.normalize().dotProduct(x_basis));
        eAngle = (edge.dotProduct(y_basis) < 0) ?  2*Math.PI - eAngle : eAngle;
        if(Math.abs(dAngle - eAngle) > Math.PI){ //Si es mayor de 180ª
            if(dAngle > eAngle) //Empezamos con el ángulo mayor
                dAngle -= 2*Math.PI; 
            else
                eAngle -= 2*Math.PI; 
        }

        arcparamsT.sAngle = (dAngle < eAngle) ? dAngle : eAngle;
        var endAngleD = (dAngle < eAngle) ? eAngle : dAngle;
        arcparamsT.eAngle = endAngleD;

        let arcTheta  = new Figure2D(gl, WebGL, 'sliceCircle', unit, [255, 0, 0, 180], arcparamsT);
        
        //Cálculos para el arco del ángulo theta
        var lAngle = Math.acos(L.normalize().dotProduct(x_basis));
        lAngle = (L.dotProduct(y_basis) < 0) ?  2*Math.PI - lAngle : lAngle;
        if(Math.abs(dAngle - lAngle) > Math.PI){ //Si es mayor de 180ª
            if(dAngle > lAngle) //Empezamos con el ángulo mayor
                dAngle -= 2*Math.PI; 
            else
                lAngle -= 2*Math.PI; 
        }
        arcparams.sAngle = (dAngle < lAngle) ? dAngle : lAngle;
        arcparams.eAngle = (dAngle < lAngle) ? lAngle : dAngle;
      
        let arcL  = new Figure2D(gl, WebGL, 'arc', unit, [0, 206, 209, 255], arcparams);
        
        
        arcTheta.draw(gl, M3.identity(), projectionMatrix);
        arcL.draw(gl, M3.identity(), projectionMatrix);


        D_arrow.draw(gl, projectionMatrix, null, D);
        el_arrow.draw(gl, projectionMatrix, null, lEdge);
        er_arrow.draw(gl, projectionMatrix, null, rEdge);
        L_arrow.draw(gl, projectionMatrix, null, L);
        P_point.draw(gl, M3.identity(), projectionMatrix);        
        Q_point.draw(gl, M3.identity(), projectionMatrix);        
        
        let labelPos = MU.getVectorLabelMidLPosition(projectionMatrix, width, height, unit, D, P);
        dLabel.setPosition(labelPos);

        labelPos = MU.getVectorLabelMidLPosition(projectionMatrix, width, height, unit, L, P);
        lLabel.setPosition(labelPos);

        labelPos = MU.getVectorLabelPosition(Q, projectionMatrix, width, height, unit, {t:7, l:-4},1);
        qLabel.setPosition(labelPos);
        labelPos = MU.getVectorLabelPosition(P, projectionMatrix, width, height, unit, {t:-27, l:-7}, 1);
        pLabel.setPosition(labelPos);
        
    }
    function getEdge(angle){
        let rotation = M3.rotate(angle);
        let edge = M3.multiplyVector(rotation, [D.x, D.y, 1]);
        return new V2(edge[0], edge[1]);
    }
    function updateCuttOff(value){
        theta = value;
        draw();
    }
    function updateRD(value){
        D_rotation = value;
        let rotation = M3.rotate(D_rotation);
        let new_direction = M3.multiplyVector(rotation, [D_const.x, D_const.y, 1]);
        D = new V2(new_direction[0], new_direction[1]);
        draw();
    }
}