import { resize, MathBox, InputElement, MatrixElement, scaleToFitContainer} from "../../../modules/HTMLUtils.js";
import WebGL from "../../../modules/WebGLUtils.js";
import Figure2D from "../../../geometry/Figure2D.js";
import V2 from "../../../modules/V2.js";
import M3 from "../../../modules/M3.js";
import Vector2D from "../../../geometry/Vector2D.js";
import * as MV from "../../../modules/MouseEvents.js";

/**
 * Manipulación de puntos de un cuadrado utilizando matrices.
 * @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;
    resize(canvas);
    let controls = document.getElementById("ui-container");

    const unit = 65;   
    
    //Límites de la proyección
    let projectionLimits = { l: -.5, r: .5, t: .4, b: -.6};
    //Ejes
    const axesColor = [141, 141, 141, 200];
    var x = new Vector2D(gl, WebGL, new V2(-1, 0), new V2(2,0), unit, 1.2, axesColor);
    var y = new Vector2D(gl, WebGL, new V2(0,-1), new V2(0,2), unit, 1.2, axesColor);
    //Paralelogramo
    const areaColor = [102, 149, 238, 255];
    const opaqueAreaColor = [175, 196, 210, 235];
    var rparams = { sPoint: new V2(-.5,-.5), width: 1, height: 1};
    var paralellogram = new Figure2D(gl, WebGL, 'rect', unit, areaColor, rparams);
    var staticParalellogram = new Figure2D(gl, WebGL, 'rect', unit, opaqueAreaColor, rparams);
    //Colores de los vértices
    const yellowColor = [255, 215, 0, 255];
    const redColor = [255, 0, 0, 255];
    const greenColor = [34, 139, 34, 255];
    const purpleColor = [148, 0, 211, 255];
    const colors = [ yellowColor, redColor, greenColor, purpleColor];
    const opaqueColors = [ [255, 245, 20, 255], [232, 105, 105, 235], [105, 184, 105, 235],
                           [184, 135, 205, 235]];
    //Vértices
    var points = [ new V2(-.5, .5), new V2(.5, .5), new V2(-.5,-.5), new V2(.5, -.5)];
    let vertices = [];
    let staticVertices = [];
    for(var i = 0; i < 4; i++){
        var params = {center: points[i], r: 0.1, numPoints: 10};
        vertices.push(new Figure2D(gl, WebGL, 'circle', unit, colors[i], params));
        staticVertices.push(new Figure2D(gl, WebGL, 'circle', unit, opaqueColors[i], params));
    }

    //Etiquetas
    let nameM = new MathBox(controls, {top: 0, left: 32}, "\\mathbf{M}", "font-size");
    let nameP = new MathBox(controls, {top: 0, left: 56}, "\\mathbf{P}", "font-size");
    let namePPrime = new MathBox(controls, {top: 0, left: 70.5}, "\\mathbf{P'}", "font-size");
    let times = new MathBox(controls, {top: 36, left: 47.5}, "\\times", "symbol");
    let equals = new MathBox(controls, {top: 36, left: 62.5}, "=", "symbol");
    
    //Elementos de las  matrices
    let matrixA = document.getElementById("a-matrix");
    let matrixB = document.getElementById("b-matrix");
    let matrixAB = document.getElementById("ab-matrix");
    let m = []; 
    let p = [];
    var vector = ['x','y','z'];
    var vectorPrime = ["x'", "y'", "z'"];

    for(var i= 0; i< 6; i++){
        if( i == 0 || i == 4)
            m.push(new InputElement(matrixA, "element input", 1, draw));
        else
            m.push(new InputElement(matrixA, "element input", 0, draw));
    }
    for(var i = 0; i < 3; i++){
        var num = (i < 2) ? 0 : 1; 
        m.push(new MatrixElement(matrixA, "element a-ele", num));
        p.push(new MatrixElement(matrixB, "element", vector[i]));
    }

    let pPrime = [];
    for(var i = 0; i < 3; i++)
        pPrime.push(new MatrixElement(matrixAB, "element ab-ele", vectorPrime[i]));

    //Constructores auxiliares para  el manejador de eventos con el ratón
    const radiusRegion = 0.15;
    let mousePointers = [];
    for(var i = 0; i < 4; i++)
        mousePointers.push(new MV.MousePointer(gl, points[i], radiusRegion, unit, projectionLimits));
    var cparams = { center: points[0], r: radiusRegion, thickness: 0.05, numPoints: 10};
    let region = new Figure2D(gl, WebGL, 'circumference', unit, [21, 67, 96, 255], cparams);
    let position = new V2(50,60);
    //Transparecia
    gl.clearColor(0, 0, 0, 0);
    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
    draw();
    
    MV.registerMousePointerEvents(canvas, mousePointers, draw);
    window.addEventListener('resize', draw);
    
    function draw(){
        resize(canvas);
        scaleToFitContainer(controls, position);
        gl.depthMask(true);
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
        
        const {width, height} = gl.canvas;
        gl.viewport(0, 0, width, height);
        var projectionMatrix = M3.projection(projectionLimits.l * width, 
                                             projectionLimits.r * width, 
                                             projectionLimits.t * height, 
                                             projectionLimits.b * height);

                                             
        y.draw(gl, projectionMatrix);
        x.draw(gl, projectionMatrix);
        var model = [m[0].ele.value, m[1].ele.value, m[2].ele.value, 
                      m[3].ele.value, m[4].ele.value, m[5].ele.value];
        
        var modelMatrix = M3.createMatrix(model);
        staticParalellogram.draw(gl, M3.identity(), projectionMatrix);
        for(var i = 0; i < 4; i++)
            staticVertices[i].draw(gl, M3.identity(), projectionMatrix);
        paralellogram.draw(gl, modelMatrix, projectionMatrix);
        
        var showRegion = false;
        for(var i = 0; i < 4; i++){
            var center = [points[i].x, points[i].y, 1];
            var modelVector = M3.multiplyVector(modelMatrix, center);
            mousePointers[i].vector = new V2(modelVector[0], modelVector[1]);
            //Dibujamos los vértices
            vertices[i].draw(gl, M3.identity(), projectionMatrix, mousePointers[i].vector);
            if(mousePointers[i].isInRegion){
                showRegion = true;
                region.draw(gl, M3.identity(), projectionMatrix, mousePointers[i].vector);
                multiply(pPrime, modelVector);
                multiply(p, center);
                for(var j= 0; j < 3; j++){ //Pintamos los elementos de la columna de P
                    p[j].ele.setAttribute("selectedB", "true");
                    pPrime[j].ele.setAttribute("selectedB", "true");
                }
            }
        }
        if(!showRegion){
            multiply(p, vector);
            multiply(pPrime, vectorPrime);
            for(var j= 0; j <3; j++){ //Despintamos los elementos de la columna de P
                p[j].ele.setAttribute("selectedB", "false");
                pPrime[j].ele.setAttribute("selectedB", "false");
            }
        }
    }
    /**
     * Multiplica las matrices M (compuesta de elementos HTML) y el vector dado v, 
     * con M de dimensión 3x3 y v el vector 3x1.
     * Devuelve un arreglo de constructores con los atributos num 
     * (resultado asociado al elemento) o bien la tripleta 
     * ["x'", "y'", "z'"] para cuando no se selecciones algún punto, es decir, 
     * v = ['x', 'y', 'z'].
     * @param {*} v vector  
     */
    function multiply(htmlVector, v){
        var isNum = (v[0][0] != 'x') ? true : false;
        for(var i= 0; i < 3; i++){ 
            var ab_ij = 0;
            if(isNum)
                for(var j = 0; j <3; j++){
                    var m_ele = (m[3* i + j].num == undefined) ?  m[3* i + j].value : m[3* i + j].num;
                    ab_ij += m_ele * v[j];
                }
            else
                ab_ij = vectorPrime[i];
            htmlVector[i].setNum(ab_ij);
        }
    }
}