import { Vec2 } from '../../../core/math/vec2.js';
import { InputSource } from '../input.js';

const tmpVa = new Vec2();
class MultiTouchSource extends InputSource {
		constructor(){
				super({
						touch: [
								0,
								0
						],
						count: [
								0
						],
						pinch: [
								0
						]
				}), this._pointerEvents = new Map(), this._pointerPos = new Vec2(), this._pinchDist = -1;
				this._onPointerDown = this._onPointerDown.bind(this);
				this._onPointerMove = this._onPointerMove.bind(this);
				this._onPointerUp = this._onPointerUp.bind(this);
				this._onContextMenu = this._onContextMenu.bind(this);
		}
		_onPointerDown(event) {
				const { pointerId, pointerType } = event;
				if (pointerType !== 'touch') {
						return;
				}
				this._element?.setPointerCapture(pointerId);
				this._pointerEvents.set(pointerId, event);
				this.deltas.count.append([
						1
				]);
				if (this._pointerEvents.size > 1) {
						this._getMidPoint(this._pointerPos);
						this._pinchDist = this._getPinchDist();
				}
		}
		_onPointerMove(event) {
				const { pointerType, target, pointerId, movementX, movementY } = event;
				if (pointerType !== 'touch') {
						return;
				}
				if (target !== this._element) {
						return;
				}
				if (this._pointerEvents.size === 0) {
						return;
				}
				this._pointerEvents.set(pointerId, event);
				if (this._pointerEvents.size > 1) {
						const mid = this._getMidPoint(tmpVa);
						this.deltas.touch.append([
								mid.x - this._pointerPos.x,
								mid.y - this._pointerPos.y
						]);
						this._pointerPos.copy(mid);
						const pinchDist = this._getPinchDist();
						if (this._pinchDist > 0) {
								this.deltas.pinch.append([
										this._pinchDist - pinchDist
								]);
						}
						this._pinchDist = pinchDist;
				} else {
						this.deltas.touch.append([
								movementX,
								movementY
						]);
				}
		}
		_onPointerUp(event) {
				const { pointerType, pointerId } = event;
				if (pointerType !== 'touch') {
						return;
				}
				this._element?.releasePointerCapture(pointerId);
				this._pointerEvents.delete(pointerId);
				this.deltas.count.append([
						-1
				]);
				if (this._pointerEvents.size < 2) {
						this._pinchDist = -1;
				}
				this._pointerPos.set(0, 0);
		}
		_onContextMenu(event) {
				event.preventDefault();
		}
		_getMidPoint(out) {
				if (this._pointerEvents.size < 2) {
						return out.set(0, 0);
				}
				const [a, b] = this._pointerEvents.values();
				const dx = a.clientX - b.clientX;
				const dy = a.clientY - b.clientY;
				return out.set(b.clientX + dx * 0.5, b.clientY + dy * 0.5);
		}
		_getPinchDist() {
				if (this._pointerEvents.size < 2) {
						return 0;
				}
				const [a, b] = this._pointerEvents.values();
				const dx = a.clientX - b.clientX;
				const dy = a.clientY - b.clientY;
				return Math.sqrt(dx * dx + dy * dy);
		}
		attach(element) {
				super.attach(element);
				this._element = element;
				this._element.addEventListener('pointerdown', this._onPointerDown);
				this._element.addEventListener('pointermove', this._onPointerMove);
				this._element.addEventListener('pointerup', this._onPointerUp);
				this._element.addEventListener('pointercancel', this._onPointerUp);
				this._element.addEventListener('contextmenu', this._onContextMenu);
		}
		detach() {
				if (!this._element) {
						return;
				}
				this._element.removeEventListener('pointerdown', this._onPointerDown);
				this._element.removeEventListener('pointermove', this._onPointerMove);
				this._element.removeEventListener('pointerup', this._onPointerUp);
				this._element.removeEventListener('pointercancel', this._onPointerUp);
				this._element.removeEventListener('contextmenu', this._onContextMenu);
				this._pointerEvents.clear();
				super.detach();
		}
}

export { MultiTouchSource };
