"use strict";

import {resize, MathBox, Button} from "../../../modules/HTMLUtils.js";
import WebGL from "../../../modules/WebGLUtils.js";
import M4 from "../../../modules/M4.js";
import Diffuse from "../../../materials/Diffuse.js";
import SolidColor from "../../../materials/SolidColor.js";
import Vector3D from "../../../geometry/Vector3D.js";
import Line3D from "../../../geometry/Line3D.js";
import {Sphere, RectangularPrism} from "../../../geometry/Figure.js";
import {getPixel3DPosition} from "../../../modules/MathUtils.js";
import GeometryPainter from "../../../geometry/GeometryPainter.js";
import {TrackballCamera, registerCameraEvents} from "../../../modules/Trackballcamera.js";
import V3 from "../../../modules/V3.js";

/**
 * Proyección ortogonal sobre un plano.
 * @author Melissa Méndez Servín.
 */
window.addEventListener("load", main);

let step = 0;
let max_step = 4;
function main(){
    var canvas = document.getElementById("gl_canvas");
    var gl = WebGL.init(canvas);
    if(!gl) return;

    let controls = document.getElementById("ui-container");
    controls.className = "vertical-up-bttns-box";

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

    let lightPosition = [0, 1, 5, 0];
    let diffuseUniforms = { u_light_position: lightPosition}; 
    let sColor = { u_color: [.8,.8,.8,1] };
    let pColor = { u_color: [.2,.2,.4,1]}
    let qColor = { u_color: [.4,.4,.4,1]}
    let sPoint = new V3(0,-.5,0);
    let normal_label = new MathBox(container, {}, "\\mathbf{n}");
    let v_label = new MathBox(container, {}, "\\overset{\\rarr}{SP}");
    let p_label = new MathBox(container, {}, "P");
    let s_label = new MathBox(container, {}, "S");
    let q_label = new MathBox(container, {}, "Q");
    let pnv_label = new MathBox(container, {}, "P_{n}\\overset{\\rarr}{SP}");
    let pnvi_label = new MathBox(container, {}, "-P_{n}\\overset{\\rarr}{SP}");

    //Flechas
    const proyColor = [.8,.8,.2,1];
    let normal_vec = new V3(0,1.3,0);
    let point_vec = new V3(1,1,0);
    let proy_vec = point_vec.projection(normal_vec);
    let p = point_vec;
    let p_point_vec = sPoint.add(p);
    let normalArrow = new Vector3D(gl, WebGL, normal_vec, sPoint, .07, [.8,.8,.8,1], lightPosition, normal_label);
    let vArrow = new Vector3D(gl, WebGL, point_vec, sPoint, .07, pColor.u_color, lightPosition, v_label); 
    let PnvArrow = new Vector3D(gl, WebGL, proy_vec, sPoint, .08, proyColor, lightPosition, pnv_label); 
    let PnvIArrow = new Vector3D(gl, WebGL, proy_vec.scale(-1), p_point_vec, .07, proyColor, lightPosition, pnvi_label); 
    
    PnvArrow.setOffsetLabelPosition(-60,-20);
    PnvIArrow.setOffsetLabelPosition(8,0);
    //Puntos
    let q_point_vec = p_point_vec.add(proy_vec.scale(-1));
    let translateToPPoint = M4.translate(p_point_vec.x , p_point_vec.y, p_point_vec.z);
    let translateToQPoint = M4.translate(q_point_vec.x , q_point_vec.y, q_point_vec.z);
    let pointFigure = new Sphere(.1, 40, 30);
    let s = new GeometryPainter(gl, new Diffuse(gl, WebGL, pointFigure, sColor), M4.scale(.6,.6,.6));
    let p_point = new GeometryPainter(gl, new Diffuse(gl, WebGL, pointFigure, pColor), M4.scale(.4,.4,.4));
    let q_point = new GeometryPainter(gl, new Diffuse(gl, WebGL, pointFigure, qColor), M4.scale(.4,.4,.4));
    //Plano
    var rect = new RectangularPrism(4.5,.02,4.5,true);
    let plane = new GeometryPainter(gl, new SolidColor(gl, WebGL, rect, [.8,.9,1,1]), M4.translate(0,sPoint.y-.005,0));    
    
    //Linea de proyección
    let lineProy = new Line3D(gl, WebGL, p, proy_vec, sPoint, .025, [.6,.6,.1,1]);
   
    var fov = 70;
    if(window.innerWidth < window.innerHeight)
        fov = 120;

    let zNear = .1;
    let zFar = 2000;
    let camera = new TrackballCamera(new V3(0,.4,2.3));
    camera.setZoomConfig(4.5,2.1);
    resize(canvas);
    
    gl.enable(gl.DEPTH_TEST);
    //gl.enable(gl.CULL_FACE);
    gl.clearColor(0, 0, 0, 0);

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

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

        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);
        diffuseUniforms.u_light_position = lightPos;

        let sVM = M4.multiply(viewMatrix, M4.translate(sPoint.x, sPoint.y, sPoint.z));
        s.draw(gl, sVM, projectionMatrix, diffuseUniforms);
        
        let pointVM = M4.multiply(viewMatrix, translateToPPoint);
        p_point.draw(gl, pointVM, projectionMatrix, diffuseUniforms);
        
        let label_pos = getPixel3DPosition(gl, M4.multiply(projectionMatrix, sVM), -25, -10); 
        s_label.setPosition(label_pos);
        label_pos = getPixel3DPosition(gl, M4.multiply(projectionMatrix, pointVM), 7, -10); 
        p_label.setPosition(label_pos);

        normalArrow.draw(gl, viewMatrix, projectionMatrix, lightPos);
        
        vArrow.hideLabel();
        PnvArrow.hideLabel();
        PnvIArrow.hideLabel();
        q_label.hideLabel();

        if(step >= 1)
            vArrow.draw(gl, viewMatrix, projectionMatrix, lightPos);
        if(step >= 2){
            PnvArrow.draw(gl, viewMatrix, projectionMatrix, lightPos);
            lineProy.draw(gl, viewMatrix, projectionMatrix);
        }
        if(step >= 3)
            PnvIArrow.draw(gl, viewMatrix, projectionMatrix, lightPos);
        if(step == 4){
            pointVM = M4.multiply(viewMatrix, translateToQPoint);
            q_point.draw(gl, pointVM, projectionMatrix, diffuseUniforms);
    
            label_pos = getPixel3DPosition(gl, M4.multiply(projectionMatrix, pointVM), 7, -10); 
            q_label.setPosition(label_pos);
        }
        
        plane.draw(gl, viewMatrix, projectionMatrix);
    }
    
    function upadateStep(button){
        return function(){
            if (step + button < 0 || step + button > max_step)
                return;
            step += button;

            buttons[0].updateState(step, 1, max_step);
            buttons[1].updateState(step, 0, max_step-1);
            draw(); 
        }
    }
    function reset(){
        step = 0;
        buttons[0].updateState(step, 1, max_step);
        buttons[1].updateState(step, 0, max_step-1);
        draw();
    }
}