import { Cone, Cylinder } from "./Figure.js";
import Diffuse from "../materials/Diffuse.js";
import GeometryPainter from "./GeometryPainter.js";
import M4 from "../modules/M4.js";
import V3 from "../modules/V3.js";

/**
 * Dibuja un vector 3D representándolo con una flecha 3D.
 * El vector posee dirección y punto inicial. La longitud del vector es tomada 
 * en cuenta como la distancia entre su punto inicial y punto final de la dirección.
 * @author Melissa Méndez Servín.
 */
export default class Vector3D{
    constructor(gl, WebGL, vector, sPoint, radius, color, lightPosition, label=null, middleLabel=true){
        this.vector = vector;
        this.radius = radius;
        this.cone_height = (this.radius * 1.5);
        this.height = 1;
        this.vector = vector || new V3(0,1,0);
        this.sPoint = sPoint || new V3(0,0,0);
        this.base = new V3(0,1,0);
        this.uniforms = { u_color: color, u_light_position: lightPosition};
        let coneFigure = new Cone(this.radius, this.cone_height, 20);
        let cylinderFigure = new Cylinder(this.radius/2.5, 1, 25);
        
        this.arrow = new GeometryPainter(gl, new Diffuse(gl, WebGL, coneFigure, this.uniforms));
        this.body = new GeometryPainter(gl, new Diffuse(gl, WebGL, cylinderFigure, this.uniforms));
        
        this.label = label;
        this.middleLabel = middleLabel;
        this.showLabel = (this.label) ? true : false;
        this.offset_x = (middleLabel) ? -5 : 22;
        this.offset_y = (middleLabel) ? 0 : -25;
    }
    draw(gl,  modelViewMatrix, projectionMatrix, lightPosition, currVector, currSPoint){
        let vector = currVector || this.vector;
        let sPoint = currSPoint || this.sPoint;

        this.uniforms.u_light_position = lightPosition;
        let height = vector.length() - this.cone_height + .02;
        let translateToSPoint = M4.translate(sPoint.x, sPoint.y, sPoint.z);
        let fixHeight = M4.translate(0, height/2, 0);
        
        let axis = this.base.cross(vector).normalize();
        let theta = Math.acos(this.base.dotProduct(vector.normalize()));
        let rotateToVector = M4.rotate(axis, theta);
        //console.log("vector", vector, M4.multiplyVector(rotateToVector, [0,1,0,1]));
        
        let commonTransformation = M4.multiply(translateToSPoint, M4.multiply(rotateToVector, fixHeight));
        
        let transformCylinder = M4.scale(1, height, 1);
        let transformCone = M4.translate(0, height/2 + this.cone_height/2 , 0);

        let modelViewMatrixCylinder = M4.multiply(commonTransformation, transformCylinder); 
        modelViewMatrixCylinder = M4.multiply(modelViewMatrix, modelViewMatrixCylinder);

        let modelViewMatrixCone = M4.multiply(commonTransformation, transformCone); 
        modelViewMatrixCone = M4.multiply(modelViewMatrix, modelViewMatrixCone);

        this.body.draw(gl, modelViewMatrixCylinder, projectionMatrix, this.uniforms);  
        this.arrow.draw(gl, modelViewMatrixCone, projectionMatrix, this.uniforms);  
        
        if(this.showLabel){
            let PMV_Matrix = (this.middleLabel) ? M4.multiply(projectionMatrix, modelViewMatrixCylinder) :
                                                  M4.multiply(projectionMatrix, modelViewMatrixCone);
            let sign; 
            if(this.middleLabel)
                sign = 1;
            else    
                sign = (vector.x > 0 ) ? .5 : -1;
            let coords = this.getPixelPosition(gl, PMV_Matrix, sign);
            this.label.setPosition(coords);
        }
    }
    hideLabel(){
        this.showLabel = true;
        this.label.setPosition({left:-100, top: -100});
    }
    setOffsetLabelPosition(x,y){
        this.offset_x = x;
        this.offset_y = y;
    }
    getPixelPosition(gl, PMV_Matrix, dir){
        //var position = sPoint.add(vector).toArray();
        let width = gl.canvas.clientWidth;
        let height = gl.canvas.clientHeight
        var NDCCoords = M4.multiplyVector(PMV_Matrix, [0,0,0,1]);
        var coords = { left: (NDCCoords[0]/NDCCoords[3] * 0.5 + 0.5) * width + dir*this.offset_x,
                       top: (NDCCoords[1]/NDCCoords[3] * -0.5 + 0.5) * height + this.offset_y,
                       type: "px"};
        //console.log(coords, width, height);
        return coords;
    }
}