// #region Imports
import { emit, on } from '@breadstone/mosaik-elements';
import { ControllerBase } from './Abstracts/ControllerBase';
/**
 * Controller to recognized when two or more pointers are moving toward (zoom-in) or away from each other (zoom-out).
 *
 * @public
 */
export class PinchController extends ControllerBase {
    // #region Fields
    _pointerMap;
    _active;
    _startDistance;
    _currentDistance;
    _scale = 1;
    _pointerDownEventListenerSubscription;
    _pointerMoveEventListenerSubscription;
    _pointerUpEventListenerSubscription;
    _pointerCancelEventListenerSubscription;
    _lastScale = 1;
    // #endregion
    // #region Ctor
    /**
     * Constructs a new instance of the `PinchController` class.
     *
     * @public
     */
    constructor(host) {
        super(host);
        this._pointerMap = new Map();
        this._active = false;
        this._startDistance = 0;
        this._currentDistance = 0;
        this._scale = 1;
        this._pointerDownEventListenerSubscription = null;
        this._pointerMoveEventListenerSubscription = null;
        this._pointerUpEventListenerSubscription = null;
        this._pointerCancelEventListenerSubscription = null;
        this._lastScale = 1;
    }
    // #endregion
    // #region Methods
    hostConnected() {
        this._pointerDownEventListenerSubscription = on(this.host, 'pointerdown', this.onPointerDown.bind(this));
        this._pointerMoveEventListenerSubscription = on(this.host, 'pointermove', this.onPointerMove.bind(this));
        this._pointerUpEventListenerSubscription = on(this.host, 'pointerup', this.onPointerUp.bind(this));
        this._pointerCancelEventListenerSubscription = on(this.host, 'pointercancel', this.onPointerCancel.bind(this));
    }
    hostDisconnected() {
        this._pointerDownEventListenerSubscription?.dispose();
        this._pointerMoveEventListenerSubscription?.dispose();
        this._pointerUpEventListenerSubscription?.dispose();
        this._pointerCancelEventListenerSubscription?.dispose();
    }
    onPointerDown(event) {
        this._pointerMap.set(event.pointerId, event);
        if (this._pointerMap.size === 2 && !this._active) {
            const [p1, p2] = Array.from(this._pointerMap.values());
            this._startDistance = this.getDistance(p1, p2);
            this._currentDistance = this._startDistance;
            this._scale = 1;
            this._lastScale = 1;
            this._active = true;
            emit(this.host, 'pinchstart', {
                distance: this._startDistance,
                scale: this._scale
            });
        }
    }
    onPointerMove(event) {
        if (!this._pointerMap.has(event.pointerId))
            return;
        this._pointerMap.set(event.pointerId, event);
        if (this._active && this._pointerMap.size === 2) {
            const [p1, p2] = Array.from(this._pointerMap.values());
            this._currentDistance = this.getDistance(p1, p2);
            this._scale = this._currentDistance / this._startDistance;
            emit(this.host, 'pinchmove', {
                distance: this._currentDistance,
                scale: this._scale
            });
            // Pinchin / Pinchout events
            if (this._scale < this._lastScale) {
                emit(this.host, 'pinchin', {
                    distance: this._currentDistance,
                    scale: this._scale
                });
            }
            else if (this._scale > this._lastScale) {
                emit(this.host, 'pinchout', {
                    distance: this._currentDistance,
                    scale: this._scale
                });
            }
            this._lastScale = this._scale;
        }
    }
    onPointerUp(event) {
        this._pointerMap.delete(event.pointerId);
        if (this._active) {
            emit(this.host, 'pinchend', {
                distance: this._currentDistance,
                scale: this._scale
            });
            this._active = false;
            this._startDistance = 0;
            this._currentDistance = 0;
            this._scale = 1;
            this._lastScale = 1;
        }
    }
    onPointerCancel(event) {
        this._pointerMap.delete(event.pointerId);
        if (this._active) {
            emit(this.host, 'pinchcancel', {
                distance: this._currentDistance,
                scale: this._scale
            });
            this._active = false;
            this._startDistance = 0;
            this._currentDistance = 0;
            this._scale = 1;
            this._lastScale = 1;
        }
    }
    getDistance(p1, p2) {
        const dx = p2.clientX - p1.clientX;
        const dy = p2.clientY - p1.clientY;
        return Math.hypot(dx, dy);
    }
}
//# sourceMappingURL=PinchController.js.map