import { AppObjectEntity, getSingletonComponent, MemoizedBoolean, ParametricLine, Vector3, } from "@vived/core";
import { Transform3D } from "../../Transform3D";
export class StylusEntity extends AppObjectEntity {
    static get(appObjects) {
        return getSingletonComponent(StylusEntity.type, appObjects);
    }
}
StylusEntity.type = "StylusEntity";
StylusEntity.clickMovementThreshold = 0.32;
StylusEntity.clickTimeThresholdMS = 350;
export function makeStylusEntity(appObj) {
    return new StylusImp(appObj);
}
class StylusImp extends StylusEntity {
    get pickRay() {
        return ParametricLine.FromPointDirection(this.transform.worldPosition, this.transform.localDirectionToWorld(Vector3.Forward()));
    }
    get isInUse() {
        return this.memoizedIsInUse.val;
    }
    checkIfStylusIsInUse(worldMatrix) {
        const m = worldMatrix.m;
        if (m[1] === 0 &&
            m[2] === 0 &&
            m[3] === 0 &&
            m[4] === 0 &&
            m[7] === 0 &&
            m[8] === 0 &&
            m[11] === 0 &&
            m[12] === 0 &&
            m[15] === 1) {
            this.memoizedIsInUse.val = false;
        }
        else {
            this.memoizedIsInUse.val = true;
        }
    }
    constructor(appObject) {
        super(appObject, StylusEntity.type);
        this.controllers = [];
        this.buttonStates = [false, false, false];
        this.pressPosition = Vector3.Zero();
        this.pressTime = 0;
        this.registerController = (controller) => {
            this.controllers.push(controller);
        };
        this.updateButtonState = (button, isPressed) => {
            if (this.buttonStates[button] === isPressed)
                return;
            this.controllers.forEach((controller) => {
                if (isPressed) {
                    if (controller.onButtonDown) {
                        controller.onButtonDown(button);
                    }
                    this.lassPressedButton = button;
                    this.pressPosition = this.transform.localPosition;
                    this.pressTime = Date.now();
                }
                else {
                    if (controller.onButtonUp) {
                        controller.onButtonUp(button);
                    }
                    if (this.isClick(button) && controller.onButtonClick) {
                        controller.onButtonClick(button);
                    }
                }
            });
            this.buttonStates[button] = isPressed;
            this.notifyOnChange();
        };
        this.getButtonState = (button) => {
            if (button < 0 || button >= this.buttonStates.length) {
                return false;
            }
            else {
                return this.buttonStates[button];
            }
        };
        this.isClick = (button) => {
            const buttonIsCorrect = button === this.lassPressedButton;
            const movement = Vector3.Subtract(this.transform.localPosition, this.pressPosition).magnitude;
            const movementIsSmallEnough = movement < StylusEntity.clickMovementThreshold;
            const passedTime = Date.now() - this.pressTime;
            const pressTimeIsShortEnough = passedTime < StylusEntity.clickTimeThresholdMS;
            if (buttonIsCorrect && movementIsSmallEnough && pressTimeIsShortEnough) {
                return true;
            }
            else {
                return false;
            }
        };
        this.onTransformUpdate = () => {
            this.checkIfStylusIsInUse(this.transform.worldMatrix);
            this.controllers.forEach((controller) => {
                if (controller.onStylusMove) {
                    controller.onStylusMove(this.transform);
                }
            });
            this.notifyOnChange();
        };
        this.memoizedIsInUse = new MemoizedBoolean(false, this.notifyOnChange);
        this.transform = Transform3D.addIfMissing(appObject);
        this.transform.addChangeObserver(this.onTransformUpdate);
    }
}
//# sourceMappingURL=StylusEntity.js.map