import M4 from "./M4.js";
import V3 from "./V3.js";
import {cos, sin} from "./MathUtils.js";
import {getMousePositionInCanvas, getTouchPositionInCanvas} from "./InputEventsHandler.js";

/**
 * Clase auxiliar para el manejo de la cámara con el ratón.
 * @author Melissa Méndez Servín.
 */
class TrackballCamera{
    constructor(pos, target, up, init=true){
        this.pos = pos || new V3(0,0,1);
        this.target = target || new V3(0,0,0);
        this.up = up || new V3(0,1,0);
        
        this.radius = this.pos.distance(this.target);
        let direction = this.pos.sub(this.target);
        this.min_zoom = undefined;
        this.max_zoom = undefined;

        this.theta = Math.atan2(direction.z, direction.x);
        this.phi = Math.atan2(direction.y, direction.z);
        this.zoom = false;
        if(init)
            this.rotatePosition({x:0,y:0}, {x:0,y:0});
        //console.log("dir", direction);
        //console.log(this.pos, "phi " + this.phi, "theta "+ this.theta);
        this.init_pos = pos || new V3(0,0,1);
    }
    setZoomConfig(zoom_out, zoom_in, delta=0.1){
        this.zoom = true;
        this.min_zoom = zoom_out;
        this.max_zoom = zoom_in;
        this.deltaZoom = delta;
    }
    getMatrix(){
        return M4.camera(this.pos, this.target, this.up);
    }

    getAngles(initialPosition, currentPosition){
        let theta = this.theta + (currentPosition.x - initialPosition.x)/100;
        let phi = Math.min(
                    Math.max(
                        this.phi   + (currentPosition.y - initialPosition.y)/100,
                        -(Math.PI/2-0.1)
                        ),
                        Math.PI/2-0.1
                    );
                
        return { theta : theta,
                 phi   : phi
        };
    }
    rotatePosition(initialPosition, currentPosition){
        let angles = this.getAngles(initialPosition, currentPosition);
        this.pos =  new V3(
                        this.radius * cos(angles.phi) * cos(angles.theta), 
                        this.radius * sin(angles.phi), 
                        this.radius * cos(angles.phi) * sin(angles.theta)
        );
        //console.log(this.pos, "phi " + this.phi, "theta "+ this.theta);
    }
    updateAngles(initialPosition, currentPosition) {
        let angles = this.getAngles(initialPosition, currentPosition);
        this.theta = angles.theta;
        this.phi   = angles.phi;
    }
    resetInitialPosition(){
        this.pos = this.init_pos;
        let direction = this.pos.sub(this.target);

        this.theta = Math.atan2(direction.z, direction.x);
        this.phi = Math.atan2(direction.y, direction.z);

        this.rotatePosition({x:0,y:0}, {x:0,y:0});
    }
}

function registerCameraEvents(camera, canvas, draw_callback){
    let initialPosition = null;
    if(((window.hasOwnProperty) && (window.hasOwnProperty("ontouchstart"))) || ("ontouchstart" in window)){
        console.log("TOUCH");
        //camera.radius +=2;
        let passiveIfSupported = false;
        try {
        window.addEventListener("test", null,
            Object.defineProperty(
            {},
            "passive",
            {
                get: function() { passiveIfSupported = { passive: true }; }
            }
            )
        );
        } catch(err) {}
     
        canvas.addEventListener("touchstart", (evt) => {
            if(passiveIfSupported == false)
                evt.preventDefault();
            initialPosition = getTouchPositionInCanvas(evt, canvas);
            canvas.addEventListener("touchmove", touchMove, passiveIfSupported);
        },  passiveIfSupported);
    
        window.addEventListener("touchend", (evt) => {
            if(passiveIfSupported == false)
                evt.preventDefault();
            camera.updateAngles(initialPosition, getTouchPositionInCanvas(evt, canvas));
            canvas.removeEventListener("touchmove", touchMove);
            initialPosition = null;
        }, false);
    }
    else{
        canvas.addEventListener("mousedown", (evt) => {
            initialPosition = getMousePositionInCanvas(evt, canvas);
            canvas.addEventListener("mousemove", mouseMove);
        });

        window.addEventListener("mouseup", (evt) => {
            if (initialPosition) {
                camera.updateAngles(initialPosition, getMousePositionInCanvas(evt, canvas));
                canvas.removeEventListener("mousemove", mouseMove);
                initialPosition = null;
            }
        });
    }
    function mouseMove(evt) {
        camera.rotatePosition(initialPosition, getMousePositionInCanvas(evt, canvas));
        draw_callback();
    } 
    function touchMove(evt) {
        camera.rotatePosition(initialPosition, getTouchPositionInCanvas(evt, canvas));
        draw_callback();
    } 
    canvas.addEventListener('wheel', zoom, {passive: true});
    function zoom(evt){
        //event.preventDefault();
        if(!camera.zoom) return;
        
        var deltaY = (evt.deltaY > 50) ? evt.deltaY/100 : evt.deltaY; 
        let new_radius = camera.radius + (deltaY * camera.deltaZoom);
        camera.radius = Math.min(Math.max(camera.max_zoom, new_radius), camera.min_zoom);
        camera.rotatePosition({x:0, y:0}, {x:0, y:0});
        draw_callback();
    }
}
export{
    TrackballCamera, 
    registerCameraEvents
}

/*if(((window.hasOwnProperty) && (window.hasOwnProperty("ontouchstart"))) || ("ontouchstart" in window)){
    console.log("TOUCH");
    let passiveIfSupported = false;
    try {
    window.addEventListener("test", null,
        Object.defineProperty(
        {},
        "passive",
        {
            get: function() { passiveIfSupported = { passive: true }; }
        }
        )
    );
    } catch(err) {}

    canvas.addEventListener("touchstart", (evt) => {
        if(passiveIfSupported == false)
            evt.preventDefault();
        initialPosition = getTouchPositionInCanvas(evt, canvas);
        canvas.addEventListener("touchmove", touchMove, passiveIfSupported);
    },  passiveIfSupported);

    window.addEventListener("touchend", (evt) => {
        if(passiveIfSupported == false)
            evt.preventDefault();
        if (initialPosition) {
            camera.upadetAngles(initialPosition, getTouchPositionInCanvas(evt, canvas));
            canvas.removeEventListener("mousemove", touchMove);
            initialPosition = null;
        }
        canvas.removeEventListener("touchmove", touchMove);
    }, false);
    function touchMove(evt) {
        if(passiveIfSupported == false)
            evt.preventDefault();
        camera.rotatePosition(initialPosition, getMousePositionInCanvas(evt, canvas));
        draw_callback();
    }
}else{*/
