import { AppObjectEntity, getSingletonComponent } from "@vived/core";
import { Vector2 } from "@vived/core";
export class MouseInputEntity extends AppObjectEntity {
}
MouseInputEntity.type = "MouseInputEntity";
MouseInputEntity.get = (appObjects) => getSingletonComponent(MouseInputEntity.type, appObjects);
export function makeMouseInput(appObject) {
    return new MouseInputEntityImp(appObject);
}
class MouseInputEntityImp extends MouseInputEntity {
    get eventElement() {
        return this._eventElement;
    }
    makeMouseInputEvent(event) {
        const px = event.offsetX;
        const py = event.offsetY;
        const button = event.button;
        return {
            position: new Vector2(px, py),
            button,
            event,
        };
    }
    constructor(appObject) {
        super(appObject, MouseInputEntity.type);
        this.controllers = [];
        this.maxClickMovement = 5; // pixels
        this.isPressed = false;
        this.initialClickTime = 0;
        this.initialClickPos = Vector2.Zero();
        this.clickCount = 0;
        this.maxDoubleClickTimeMS = 300;
        this.maxDoubleClickDistancePx = 5;
        this._eventElement = undefined;
        this.setEventElement = (eventElement) => {
            if (this._eventElement)
                this.clearInputElement();
            eventElement.addEventListener("mousedown", this.onMouseDown, false);
            eventElement.addEventListener("mouseup", this.onMouseUp, false);
            eventElement.addEventListener("mousemove", this.onMouseMove, false);
            eventElement.addEventListener("mouseout", this.onMouseOut, false);
            eventElement.addEventListener("wheel", this.onWheel, false);
            this._eventElement = eventElement;
        };
        this.clearInputElement = () => {
            if (!this._eventElement)
                return;
            this._eventElement.removeEventListener("mousedown", this.onMouseDown);
            this._eventElement.removeEventListener("mouseup", this.onMouseUp);
            this._eventElement.removeEventListener("mousemove", this.onMouseMove);
            this._eventElement.removeEventListener("mouseout", this.onMouseOut);
            this._eventElement.removeEventListener("wheel", this.onWheel);
            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);
            }
        };
        this.onMouseDown = (e) => {
            const inputEvt = this.makeMouseInputEvent(e);
            this.controllers.forEach((c) => {
                if (c.onDown) {
                    c.onDown(inputEvt);
                }
            });
            this.isPressed = true;
            this.pressEvent = e;
            if (this.clickCount === 0)
                return;
            const movement = Vector2.Subtract(this.initialClickPos, inputEvt.position)
                .magnitued;
            const passedTime = Date.now() - this.initialClickTime;
            if (passedTime > this.maxDoubleClickTimeMS ||
                movement > this.maxDoubleClickDistancePx) {
                this.clickCount = 0;
            }
        };
        this.onMouseUp = (e) => {
            const inputEvt = this.makeMouseInputEvent(e);
            this.controllers.forEach((c) => {
                if (c.onUp) {
                    c.onUp(inputEvt);
                }
            });
            this.isPressed = false;
            if (!this.pressEvent)
                return;
            const deltaX = this.pressEvent.screenX - e.screenX;
            const deltaY = this.pressEvent.screenY - e.screenY;
            const delta = new Vector2(deltaX, deltaY);
            if (delta.magnitued < this.maxClickMovement) {
                this.controllers.forEach((c) => {
                    if (c.onClick) {
                        c.onClick(inputEvt);
                    }
                });
                this.clickCount += 1;
            }
            else {
                this.cancelDoubleClick();
                return;
            }
            if (this.clickCount === 1) {
                this.initialClickTime = Date.now();
                this.initialClickPos = new Vector2(this.pressEvent.screenX, this.pressEvent.screenY);
            }
            else if (this.clickCount === 2) {
                const currentPos = new Vector2(this.pressEvent.screenX, this.pressEvent.screenY);
                let movement = Vector2.Subtract(this.initialClickPos, currentPos)
                    .magnitued;
                if (isNaN(movement)) {
                    movement = 0;
                }
                const passedTime = Date.now() - this.initialClickTime;
                if (passedTime <= this.maxDoubleClickTimeMS &&
                    movement <= this.maxDoubleClickDistancePx) {
                    this.controllers.forEach((c) => {
                        if (c.onDoubleClick) {
                            c.onDoubleClick(inputEvt);
                        }
                    });
                    this.cancelDoubleClick();
                }
            }
            this.pressEvent = undefined;
        };
        this.cancelDoubleClick = () => {
            this.initialClickPos = Vector2.Zero();
            this.initialClickTime = 0;
            this.clickCount = 0;
        };
        this.onMouseMove = (e) => {
            const inputEvt = this.makeMouseInputEvent(e);
            this.controllers.forEach((c) => {
                if (c.onMove) {
                    c.onMove(inputEvt);
                }
            });
            if (!this.pressEvent)
                return;
            const deltaX = this.pressEvent.screenX - e.screenX;
            const deltaY = this.pressEvent.screenY - e.screenY;
            const delta = new Vector2(deltaX, deltaY);
            if (delta.magnitued > this.maxClickMovement) {
                this.pressEvent = undefined;
            }
        };
        this.onMouseOut = (e) => {
            this.cancelDoubleClick();
            if (!this.isPressed)
                return;
            const inputEvt = this.makeMouseInputEvent(e);
            this.controllers.forEach((c) => {
                if (c.onUp) {
                    c.onUp(inputEvt);
                }
            });
            this.pressEvent = undefined;
            this.isPressed = false;
        };
        this.onWheel = (e) => {
            e.preventDefault();
            const px = e.offsetX;
            const py = e.offsetY;
            const button = e.button;
            const inputEvt = {
                position: new Vector2(px, py),
                event: e,
            };
            this.controllers.forEach((c) => {
                if (c.onWheel) {
                    c.onWheel(inputEvt);
                }
            });
        };
    }
}
//# sourceMappingURL=MouseInput.js.map