"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";

/**
 * Vectores base 3D.
 * @author Melissa Méndez Servín.
 */
window.addEventListener("load", main);

let step = 0;
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), "Sig"),
                    new Button(controls, upadateStep(-1), "Prev", "", true),
                    new Button(controls, reset, "Reset")];

    const basisColor = [.08,.1,.3,1];
    const opaqueColor = [.5, .5, .6, 1]; 

    let lightPosition = [2, 3, 3, 0];
    let s_uniforms = { u_color: basisColor };
    let p_uniforms = { u_color: [.6,.6,.7,1]}
    let sPoint = new V3(-1.4,0.2,-1);
    let o_label = new MathBox(container, {}, "\\mathbf{O}");
    let e1_label = new MathBox(container, {}, "\\mathbf{e}_1");
    let e2_label = new MathBox(container, {}, "\\mathbf{e}_2");
    let e3_label = new MathBox(container, {}, "\\mathbf{e}_3");
    let e3P_label = new MathBox(container, {}, "z\\mathbf{e}_3");
    let v_label = new MathBox(container, {}, "\\mathbf{v}")
    let p_label = new MathBox(container, {}, "P_v");
    let pP_label = new MathBox(container, {}, "P_v'");
    let px_label = new MathBox(container, {}, "P_{x}");
    let py_label = new MathBox(container, {}, "P_{y}");
    let p_label_pos;
    //Flechas
    let e1_vec = new V3(0,0,1);
    let e2_vec = new V3(1,0,0);
    let e3_vec = new V3(0,1,0);
    let s_e1 = e1_vec.scale(1.8);
    let s_e2 = e2_vec.scale(2.1);
    let s_e3 = e3_vec.scale(1.2);
    let p_in_plane = s_e1.add(s_e2);
    let s_p_vec = p_in_plane.add(s_e3);

    let correct_point = sPoint.add(p_in_plane);
    let correct_s_point = sPoint.add(s_p_vec);
    let v_vec = correct_s_point.sub(sPoint);
    let translatePoint;

    let e1Arrow = new Vector3D(gl, WebGL, e1_vec, sPoint, .09, basisColor, lightPosition, e1_label);
    let e2Arrow = new Vector3D(gl, WebGL, e2_vec, sPoint, .09, basisColor, lightPosition, e2_label); 
    let e3Arrow = new Vector3D(gl, WebGL, e3_vec, sPoint, .09, basisColor, lightPosition, e3_label); 
    e3Arrow.setOffsetLabelPosition(8,-20);
    let vArrow = new Vector3D(gl, WebGL, v_vec, sPoint, .09, opaqueColor, lightPosition, v_label); 
    let e3PArrow = new Vector3D(gl, WebGL, s_e3, correct_point, .09, basisColor, lightPosition, e3P_label); 
    e3PArrow.setOffsetLabelPosition(8,0);
    
    let pointFigure =  new Sphere(.1, 30, 30);
    let point = new GeometryPainter(gl, new Diffuse(gl, WebGL, pointFigure), M4.scale(.6,.6,.6));
    //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,0));    
    
    //Lineas
    let p0 = p_in_plane.add(e3_vec.scale(-10));
    let p1 = p_in_plane.add(e3_vec.scale(10));
    let linePE1 = new Line3D(gl, WebGL, p0, p1, sPoint, .022, [0,0,0,1]);
    let lineE1ToSE1 = new Line3D(gl, WebGL, e1_vec, s_e1, sPoint, .025, [0,0,0,1]);
    let lineE2ToSE2 = new Line3D(gl, WebGL, e2_vec, s_e2, sPoint, .025, [0,0,0,1]);
    let lineSE1ToP = new Line3D(gl, WebGL, s_e1, p_in_plane, sPoint, .025, [0,0,0,1]);
    let lineSE2ToP = new Line3D(gl, WebGL, s_e2, p_in_plane, sPoint, .025, [0,0,0,1]);
    s_e1 = sPoint.add(s_e1);
    s_e2 = sPoint.add(s_e2);
    let translateSE1 = M4.translate(s_e1.x, s_e1.y, s_e1.z);
    let translateSE2 = M4.translate(s_e2.x, s_e2.y, s_e2.z);
    let pointVM;

    var fov = 80;
    if(window.innerWidth < window.innerHeight)
        fov = 120;

    let zNear = .1;
    let zFar = 2000;
    let pos = M4.multiplyVector(M4.rotateY(-90), [1.4,.6,2.5,1]);
    let camera = new TrackballCamera(new V3(pos[0],pos[1],pos[2]));
    camera.setZoomConfig(4.5,2.3);
    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);
        s_uniforms.u_light_position = lightPos;
        p_uniforms.u_light_position = lightPos;
    
        e1Arrow.draw(gl, viewMatrix, projectionMatrix, lightPos);
        e2Arrow.draw(gl, viewMatrix, projectionMatrix, lightPos);
        e3Arrow.draw(gl, viewMatrix, projectionMatrix, lightPos);

        let sVM = M4.multiply(viewMatrix, M4.translate(sPoint.x, sPoint.y, sPoint.z));
        point.draw(gl, sVM, projectionMatrix, s_uniforms);
         
        o_label.setPosition(getPixel3DPosition(gl, M4.multiply(projectionMatrix, sVM), -20, 0));
        e3PArrow.hideLabel();
        pP_label.hideLabel();
        v_label.hideLabel();
        px_label.hideLabel();
        py_label.hideLabel();

        if(step <= 1){
            vArrow.draw(gl, viewMatrix, projectionMatrix, lightPos);
        }
        if(step >= 1){
            translatePoint = M4.translate(correct_s_point.x , correct_s_point.y, correct_s_point.z);
            let pointVM = M4.multiply(viewMatrix, translatePoint);
            point.draw(gl, pointVM, projectionMatrix, p_uniforms);
            p_label_pos = getPixel3DPosition(gl, M4.multiply(projectionMatrix, pointVM), 7, -10); 
            p_label.setPosition(p_label_pos);
        }
        if(step >= 3){
            let parallel_s = sPoint.add(p_in_plane.add(e3_vec.scale(.2)));
            if(step == 3)
                e3PArrow.draw(gl, viewMatrix, projectionMatrix, lightPos);
            linePE1.draw(gl, viewMatrix, projectionMatrix);
        }
        if(step >= 4){
            translatePoint = M4.translate(correct_point.x , correct_point.y, correct_point.z);
            pointVM = M4.multiply(viewMatrix, translatePoint);
            point.draw(gl, pointVM, projectionMatrix, p_uniforms);
            p_label_pos = getPixel3DPosition(gl, M4.multiply(projectionMatrix, pointVM), 7, -10);
            pP_label.setPosition(p_label_pos);
        } 
        if(step >= 5){
            lineE1ToSE1.draw(gl, viewMatrix, projectionMatrix);
            lineE2ToSE2.draw(gl, viewMatrix, projectionMatrix);
            lineSE1ToP.draw(gl, viewMatrix, projectionMatrix);
            lineSE2ToP.draw(gl, viewMatrix, projectionMatrix);
            
            pointVM = M4.multiply(viewMatrix, translateSE1);
            p_label_pos = getPixel3DPosition(gl, M4.multiply(projectionMatrix, pointVM), 5, 7);
            px_label.setPosition(p_label_pos);  
            point.draw(gl, pointVM, projectionMatrix, s_uniforms);
            
            pointVM = M4.multiply(viewMatrix, translateSE2);
            p_label_pos = getPixel3DPosition(gl, M4.multiply(projectionMatrix, pointVM), 3, 0);
            py_label.setPosition(p_label_pos);  
            point.draw(gl, pointVM, projectionMatrix, s_uniforms);

        }
        if(step == 6){
            e3PArrow.draw(gl, viewMatrix, projectionMatrix, lightPos);
            vArrow.draw(gl, viewMatrix, projectionMatrix, lightPos);
        }

        plane.draw(gl, viewMatrix, projectionMatrix);
    }

    function upadateStep(button){
        return function(){
            if (step + button < 0 || step + button > 6)
                return;
            step += button;
            buttons[0].updateState(step, 0, 5);
            buttons[1].updateState(step, 1, 6);
            draw(); 
        }
    }
    function reset(){
        step = 0;
        buttons[0].updateState(step, 0, 5);
        buttons[1].updateState(step, 1, 6);
        draw();
    }
}