import { getSingletonComponent } from "@vived/core";
import { AppObjectEntity } from "@vived/core";
import { Vector2 } from "@vived/core";
export class TouchInputEntity extends AppObjectEntity {
}
TouchInputEntity.type = "TouchInputEntity";
TouchInputEntity.get = (appObjects) => getSingletonComponent(TouchInputEntity.type, appObjects);
export function makeTouchInput(appObject) {
    return new TouchInputImp(appObject);
}
class TouchInputImp extends TouchInputEntity {
    get eventElement() {
        return this._eventElement;
    }
    createTouchInputEvent(event) {
        const touches = [];
        const touchCount = event.touches.length;
        let minX = 0;
        let maxX = 0;
        let minY = 0;
        let maxY = 0;
        for (let i = 0; i < touchCount; i++) {
            const touch = event.touches[i];
            const position = this.getTouchOffsetPosition(touch);
            touches.push({
                id: touch.identifier,
                touch,
                position,
            });
            if (i === 0) {
                minX = position.x;
                maxX = position.x;
                minY = position.y;
                maxY = position.y;
            }
            else {
                minX = Math.min(minX, position.x);
                maxX = Math.max(maxX, position.x);
                minY = Math.min(minY, position.y);
                maxY = Math.max(maxY, position.y);
            }
        }
        let cntX = 0;
        let cntY = 0;
        if (touchCount === 1) {
            cntX = maxX;
            cntY = maxY;
        }
        else {
            cntX = minX + (maxX - minX) / 2;
            cntY = minY + (maxY - minY) / 2;
        }
        return {
            touchCenter: new Vector2(cntX, cntY),
            touchCount,
            touches,
            event,
        };
    }
    constructor(appObject) {
        super(appObject, TouchInputEntity.type);
        this.controllers = [];
        this._eventElement = undefined;
        this.updateInputElementBounds = () => {
            if (!this._eventElement)
                return;
            this.eventElementBounds = this._eventElement.getBoundingClientRect(); // Expensive so we cache
        };
        this.getTouchOffsetPosition = (touch) => {
            if (!this.eventElementBounds) {
                console.warn("No target bounds");
                return Vector2.Zero();
            }
            const x = touch.clientX - this.eventElementBounds.x;
            const y = touch.clientY - this.eventElementBounds.y;
            return new Vector2(x, y);
        };
        this.setEventElement = (eventElement) => {
            if (this._eventElement)
                this.clearInputElement();
            eventElement.addEventListener("touchstart", this.onTouchStart, false);
            eventElement.addEventListener("touchmove", this.onTouchMove, false);
            eventElement.addEventListener("touchend", this.onTouchEnd, false);
            eventElement.addEventListener("touchcancel", this.onTouchCancel, false);
            this.eventElementBounds = eventElement.getBoundingClientRect();
            this._eventElement = eventElement;
        };
        this.considerTap = false;
        this.tapStartPosition = Vector2.Zero();
        this.maxTapDistancePx = 5;
        this.onTouchStart = (e) => {
            if (e.cancelable)
                e.preventDefault();
            const touchInput = this.createTouchInputEvent(e);
            this.controllers.forEach((c) => {
                if (c.onTouchStart) {
                    c.onTouchStart(touchInput);
                }
            });
            if (touchInput.touchCount === 1) {
                this.considerTap = true;
                this.tapStartPosition = touchInput.touchCenter;
                this.tapEvent = touchInput;
            }
            else {
                this.cancelTap();
            }
        };
        this.cancelTap = () => {
            this.considerTap = false;
            this.tapStartPosition = Vector2.Zero();
            this.tapEvent = undefined;
        };
        this.onTouchMove = (e) => {
            if (e.cancelable)
                e.preventDefault();
            const touchInput = this.createTouchInputEvent(e);
            this.controllers.forEach((c) => {
                if (c.onTouchMove) {
                    c.onTouchMove(touchInput);
                }
            });
            if (!this.considerTap)
                return;
            if (touchInput.touchCount !== 1) {
                this.cancelTap();
            }
            const movement = Vector2.Subtract(this.tapStartPosition, touchInput.touchCenter).magnitued;
            if (movement > this.maxTapDistancePx) {
                this.cancelTap();
            }
        };
        this.onTouchEnd = (e) => {
            if (e.cancelable)
                e.preventDefault();
            const touchInput = this.createTouchInputEvent(e);
            this.controllers.forEach((c) => {
                if (c.onTouchEnd) {
                    c.onTouchEnd(touchInput);
                }
            });
            if (!this.considerTap || !this.tapEvent)
                return;
            this.controllers.forEach((c) => {
                if (c.onTap) {
                    c.onTap(this.tapEvent);
                }
            });
            this.cancelTap();
        };
        this.onTouchCancel = (e) => {
            if (e.cancelable)
                e.preventDefault();
            const touchInput = this.createTouchInputEvent(e);
            this.controllers.forEach((c) => {
                if (c.onTouchCancel) {
                    c.onTouchCancel(touchInput);
                }
            });
            this.cancelTap();
        };
        this.clearInputElement = () => {
            if (!this._eventElement)
                return;
            this._eventElement.removeEventListener("touchstart", this.onTouchStart);
            this._eventElement.removeEventListener("touchmove", this.onTouchMove);
            this._eventElement.removeEventListener("touchend", this.onTouchEnd);
            this._eventElement.removeEventListener("touchcancel", this.onTouchCancel);
            this._eventElement = undefined;
        };
        this.registerController = (controller) => {
            this.controllers.push(controller);
        };
        this.removeController = (controller) => {
            const index = this.controllers.indexOf(controller);
            if (index >= 0) {
                this.controllers.splice(index, 1);
            }
        };
    }
}
//# sourceMappingURL=TouchInput.js.map