var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { Component, Emitter } from '@wonderlandengine/api';
import { property } from '@wonderlandengine/api/decorators.js';
import { setXRRigidTransformLocal } from './utils/webxr.js';
var tempVec3 = new Float32Array(3);
var tempQuat = new Float32Array(4);
/**
 * Sets the location of the object to the location of an XRAnchor
 *
 * Create anchors using the `Anchor.create()` static function.
 *
 * Example for use with cursor:
 * ```js
 * cursorTarget.onClick.add((object, cursor, originalEvent) => {
 *     /* Only events in XR will have a frame attached *\/
 *     if(!originalEvent.frame) return;
 *     Anchor.create(anchorObject, {uuid: id, persist: true}, originalEvent.frame);
 * });
 * ```
 */
class Anchor extends Component {
    static TypeName = 'anchor';
    /* Static management of all anchors */
    static #anchors = [];
    persist = false;
    /** Unique identifier to load a persistent anchor from, or empty/null if unknown */
    uuid = null;
    /** The xrAnchor, if created */
    xrAnchor = null;
    /** Emits events when the anchor is created either by being restored or newly created */
    onCreate = new Emitter();
    /** Whether the anchor is currently being tracked */
    visible = false;
    /** Emits an event when this anchor starts tracking */
    onTrackingFound = new Emitter();
    /** Emits an event when this anchor stops tracking */
    onTrackingLost = new Emitter();
    /** XRFrame to use for creating the anchor */
    xrFrame = null;
    /** XRHitTestResult to use for creating the anchor */
    xrHitResult = null;
    /** Retrieve all anchors of the current scene */
    static getAllAnchors() {
        return Anchor.#anchors;
    }
    static #addAnchor(anchor) {
        Anchor.#anchors.push(anchor);
    }
    static #removeAnchor(anchor) {
        const index = Anchor.#anchors.indexOf(anchor);
        if (index < 0)
            return;
        Anchor.#anchors.splice(index, 1);
    }
    /**
     * Create a new anchor
     *
     * @param o Object to attach the component to
     * @param params Parameters for the anchor component
     * @param frame XRFrame to use for anchor cration, if null, will use the current frame if available
     * @param hitResult Optional hit-test result to create the anchor with
     * @returns Promise for the newly created anchor component
     */
    static create(o, params, frame, hitResult) {
        const a = o.addComponent(Anchor, { ...params, active: false });
        if (a === null)
            return null;
        a.xrHitResult = hitResult ?? null;
        a.xrFrame = frame ?? null;
        a.onCreate.once(() => ((a.xrFrame = null), (a.xrHitResult = null)));
        a.active = true;
        return a.onCreate.promise();
    }
    #getFrame() {
        return this.xrFrame || this.engine.xr.frame;
    }
    async #createAnchor() {
        if (!this.#getFrame().createAnchor) {
            throw new Error("Cannot create anchor - anchors not supported, did you enable the 'anchors' WebXR feature?");
        }
        if (this.xrHitResult) {
            if (this.xrHitResult.createAnchor === undefined) {
                throw new Error('Requested anchor on XRHitTestResult, but WebXR hit-test feature is not available.');
            }
            return this.xrHitResult.createAnchor();
        }
        else {
            this.object.getTranslationWorld(tempVec3);
            tempQuat.set(this.object.rotationWorld);
            const rotation = tempQuat;
            const anchorPose = new XRRigidTransform({ x: tempVec3[0], y: tempVec3[1], z: tempVec3[2] }, { x: rotation[0], y: rotation[1], z: rotation[2], w: rotation[3] });
            return this.#getFrame()?.createAnchor(anchorPose, this.engine.xr.currentReferenceSpace);
        }
    }
    #onAddAnchor(anchor) {
        if (!anchor)
            return;
        if (this.persist) {
            if (anchor.requestPersistentHandle !== undefined) {
                anchor.requestPersistentHandle().then((uuid) => {
                    this.uuid = uuid;
                    this.#onCreate(anchor);
                    Anchor.#addAnchor(this);
                });
                return;
            }
            else {
                console.warn('anchor: Persistent anchors are not supported by your client. Ignoring persist property.');
            }
        }
        this.#onCreate(anchor);
    }
    #onRestoreAnchor(anchor) {
        this.#onCreate(anchor);
    }
    #onCreate(anchor) {
        this.xrAnchor = anchor;
        this.onCreate.notify(this);
    }
    start() {
        if (this.uuid && this.engine.xr) {
            this.persist = true;
            if (this.engine.xr.session.restorePersistentAnchor === undefined) {
                console.warn('anchor: Persistent anchors are not supported by your client. Ignoring persist property.');
            }
            this.engine.xr.session.restorePersistentAnchor(this.uuid).then(this.#onRestoreAnchor.bind(this));
        }
        else if (this.#getFrame()) {
            this.#createAnchor().then(this.#onAddAnchor.bind(this));
        }
        else {
            throw new Error('Anchors can only be created during the XR frame in an active XR session');
        }
    }
    update() {
        if (!this.xrAnchor || !this.engine.xr)
            return;
        /* We need to use the actual frame from the draw callback here */
        const pose = this.engine.xr.frame.getPose(this.xrAnchor.anchorSpace, this.engine.xr.currentReferenceSpace);
        const visible = !!pose;
        if (visible != this.visible) {
            this.visible = visible;
            (visible ? this.onTrackingFound : this.onTrackingLost).notify(this);
        }
        if (pose) {
            setXRRigidTransformLocal(this.object, pose.transform);
        }
    }
    onDestroy() {
        Anchor.#removeAnchor(this);
    }
}
__decorate([
    property.bool(false)
], Anchor.prototype, "persist", void 0);
__decorate([
    property.string()
], Anchor.prototype, "uuid", void 0);
export { Anchor };
//# sourceMappingURL=anchor.js.map