import { BridgedCameraSource } from "./bridged-camera-source";
import { anchor_status_t, plane_orientation_t, world_scale_mode_t } from "./gen/zappar";
import { Pipeline } from "./pipeline";
const _emptyUint8Array = new Uint8Array(0);
export class BridgedWorldTracker {
    constructor() {
        this._latestId = 1;
        this._wtStateById = new Map();
        this._anchorStateById = new Map();
        this._identityPose = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
        this._emptyArray = new Float32Array([]);
        this.impl = {
            world_tracker_create: (pipeline) => {
                let p = Pipeline.get(pipeline);
                if (!p)
                    throw new Error("Invalid pipeline in world_tracker_create");
                let newId = (this._latestId++);
                let s = {
                    pipeline: p,
                    enabled: true,
                    horizontal_plane_detection_enabled: true,
                    vertical_plane_detection_enabled: false,
                    world_anchor_id: 'world',
                    ground_anchor_id: 'ground',
                    tracks_data_enabled: false,
                    projections_data_enabled: false,
                    mesh_anchors_enabled: false
                };
                this._wtStateById.set(newId, s);
                this._notifyOptionsUpdated(s.pipeline);
                return newId;
            },
            world_tracker_destroy: (o) => {
                let s = this._getWtState(o);
                this._wtStateById.delete(o);
            },
            world_tracker_enabled: (o) => {
                let s = this._getWtState(o);
                return s.enabled;
            },
            world_tracker_enabled_set: (o, enabled) => {
                let s = this._getWtState(o);
                s.enabled = enabled;
                this._notifyOptionsUpdated(s.pipeline);
            },
            world_tracker_session_number: (o) => {
                let wtData = this._getWtData(o);
                let s = wtData === null || wtData === void 0 ? void 0 : wtData.session_number;
                if (s === undefined)
                    return 0;
                return s;
            },
            world_tracker_quality: (o) => {
                let wtData = this._getWtData(o);
                if (!wtData)
                    return 3;
                return wtData.quality;
            },
            world_tracker_horizontal_plane_detection_enabled: (o) => {
                let s = this._getWtState(o);
                return s.horizontal_plane_detection_enabled;
            },
            world_tracker_horizontal_plane_detection_enabled_set: (o, enabled) => {
                let s = this._getWtState(o);
                s.horizontal_plane_detection_enabled = enabled;
                this._notifyOptionsUpdated(s.pipeline);
            },
            world_tracker_vertical_plane_detection_enabled: (o) => {
                let s = this._getWtState(o);
                return s.vertical_plane_detection_enabled;
            },
            world_tracker_vertical_plane_detection_enabled_set: (o, enabled) => {
                let s = this._getWtState(o);
                s.vertical_plane_detection_enabled = enabled;
                this._notifyOptionsUpdated(s.pipeline);
            },
            world_tracker_plane_anchor_count: (o) => {
                let wtData = this._getWtData(o);
                let plane_anchors = wtData === null || wtData === void 0 ? void 0 : wtData.plane_anchors;
                if (!plane_anchors)
                    return 0;
                return plane_anchors.length;
            },
            world_tracker_plane_anchor_id: (o, indx) => {
                var _a, _b, _c;
                let wtData = this._getWtData(o);
                return (_c = (_b = (_a = wtData === null || wtData === void 0 ? void 0 : wtData.plane_anchors) === null || _a === void 0 ? void 0 : _a[indx]) === null || _b === void 0 ? void 0 : _b.id) !== null && _c !== void 0 ? _c : "";
            },
            world_tracker_plane_anchor_pose_raw: (o, indx) => {
                var _a, _b;
                let wtData = this._getWtData(o);
                let pose = (_b = (_a = wtData === null || wtData === void 0 ? void 0 : wtData.plane_anchors) === null || _a === void 0 ? void 0 : _a[indx]) === null || _b === void 0 ? void 0 : _b.pose;
                if (pose === undefined)
                    return this._identityPose;
                if (Array.isArray(pose)) {
                    pose = new Float32Array(pose);
                    wtData.plane_anchors[indx].pose = pose;
                }
                return pose;
            },
            world_tracker_plane_anchor_status: (o, indx) => {
                var _a, _b, _c, _d;
                return (_d = (_c = (_b = (_a = this._getWtData(o)) === null || _a === void 0 ? void 0 : _a.plane_anchors) === null || _b === void 0 ? void 0 : _b[indx]) === null || _c === void 0 ? void 0 : _c.status) !== null && _d !== void 0 ? _d : anchor_status_t.ANCHOR_STATUS_STOPPED;
            },
            world_tracker_plane_anchor_polygon_data_size: (o, indx) => {
                var _a, _b, _c, _d, _e;
                return (_e = (_d = (_c = (_b = (_a = this._getWtData(o)) === null || _a === void 0 ? void 0 : _a.plane_anchors) === null || _b === void 0 ? void 0 : _b[indx]) === null || _c === void 0 ? void 0 : _c.boundary) === null || _d === void 0 ? void 0 : _d.length) !== null && _e !== void 0 ? _e : 0;
            },
            world_tracker_plane_anchor_polygon_data: (o, indx) => {
                var _a, _b, _c;
                let boundary = (_c = (_b = (_a = this._getWtData(o)) === null || _a === void 0 ? void 0 : _a.plane_anchors) === null || _b === void 0 ? void 0 : _b[indx]) === null || _c === void 0 ? void 0 : _c.boundary;
                if (!boundary)
                    return this._emptyArray;
                if (Array.isArray(boundary)) {
                    boundary = new Float32Array(boundary);
                    this._getWtData(o).plane_anchors[indx].boundary = boundary;
                }
                return boundary;
            },
            world_tracker_plane_anchor_polygon_version: (o, indx) => {
                var _a, _b, _c, _d;
                return (_d = (_c = (_b = (_a = this._getWtData(o)) === null || _a === void 0 ? void 0 : _a.plane_anchors) === null || _b === void 0 ? void 0 : _b[indx]) === null || _c === void 0 ? void 0 : _c.boundaryVersion) !== null && _d !== void 0 ? _d : 0;
            },
            world_tracker_plane_anchor_orientation: (o, indx) => {
                var _a, _b, _c, _d;
                return ((_d = (_c = (_b = (_a = this._getWtData(o)) === null || _a === void 0 ? void 0 : _a.plane_anchors) === null || _b === void 0 ? void 0 : _b[indx]) === null || _c === void 0 ? void 0 : _c.horizontal) !== null && _d !== void 0 ? _d : true) ? plane_orientation_t.PLANE_ORIENTATION_HORIZONTAL : plane_orientation_t.PLANE_ORIENTATION_VERTICAL;
            },
            world_tracker_world_anchor_status: (o) => {
                var _a, _b;
                return (_b = (_a = this._getWtData(o)) === null || _a === void 0 ? void 0 : _a.world_anchor_status) !== null && _b !== void 0 ? _b : anchor_status_t.ANCHOR_STATUS_INITIALIZING;
            },
            world_tracker_world_anchor_id: (o) => {
                let s = this._getWtState(o);
                return s.world_anchor_id;
            },
            world_tracker_world_anchor_pose_raw: (o) => {
                let wtData = this._getWtData(o);
                let pose = wtData === null || wtData === void 0 ? void 0 : wtData.world_anchor_pose;
                if (pose === undefined)
                    return this._identityPose;
                if (Array.isArray(pose)) {
                    pose = new Float32Array(pose);
                    wtData.world_anchor_pose = pose;
                }
                return pose;
            },
            world_tracker_ground_anchor_status: (o) => {
                var _a, _b;
                return (_b = (_a = this._getWtData(o)) === null || _a === void 0 ? void 0 : _a.ground_anchor_status) !== null && _b !== void 0 ? _b : anchor_status_t.ANCHOR_STATUS_INITIALIZING;
            },
            world_tracker_ground_anchor_id: (o) => {
                let s = this._getWtState(o);
                return s.ground_anchor_id;
            },
            world_tracker_ground_anchor_pose_raw: (o) => {
                let wtData = this._getWtData(o);
                let pose = wtData === null || wtData === void 0 ? void 0 : wtData.ground_anchor_pose;
                if (pose === undefined)
                    return this._identityPose;
                if (Array.isArray(pose)) {
                    pose = new Float32Array(pose);
                    wtData.ground_anchor_pose = pose;
                }
                return pose;
            },
            world_tracker_reset: (o) => {
                let s = this._getWtState(o);
                let source = s.pipeline.currentCameraSource;
                if (source instanceof BridgedCameraSource) {
                    source.resetTracking();
                }
            },
            world_tracker_tracks_data_enabled: (o) => {
                let s = this._getWtState(o);
                return s.tracks_data_enabled;
            },
            world_tracker_tracks_data_enabled_set: (o, tracks_data_enabled) => {
                let s = this._getWtState(o);
                s.tracks_data_enabled = tracks_data_enabled;
                this._notifyOptionsUpdated(s.pipeline);
            },
            world_tracker_tracks_data_size: (o) => {
                // Stub
                let s = this._getWtState(o);
                return 0;
            },
            world_tracker_tracks_data: (o) => {
                // Stub
                let s = this._getWtState(o);
                return this._emptyArray;
            },
            world_tracker_tracks_type_data_size: (o) => {
                // Stub
                let s = this._getWtState(o);
                return 0;
            },
            world_tracker_tracks_type_data: (o) => {
                // Stub
                return _emptyUint8Array;
            },
            world_tracker_projections_data_enabled: (o) => {
                let s = this._getWtState(o);
                return s.projections_data_enabled;
            },
            world_tracker_projections_data_enabled_set: (o, projections_data_enabled) => {
                let s = this._getWtState(o);
                s.projections_data_enabled = projections_data_enabled;
                this._notifyOptionsUpdated(s.pipeline);
            },
            world_tracker_projections_data_size: (o) => {
                // Stub
                let s = this._getWtState(o);
                return 0;
            },
            world_tracker_projections_data: (o) => {
                // Stub
                let s = this._getWtState(o);
                return this._emptyArray;
            },
            world_tracker_scale_mode_set: (o, mode) => {
                // Stub - no-op
            },
            world_tracker_scale_mode: (o) => {
                // Stub - no-op
                return world_scale_mode_t.DEFAULT;
            },
            // #### custom_anchor ####
            custom_anchor_create: (pipeline, worldtracker, id) => {
                let newId = (this._latestId++);
                let wtState = this._getWtState(worldtracker);
                let s = {
                    pipeline: wtState.pipeline,
                    wt: worldtracker,
                    pose_version: 0,
                    anchor_id: id,
                };
                this._anchorStateById.set(newId, s);
                return newId;
            },
            custom_anchor_destroy: (o) => {
                let s = this._getAnchorState(o);
                this._anchorStateById.delete(o);
            },
            custom_anchor_status: (o) => {
                var _a, _b;
                let s = this._getAnchorState(o);
                let wtData = this._getWtDataFromPipeline(s.pipeline);
                const anchorData = ((_a = wtData === null || wtData === void 0 ? void 0 : wtData.custom_anchors) !== null && _a !== void 0 ? _a : []).find(entry => entry.id === o);
                return (_b = anchorData === null || anchorData === void 0 ? void 0 : anchorData.status) !== null && _b !== void 0 ? _b : anchor_status_t.ANCHOR_STATUS_INITIALIZING;
            },
            custom_anchor_pose_version: (o) => {
                var _a, _b;
                let s = this._getAnchorState(o);
                let wtData = this._getWtDataFromPipeline(s.pipeline);
                const anchorData = ((_a = wtData === null || wtData === void 0 ? void 0 : wtData.custom_anchors) !== null && _a !== void 0 ? _a : []).find(entry => entry.id === o);
                return (_b = anchorData === null || anchorData === void 0 ? void 0 : anchorData.poseVersion) !== null && _b !== void 0 ? _b : -1;
            },
            custom_anchor_pose_raw: (o) => {
                var _a;
                let s = this._getAnchorState(o);
                let wtData = this._getWtDataFromPipeline(s.pipeline);
                const anchorData = ((_a = wtData === null || wtData === void 0 ? void 0 : wtData.custom_anchors) !== null && _a !== void 0 ? _a : []).find(entry => entry.id === o);
                if (!anchorData)
                    return this._identityPose;
                let pose = anchorData === null || anchorData === void 0 ? void 0 : anchorData.pose;
                if (pose === undefined)
                    return this._identityPose;
                if (Array.isArray(pose)) {
                    pose = new Float32Array(pose);
                    anchorData.pose = pose;
                }
                return pose;
            },
            custom_anchor_pose_set: (o, pose) => {
                var _a, _b;
                let s = this._getAnchorState(o);
                s.pose_version++;
                let source = (_b = (_a = s.pipeline) === null || _a === void 0 ? void 0 : _a.getCurrentCameraInfo()) === null || _b === void 0 ? void 0 : _b.cameraSource;
                if (source instanceof BridgedCameraSource) {
                    source.setCustomAnchorPose(o, s.pose_version, pose);
                }
            },
            custom_anchor_pose_set_with_parent: (o, pose, anchor_id) => {
                var _a, _b;
                (_b = (_a = this.impl).custom_anchor_pose_set) === null || _b === void 0 ? void 0 : _b.call(_a, o, pose);
            },
            world_tracker_mesh_anchor_count: o => {
                var _a, _b;
                const data = this._getWtData(o);
                return (_b = (_a = data === null || data === void 0 ? void 0 : data.mesh_anchors) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
            },
            world_tracker_mesh_anchor_id: (o, indx) => {
                var _a, _b, _c;
                const data = this._getWtData(o);
                return (_c = (_b = (_a = data === null || data === void 0 ? void 0 : data.mesh_anchors) === null || _a === void 0 ? void 0 : _a[indx]) === null || _b === void 0 ? void 0 : _b.id) !== null && _c !== void 0 ? _c : "";
            },
            world_tracker_mesh_anchor_indices: (o, indx) => {
                var _a, _b;
                const data = this._getWtData(o);
                const { binaryLength, binaryOffset } = (_b = (_a = data === null || data === void 0 ? void 0 : data.mesh_anchors) === null || _a === void 0 ? void 0 : _a[indx]) === null || _b === void 0 ? void 0 : _b.indices;
                if (binaryLength === undefined || binaryOffset === undefined)
                    return new Uint32Array();
                const frameData = this._getFrameData(o);
                if (!frameData)
                    return new Uint32Array();
                return frameData.uint32ArrayForBinaryBufferOffset(binaryOffset, binaryLength);
            },
            world_tracker_mesh_anchor_indices_count: (o, indx) => {
                var _a, _b, _c;
                const data = this._getWtData(o);
                return (_c = (_b = (_a = data === null || data === void 0 ? void 0 : data.mesh_anchors) === null || _a === void 0 ? void 0 : _a[indx]) === null || _b === void 0 ? void 0 : _b.indices.count) !== null && _c !== void 0 ? _c : 0;
            },
            world_tracker_mesh_anchor_indices_size: (o, indx) => {
                var _a, _b, _c;
                return (_c = (_b = (_a = this.impl).world_tracker_mesh_anchor_indices) === null || _b === void 0 ? void 0 : _b.call(_a, o, indx).byteLength) !== null && _c !== void 0 ? _c : 0;
            },
            world_tracker_mesh_anchor_vertices: (o, indx) => {
                var _a, _b;
                const data = this._getWtData(o);
                const { binaryLength, binaryOffset } = (_b = (_a = data === null || data === void 0 ? void 0 : data.mesh_anchors) === null || _a === void 0 ? void 0 : _a[indx]) === null || _b === void 0 ? void 0 : _b.vertices;
                if (binaryLength === undefined || binaryOffset === undefined)
                    return new Float32Array();
                const frameData = this._getFrameData(o);
                if (!frameData)
                    return new Float32Array();
                return frameData.floatArrayForBinaryBufferOffset(binaryOffset, binaryLength);
            },
            world_tracker_mesh_anchor_vertices_count: (o, indx) => {
                var _a, _b, _c;
                const data = this._getWtData(o);
                return (_c = (_b = (_a = data === null || data === void 0 ? void 0 : data.mesh_anchors) === null || _a === void 0 ? void 0 : _a[indx]) === null || _b === void 0 ? void 0 : _b.vertices.count) !== null && _c !== void 0 ? _c : 0;
            },
            world_tracker_mesh_anchor_vertices_size: (o, indx) => {
                var _a, _b, _c;
                return (_c = (_b = (_a = this.impl).world_tracker_mesh_anchor_vertices) === null || _b === void 0 ? void 0 : _b.call(_a, o, indx).byteLength) !== null && _c !== void 0 ? _c : 0;
            },
            world_tracker_mesh_anchor_vertices_offset: (o, indx) => {
                var _a, _b, _c;
                const data = this._getWtData(o);
                return (_c = (_b = (_a = data === null || data === void 0 ? void 0 : data.mesh_anchors) === null || _a === void 0 ? void 0 : _a[indx]) === null || _b === void 0 ? void 0 : _b.vertices.offset) !== null && _c !== void 0 ? _c : 0;
            },
            world_tracker_mesh_anchor_vertices_stride: (o, indx) => {
                var _a, _b, _c;
                const data = this._getWtData(o);
                return (_c = (_b = (_a = data === null || data === void 0 ? void 0 : data.mesh_anchors) === null || _a === void 0 ? void 0 : _a[indx]) === null || _b === void 0 ? void 0 : _b.vertices.stride) !== null && _c !== void 0 ? _c : 0;
            },
            world_tracker_mesh_anchor_pose_raw: (o, indx) => {
                var _a, _b;
                let wtData = this._getWtData(o);
                let pose = (_b = (_a = wtData === null || wtData === void 0 ? void 0 : wtData.mesh_anchors) === null || _a === void 0 ? void 0 : _a[indx]) === null || _b === void 0 ? void 0 : _b.pose;
                if (pose === undefined)
                    return this._identityPose;
                if (Array.isArray(pose)) {
                    pose = new Float32Array(pose);
                    wtData.mesh_anchors[indx].pose = pose;
                }
                return pose;
            },
            world_tracker_mesh_anchor_status: (o, indx) => {
                var _a, _b, _c;
                const data = this._getWtData(o);
                return (_c = (_b = (_a = data === null || data === void 0 ? void 0 : data.mesh_anchors) === null || _a === void 0 ? void 0 : _a[indx]) === null || _b === void 0 ? void 0 : _b.status) !== null && _c !== void 0 ? _c : anchor_status_t.ANCHOR_STATUS_STOPPED;
            },
            world_tracker_mesh_anchors_enabled: (o) => {
                let s = this._getWtState(o);
                return s.mesh_anchors_enabled;
            },
            world_tracker_mesh_anchors_enabled_set: (o, enabled) => {
                let s = this._getWtState(o);
                s.mesh_anchors_enabled = enabled;
                this._notifyOptionsUpdated(s.pipeline);
            },
        };
    }
    static IsSupported() {
        return BridgedCameraSource.IsSupported();
    }
    static SharedInstance() {
        if (!this._sharedInstance) {
            this._sharedInstance = new BridgedWorldTracker();
        }
        return this._sharedInstance;
    }
    _getWtState(o) {
        let s = this._wtStateById.get(o);
        if (!s)
            throw new Error("This object has been destroyed");
        return s;
    }
    _getAnchorState(o) {
        let s = this._anchorStateById.get(o);
        if (!s)
            throw new Error("This object has been destroyed");
        return s;
    }
    _getWtDataFromPipeline(p) {
        var _a, _b, _c;
        return (_c = (_b = (_a = p === null || p === void 0 ? void 0 : p.getCurrentCameraInfo()) === null || _a === void 0 ? void 0 : _a.cameraSourceData) === null || _b === void 0 ? void 0 : _b.frameInfo) === null || _c === void 0 ? void 0 : _c.wtData;
    }
    _getWtData(o) {
        let s = this._getWtState(o);
        return this._getWtDataFromPipeline(s.pipeline);
    }
    _getFrameData(o) {
        var _a, _b, _c;
        let s = this._getWtState(o);
        return (_c = (_b = (_a = s === null || s === void 0 ? void 0 : s.pipeline) === null || _a === void 0 ? void 0 : _a.getCurrentCameraInfo()) === null || _b === void 0 ? void 0 : _b.cameraSourceData) === null || _c === void 0 ? void 0 : _c.frameData;
    }
    _notifyOptionsUpdated(p) {
        if (p.currentCameraSource instanceof BridgedCameraSource) {
            p.currentCameraSource.optionsUpdated(this.getCombinedOptionsForPipeline(p));
        }
    }
    getCombinedOptionsForPipeline(p) {
        const options = {};
        for (let state of this._wtStateById.values()) {
            if (state.pipeline != p)
                continue;
            if (!state.enabled)
                continue;
            options.worldTracking = true;
            if (state.horizontal_plane_detection_enabled)
                options.horizontalPlaneDetection = true;
            if (state.vertical_plane_detection_enabled)
                options.verticalPlaneDetection = true;
            if (state.tracks_data_enabled)
                options.tracksData = true;
            if (state.projections_data_enabled)
                options.projectionsData = true;
            if (state.mesh_anchors_enabled)
                options.meshAnchors = true;
        }
        return options;
    }
}
BridgedWorldTracker._sharedInstance = null;
