"use strict";

import {addLabel, Checkbox, createResetButton, resize, resizeAndCenterX, scaleToFitContainer, Select} 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 GeometryPainter from "../../../geometry/GeometryPainter.js";
import {Patch, PatchCP, Sphere} from "../../../geometry/Figure.js";
import {TrackballCamera, registerCameraEvents} from "../../../modules/Trackballcamera.js";
import V3 from "../../../modules/V3.js";

/**
 * Ejemplo de parches de Bézier aletorios y planos de grado [1,4]x[1,4].
 * @author Melissa Méndez Servín.
 */
window.addEventListener("load", main);
function main(){
    var canvas = document.getElementById("gl_canvas");
    var gl = WebGL.init(canvas);
    if(!gl) return;
    //Dimensiones
    let m = 5;
    let n = 4;
    let isPlane = false;

    //HTML CONTROLS
    let check_controls = document.getElementById("ui-container-up");
    let checkboxCP = new Checkbox(check_controls, "control_points", "Puntos de Control", draw, true);
    let checkboxSurfacePoints = new Checkbox(check_controls, "surface_points", "Puntos en el parche", draw, true);
    let checkboxSurface = new Checkbox(check_controls, "surface", "Parche de Bézier", draw, true);
    let checkboxPlane = new Checkbox(check_controls, "surface_plane", "Plano", drawCurrentSurface, false);
    let button = createResetButton(newSurface, false, "Otra");

    /* Selects */
    let dimension = { 1: 2, 2:3, 3:4, 4:5};
    let controls = document.getElementById("ui-container");
    controls.className = "right-box";
    addLabel(controls, "m");
    let selectM = new Select(controls, "dimension", setDimension(0),  dimension, m-1);
    addLabel(controls, "n");
    let selectN = new Select(controls, "dimension", setDimension(1),  dimension, n-1);

    //Figuras
    let sphereFigure = new Sphere(.035, 10, 10);
    let smallSphereFigure = new Sphere(.03, 10, 10);
    //Colors 
    const POINTS_IN_SURFACE = [1,0,1,1];//[.35,.45,.65,1]//[0.165, 0.47, 0.525, 1];
    const SURFACE = [0.1,.4,1,.65];//[0.4, 0.55, 0.6, 0.65]
    //Colores y luz
    let lightPosition = [2, 3, 3, 0];
    let diffuseUniforms = { u_light_position: lightPosition };
    let uniform = {u_color: [0,0,0,1]};
    let uniform_spoints = {u_color: POINTS_IN_SURFACE};
    let uniform_s = {u_color: SURFACE}; 
    //Puntos
    let transform = M4.translate(0.2,-0.1,0);
    let controlPoints = new GeometryPainter(gl, new Diffuse(gl, WebGL, sphereFigure, uniform), transform);
    let surfacePoints = new GeometryPainter(gl, new Diffuse(gl, WebGL, smallSphereFigure, uniform_spoints), transform);
    
    //Superficie
    let patchFigure = new PatchCP(m,n, isPlane);
    let control_points = patchFigure.getVertices();
    let surfaceFigure = new Patch(m, n, control_points);
    let surface_vertices = surfaceFigure.getVertices();

    let wireframeCP = new GeometryPainter(gl, new SolidColor(gl, WebGL, patchFigure, [0,0,0,1]), transform);
    let surface = new GeometryPainter(gl, new Diffuse(gl, WebGL, surfaceFigure, uniform_s), transform);
    surfaceFigure.quads = true; //Red
    let surfaceWireframe = new GeometryPainter(gl, new SolidColor(gl, WebGL, surfaceFigure, POINTS_IN_SURFACE), transform);

    let lastSurface = { w_CP : wireframeCP, surface: surface, w_surface: surfaceWireframe, 
                        control_points: control_points, surface_vertices: surface_vertices};

    //Superficie plana
    let planePatchFigure = new PatchCP(m, n, true);
    let plane_cpoints = planePatchFigure.getVertices();
    let planeSurfaceFigure = new Patch(m,n, plane_cpoints);
    let surface_vertices_plane = planeSurfaceFigure.getVertices();

    let planeWireframeCP = new GeometryPainter(gl, new SolidColor(gl, WebGL, planePatchFigure, [0,0,0,1]), transform);
    planeSurfaceFigure.quads = false; //Surface
    let planeSurface = new GeometryPainter(gl, new Diffuse(gl, WebGL, planeSurfaceFigure, uniform_s), transform);
    planeSurfaceFigure.quads = true; //Red
    let planeSurfaceWireframe = new GeometryPainter(gl, new SolidColor(gl, WebGL, planeSurfaceFigure, [1,0,1,1]), transform);
    
    var fov = 80;
    if(window.innerWidth < window.innerHeight)
        fov = 120;

    let zNear = .1;
    let zFar = 100;
    let pos = M4.multiplyVector(M4.rotateY(20),[0,1.5,3.55,1]);
    let camera = new TrackballCamera(new V3(pos[0], pos[1], pos[2]));
    camera.setZoomConfig(5,2.5);
    
    resize(canvas);
      
    gl.enable(gl.DEPTH_TEST);
    //Transparecia
    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
    gl.clearColor(0, 0, 0, 0);

    window.addEventListener('resize', draw);
    registerCameraEvents(camera, canvas, draw);
    
    draw();
    
    function draw(){   
        resizeAndCenterX(check_controls, {top: 0});
        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;
        
        if(checkboxCP.checked()){
            wireframeCP.drawWireframeQuad(gl, viewMatrix, projectionMatrix);   
            for(var i = 0; i < n*m*3; i+=3){
                let translate = M4.translate(control_points[i],control_points[i+1],control_points[i+2]);
                controlPoints.draw(gl, M4.multiply(viewMatrix, translate), projectionMatrix, diffuseUniforms);    
            }
        }
        if(checkboxSurfacePoints.checked()){
            surfaceWireframe.drawWireframeQuad(gl, viewMatrix, projectionMatrix);   
            for(var i = 0; i < surface_vertices.length; i+=3){
                let translate = M4.translate(surface_vertices[i],surface_vertices[i+1],surface_vertices[i+2]);
                surfacePoints.draw(gl, M4.multiply(viewMatrix, translate), projectionMatrix, diffuseUniforms);    
            }
        }
        if(checkboxSurface.checked())
            surface.draw(gl, viewMatrix, projectionMatrix, diffuseUniforms);    
    }
    function setDimension(index){
        return function(value){
            if(index == 0)
                m = dimension[value];
            else
                n = dimension[value];
            newSurface();
        }
    }
    function drawCurrentSurface(){
       if(checkboxPlane.checked()){
            wireframeCP = planeWireframeCP;
            surface = planeSurface;
            surfaceWireframe = planeSurfaceWireframe;
            control_points = plane_cpoints;
            surface_vertices = surface_vertices_plane;

       }else{
            wireframeCP = lastSurface.w_CP;
            surface = lastSurface.surface;
            surfaceWireframe = lastSurface.w_surface;
            control_points = lastSurface.control_points;
            surface_vertices = lastSurface.surface_vertices;
       }
       draw();
    }
    function newSurface(){
        patchFigure = new PatchCP(m,n, isPlane);
        patchFigure.setDim(m,n); 
        control_points = patchFigure.getVertices();
        surfaceFigure = new Patch(m, n, control_points);
        surface_vertices = surfaceFigure.getVertices();
        surface_vertices = surfaceFigure.getVertices();
        
        wireframeCP = new GeometryPainter(gl, new SolidColor(gl, WebGL, patchFigure, [0,0,0,1]), transform);
        surfaceFigure.quads = false; //Surface
        surface = new GeometryPainter(gl, new Diffuse(gl, WebGL, surfaceFigure, uniform_s), transform);
        surfaceFigure.quads = true; //Red
        surfaceWireframe = new GeometryPainter(gl, new SolidColor(gl, WebGL, surfaceFigure, POINTS_IN_SURFACE), transform);
        
        lastSurface = { w_CP : wireframeCP, surface: surface, w_surface: surfaceWireframe, 
                        control_points: control_points, surface_vertices: surface_vertices};
        draw();
    }
}