import * as Core from "@intelligentgraphics/ig.gfx.core";
import { Vector3 as THREEVector3, OrthographicCamera } from "@intelligentgraphics/three";
import { noop } from "@intelligentgraphics/ig.utilities";
import { TouchCollection } from "./touchCollection";
var WHEEL_ZOOM_FACTOR = 0.25;
var PointerHandler = /** @class */ (function () {
    function PointerHandler(scene, options) {
        this.scene = scene;
        this.options = options;
        this.touchCollection = new TouchCollection();
        this.pointerDown = this.pointerDown.bind(this);
        this.pointerMove = this.pointerMove.bind(this);
        this.pointerOut = this.pointerOut.bind(this);
        this.pointerUp = this.pointerUp.bind(this);
        this.mouseWheel = this.mouseWheel.bind(this);
    }
    PointerHandler.prototype.pointerDown = function (event) {
        // add touch to active touch list
        this.touchCollection.handleEvent(event);
        var touch = this.convertEventToTouch(event);
        // there is already an active pointer. just forward this event to the active behaviour
        if (this.activeBehaviour !== undefined) {
            this.activeBehaviour.onPointerDown(event, touch);
            return;
        }
        var persistedEvent = {
            clientX: event.clientX,
            clientY: event.clientY,
            type: event.type,
            pointerId: event.pointerId,
            pointerType: event.pointerType,
            pageX: event.pageX,
            pageY: event.pageY,
            preventDefault: noop,
            stopPropagation: noop,
            button: event.button
        };
        this.clickInfo = {
            timestamp: Date.now(),
            event: persistedEvent,
            pointerIdentifier: event.pointerId,
            touch: touch
        };
    };
    PointerHandler.prototype.pointerMove = function (event) {
        // there was no pointerDown registered since the last pointerUp. nothing should happen.
        if (this.clickInfo === undefined) {
            return;
        }
        // update touch position in active touch list
        this.touchCollection.handleEvent(event);
        var touch = this.convertEventToTouch(event);
        // behaviour has already been detected. we can skip the rest
        if (this.activeBehaviour !== undefined) {
            return this.activeBehaviour.onPointerMove(event, touch);
        }
        var distanceDelta = {
            x: this.clickInfo.event.clientX - event.clientX,
            y: this.clickInfo.event.clientY - event.clientY
        };
        var distanceToStart = Core.Vector.Magnitude2(distanceDelta);
        if (distanceToStart <= 5) {
            return;
        }
        var result = this.detectPointerBehaviour(event, touch);
        if (result === undefined) {
            return;
        }
        this.activeBehaviour = result;
        this.onPointerBehaviourStart(this.activeBehaviour);
        result.onPointerDown(this.clickInfo.event, this.clickInfo.touch);
        result.onPointerMove(event, touch);
    };
    PointerHandler.prototype.pointerUp = function (event) {
        // pointerUp will be triggered when the mouse leaves the canvas area. ensure there has been a pointerDown before processing the event
        if (this.clickInfo === undefined) {
            return;
        }
        // remove touch from active touch list
        this.touchCollection.handleEvent(event);
        var touch = this.convertEventToTouch(event);
        // there is an active behaviour and more than 0 touches active, ignore the rest and forward the event
        if (this.touchCollection.getTouchCount() > 0 &&
            this.activeBehaviour !== undefined) {
            return this.activeBehaviour.onPointerUp(event, touch);
        }
        var clickInfo = this.clickInfo;
        this.clickInfo = undefined;
        this.touchCollection.clear();
        if (this.activeBehaviour !== undefined) {
            this.activeBehaviour.onPointerUp(event, touch);
            this.activeBehaviour = undefined;
            this.onPointerBehaviourEnd();
            return;
        }
        this.handleClick(clickInfo);
    };
    PointerHandler.prototype.pointerOut = function (event) {
        return this.pointerUp(event);
    };
    PointerHandler.prototype.mouseWheel = function (event) {
        var cameraView = this.scene.getActiveCameraView();
        var controls = this.scene.getActiveOrbitControls();
        if (!cameraView) {
            console.log("Mouse Wheel handling: no cameraView is set up");
            return;
        }
        if (!(this.options.zoomToTarget === true ||
            this.options.zoomToTarget === this.getCameraName())) {
            controls.mouseWheel(event);
            return;
        }
        event.preventDefault();
        var delta = event.deltaY;
        var frame = cameraView.settings.viewFrame;
        var mX = ((event.clientX - frame.x) / frame.width) * 2 - 1;
        var mY = (-(event.clientY - frame.y) / frame.height) * 2 + 1;
        var vector = new THREEVector3(mX, mY, 1);
        // pan camera to implement zoom-to-cursor behaviour
        vector.unproject(cameraView.camera);
        vector.sub(cameraView.camera.position);
        var direction = vector.setLength(WHEEL_ZOOM_FACTOR);
        var currentTarget = cameraView.orbitControls.getTargetPoint();
        if (delta > 0) {
            var newPosition = Core.Vector.Sub3(cameraView.camera.position, direction);
            var newTarget = Core.Vector.Sub3(currentTarget, direction);
            cameraView.orbitControls.changeCameraPositionAndTarget(newTarget, newPosition);
        }
        else {
            var newPosition = Core.Vector.Add3(cameraView.camera.position, direction);
            var newTarget = Core.Vector.Add3(currentTarget, direction);
            cameraView.orbitControls.changeCameraPositionAndTarget(newTarget, newPosition);
        }
    };
    PointerHandler.prototype.onPointerBehaviourStart = function (behaviour) { };
    PointerHandler.prototype.onPointerBehaviourEnd = function () { };
    PointerHandler.prototype.getCameraName = function () {
        return this.scene.getActiveCameraView().camera instanceof
            OrthographicCamera
            ? "orthographic"
            : "perspective";
    };
    return PointerHandler;
}());
export { PointerHandler };
