/*!
 * Copyright (c) 2026 Vertex Software LLC. All rights reserved.
 */
import { r as registerInstance, h, H as Host, a as getElement } from './index-EpnuuCxl.js';
import { t as translatePointToRelative, P as PinModel, a as PinController } from './model-C-U1XF3h.js';
import { p as point } from './bundle-DfdVaPrt.js';
import { b as uuid } from './bundle-DLfw87TV.js';
import { l as labelPinCursor, p as pinCursor } from './cursors-DImFnILd.js';
import { g as getMouseClientPosition } from './dom-D6my8OyX.js';
import { E as ElementRectObserver } from './elementRectObserver-CFus3r7d.js';
import { E as EntityType } from './entities-BAhfr1Nx.js';
import { g as getMarkupBoundingClientRect } from './dom-Bg-uS9BH.js';
import './_commonjsHelpers-CG9AChtV.js';

class PinsInteractionHandler {
    get elementRect() {
        return this.rectObserver.rect;
    }
    constructor(controller, xOffset, yOffset) {
        this.rectObserver = new ElementRectObserver();
        this.droppableSurfaces = [
            EntityType.PRECISE_SURFACE,
            EntityType.IMPRECISE_SURFACE,
            EntityType.GENERIC_GEOMETRY,
        ];
        this.handlePointerMove = async (event) => {
            const isDroppableSurface = await this.isDroppableSurface(event);
            const draggable = this.controller.getDraggable();
            if (draggable != null && isDroppableSurface) {
                this.handleDrag(draggable, event);
            }
            if (this.controller.getDraggable() == null &&
                this.controller.getToolMode() === 'edit' &&
                isDroppableSurface) {
                this.addCursor(this.getCursorType());
            }
            else {
                this.clearCursor();
            }
        };
        this.handleDrag = async (draggable, event) => {
            const pt = getMouseClientPosition(event, this.elementRect);
            const worldPosition = await this.getWorldPositionForPoint(pt);
            if (worldPosition != null) {
                this.controller.updateDraggable({
                    ...draggable,
                    lastPoint: pt,
                }, worldPosition);
            }
        };
        this.handlePointerDown = async (pointerDown) => {
            const pointerUp = (pointerUp) => {
                const distanceBetweenStartAndEndPoint = point.distance(point.create(pointerDown.clientX, pointerUp.clientY), point.create(pointerUp.clientX, pointerUp.clientY));
                if (distanceBetweenStartAndEndPoint <= 2 && pointerDown.buttons !== 2) {
                    if (this.controller.getToolMode() === 'edit') {
                        const pt = getMouseClientPosition(pointerDown, this.elementRect);
                        this.handlePlacePin(pt);
                    }
                }
                dispose();
            };
            const dispose = () => {
                window.removeEventListener('pointerup', pointerUp);
            };
            window.addEventListener('pointerup', pointerUp);
            return {
                dispose,
            };
        };
        this.handlePointerUp = async () => {
            const draggable = this.controller.getDraggable();
            const lastPoint = draggable === null || draggable === void 0 ? void 0 : draggable.lastPoint;
            this.controller.setDraggable(undefined);
            if (lastPoint != null && draggable != null) {
                this.ifInitialized(async ({ api }) => {
                    var _a, _b, _c, _d, _e, _f;
                    const [hit] = await api.hitItems(lastPoint);
                    if ((hit === null || hit === void 0 ? void 0 : hit.hitPoint) != null &&
                        ((_a = hit === null || hit === void 0 ? void 0 : hit.hitPoint) === null || _a === void 0 ? void 0 : _a.x) != null &&
                        ((_b = hit === null || hit === void 0 ? void 0 : hit.hitPoint) === null || _b === void 0 ? void 0 : _b.y) != null &&
                        ((_c = hit === null || hit === void 0 ? void 0 : hit.hitPoint) === null || _c === void 0 ? void 0 : _c.z) != null) {
                        this.controller.updateDraggable({
                            ...draggable,
                            lastPoint,
                        }, {
                            x: (_d = hit === null || hit === void 0 ? void 0 : hit.hitPoint) === null || _d === void 0 ? void 0 : _d.x,
                            y: hit === null || hit === void 0 ? void 0 : hit.hitPoint.y,
                            z: hit === null || hit === void 0 ? void 0 : hit.hitPoint.z,
                        }, (_f = (_e = hit === null || hit === void 0 ? void 0 : hit.partId) === null || _e === void 0 ? void 0 : _e.hex) !== null && _f !== void 0 ? _f : undefined);
                    }
                });
            }
        };
        this.controller = controller;
        this.xOffset = xOffset;
        this.yOffset = yOffset;
    }
    initialize(element, api) {
        this.element = element;
        this.api = api;
        this.rectObserver.observe(element);
        element.addEventListener('pointermove', this.handlePointerMove);
        element.addEventListener('pointerdown', this.handlePointerDown);
        window.addEventListener('pointerup', this.handlePointerUp);
    }
    dispose() {
        var _a, _b;
        this.rectObserver.disconnect();
        this.clearCursor();
        (_a = this.element) === null || _a === void 0 ? void 0 : _a.removeEventListener('pointermove', this.handlePointerMove);
        (_b = this.element) === null || _b === void 0 ? void 0 : _b.removeEventListener('pointerdown', this.handlePointerDown);
        window.removeEventListener('pointerup', this.handlePointerUp);
        this.element = undefined;
        this.api = undefined;
    }
    async getWorldPositionForPoint(pt) {
        return this.ifInitialized(async ({ api }) => {
            const vector3 = await api.getWorldPointFromViewport(pt);
            return vector3;
        });
    }
    async handlePlacePin(pt, existingPin) {
        this.ifInitialized(async ({ api }) => {
            var _a, _b, _c, _d, _e, _f;
            const [hit] = await api.hitItems(pt);
            if ((hit === null || hit === void 0 ? void 0 : hit.hitPoint) != null && this.elementRect != null) {
                if ((hit === null || hit === void 0 ? void 0 : hit.hitPoint) != null &&
                    (hit === null || hit === void 0 ? void 0 : hit.hitPoint.x) != null &&
                    (hit === null || hit === void 0 ? void 0 : hit.hitPoint.y) != null &&
                    (hit === null || hit === void 0 ? void 0 : hit.hitPoint.z) != null) {
                    const pinId = existingPin != null ? existingPin.id : uuid.create();
                    const attributes = this.controller.getStyleAttributes() != null
                        ? {
                            style: this.controller.getStyleAttributes(),
                        }
                        : undefined;
                    switch (this.controller.getToolType()) {
                        case 'pin-icon':
                            this.controller.setPin({
                                type: 'icon',
                                id: pinId,
                                worldPosition: {
                                    x: (_a = hit === null || hit === void 0 ? void 0 : hit.hitPoint) === null || _a === void 0 ? void 0 : _a.x,
                                    y: hit === null || hit === void 0 ? void 0 : hit.hitPoint.y,
                                    z: hit === null || hit === void 0 ? void 0 : hit.hitPoint.z,
                                },
                                partId: (_c = (_b = hit === null || hit === void 0 ? void 0 : hit.itemId) === null || _b === void 0 ? void 0 : _b.hex) !== null && _c !== void 0 ? _c : undefined,
                                attributes,
                            });
                            break;
                        case 'pin-text':
                            const isNewPin = existingPin == null;
                            const relativePoint = translatePointToRelative(pt, this.elementRect, isNewPin, this.xOffset, this.yOffset);
                            this.controller.setPin({
                                type: 'text',
                                id: pinId,
                                worldPosition: {
                                    x: (_d = hit === null || hit === void 0 ? void 0 : hit.hitPoint) === null || _d === void 0 ? void 0 : _d.x,
                                    y: hit === null || hit === void 0 ? void 0 : hit.hitPoint.y,
                                    z: hit === null || hit === void 0 ? void 0 : hit.hitPoint.z,
                                },
                                partId: (_f = (_e = hit === null || hit === void 0 ? void 0 : hit.itemId) === null || _e === void 0 ? void 0 : _e.hex) !== null && _f !== void 0 ? _f : undefined,
                                label: {
                                    point: relativePoint,
                                },
                                attributes,
                            });
                            this.controller.setSelectedPinId(pinId);
                            break;
                    }
                }
            }
            else {
                this.controller.setSelectedPinId();
            }
        });
    }
    getCursorType() {
        switch (this.controller.getToolType()) {
            case 'pin-icon':
                return pinCursor;
            case 'pin-text':
                return labelPinCursor;
        }
    }
    addCursor(cursor) {
        this.clearCursor();
        this.cursor = this.ifInitialized(({ api }) => api.addCursor(cursor));
    }
    async isDroppableSurface(event) {
        var _a;
        const pt = getMouseClientPosition(event, this.elementRect);
        const type = await ((_a = this.api) === null || _a === void 0 ? void 0 : _a.getEntityTypeAtPoint(pt));
        return type != null && this.droppableSurfaces.includes(type);
    }
    ifInitialized(f) {
        if (this.element != null && this.api != null) {
            return f({ element: this.element, api: this.api });
        }
        else {
            throw new Error('Pins interaction handler not initialized.');
        }
    }
    clearCursor() {
        var _a;
        (_a = this.cursor) === null || _a === void 0 ? void 0 : _a.dispose();
        this.cursor = undefined;
    }
}

const viewerPinToolCss = () => `:host{position:absolute;top:0;bottom:0;left:0;right:0;overflow:hidden;pointer-events:none;--viewer-pin-tool-initial-label-offset-x:20;--viewer-pin-tool-initial-label-offset-y:20}`;

const ViewerPinTool = class {
    constructor(hostRef) {
        registerInstance(this, hostRef);
        /**
         * The model that contains the entities and outcomes from performing pin annotations
         */
        this.pinModel = new PinModel();
        /**
         * The type of pin.
         *
         * This property will automatically be set.
         */
        this.tool = 'pin-icon';
        /**
         * The mode of the pin tool
         */
        this.mode = 'view';
        this.pins = [];
        this.stateMap = {};
        this.handleSetProjectionMatrix = () => {
            var _a, _b;
            this.projectionViewMatrix =
                (_b = (_a = this.viewer) === null || _a === void 0 ? void 0 : _a.frame) === null || _b === void 0 ? void 0 : _b.scene.camera.projectionViewMatrix;
        };
    }
    /**
     * @ignore
     */
    watchModeChange() {
        var _a;
        (_a = this.pinController) === null || _a === void 0 ? void 0 : _a.setToolMode(this.mode);
        this.setupInteractionHandler();
        if (this.mode === 'edit') {
            this.setFeatureMaps();
            this.setCameraAndKeyboardControls();
        }
        else {
            this.resetFeatureMaps();
            this.resetCameraAndKeyboardControls();
        }
    }
    /**
     * @ignore
     */
    watchTypeChange() {
        var _a;
        (_a = this.pinController) === null || _a === void 0 ? void 0 : _a.setToolType(this.tool);
        this.setupInteractionHandler();
    }
    /**
     * @ignore
     */
    watchAccentColorChange() {
        var _a;
        (_a = this.pinController) === null || _a === void 0 ? void 0 : _a.setAccentColor(this.accentColor);
        this.setupInteractionHandler();
    }
    /**
     * @ignore
     */
    watchPrimaryColorChange() {
        var _a;
        (_a = this.pinController) === null || _a === void 0 ? void 0 : _a.setPrimaryColor(this.primaryColor);
        this.setupInteractionHandler();
    }
    /**
     * @ignore
     */
    watchPinsChange() {
        if (this.pins.length > 0) {
            this.setDepthBuffers();
            this.setFeatureMaps();
        }
        else {
            this.resetDepthBuffers();
            this.resetFeatureMaps();
        }
    }
    /**
     * @ignore
     */
    connectedCallback() {
        this.setupInteractionHandler();
        this.setDepthBuffers();
        this.setFeatureMaps();
        this.setCameraAndKeyboardControls();
    }
    /**
     * @ignore
     */
    componentWillLoad() {
        this.updateViewport();
        this.setupController();
        this.setupInteractionHandler();
        this.setDepthBuffers();
        this.setFeatureMaps();
        this.setCameraAndKeyboardControls();
        this.pinModel.onEntitiesChanged((entities) => {
            this.pins = entities;
        });
        this.pinModel.onSelectionChange((selectedId) => {
            this.selectedPinId = selectedId;
        });
        this.handleViewerChanged(this.viewer, undefined);
    }
    componentDidLoad() {
        this.resizeObserver = new ResizeObserver(() => this.updateViewport());
        this.resizeObserver.observe(this.hostEl);
    }
    /**
     * @ignore
     */
    disconnectedCallback() {
        this.clearInteractionHandler();
        this.clearModelListeners();
        this.resetDepthBuffers();
        this.resetFeatureMaps();
        this.resetCameraAndKeyboardControls();
    }
    /**
     * @ignore
     */
    handleViewerChanged(newViewer, oldViewer) {
        this.setupInteractionHandler();
        this.setDepthBuffers();
        this.setFeatureMaps();
        this.setCameraAndKeyboardControls();
        if (oldViewer != null) {
            oldViewer.removeEventListener('frameDrawn', this.handleSetProjectionMatrix);
        }
        if (newViewer != null) {
            newViewer.addEventListener('frameDrawn', this.handleSetProjectionMatrix);
        }
        this.handleSetProjectionMatrix();
    }
    render() {
        return (h(Host, { key: '311442b0cc3d62c485b81526fde10692b560af93' }, h("vertex-viewer-dom-renderer", { key: 'e4fe9d022a717db444590a6c2d2239d233bbe2ce', viewer: this.viewer, drawMode: "2d" }, this.pins.map((pin) => {
            return (h("vertex-viewer-pin-group", { id: `pin-group-${pin.id}`, "data-is-dom-group-element": true, pin: pin, elementBounds: this.elementBounds, pinModel: this.pinModel, pinController: this.pinController, projectionViewMatrix: this.projectionViewMatrix, selected: this.selectedPinId === pin.id }));
        }))));
    }
    setupController() {
        const attributes = this.accentColor || this.primaryColor
            ? {
                accentColor: this.accentColor,
                primaryColor: this.primaryColor,
            }
            : undefined;
        this.pinController = new PinController(this.pinModel, this.mode, this.tool, attributes);
    }
    clearInteractionHandler() {
        var _a;
        (_a = this.registeredInteractionHandler) === null || _a === void 0 ? void 0 : _a.then((handler) => handler.dispose());
        this.registeredInteractionHandler = undefined;
    }
    setupInteractionHandler() {
        var _a;
        const hostStyles = window.getComputedStyle(this.hostEl);
        const xOffset = hostStyles
            .getPropertyValue('--viewer-pin-tool-initial-label-offset-x')
            .trim();
        const xOffsetAsNumber = Number.isFinite(Number.parseInt(xOffset))
            ? Number.parseInt(xOffset)
            : 20;
        const yOffset = hostStyles
            .getPropertyValue('--viewer-pin-tool-initial-label-offset-y')
            .trim();
        const yOffsetAsNumber = Number.isFinite(Number.parseInt(yOffset))
            ? Number.parseInt(yOffset)
            : 20;
        this.clearInteractionHandler();
        if (this.pinController != null) {
            this.registeredInteractionHandler =
                (_a = this.viewer) === null || _a === void 0 ? void 0 : _a.registerInteractionHandler(new PinsInteractionHandler(this.pinController, xOffsetAsNumber, yOffsetAsNumber));
        }
    }
    clearModelListeners() {
        var _a, _b, _c;
        (_a = this.onEntitiesChangedHandler) === null || _a === void 0 ? void 0 : _a.dispose();
        this.onEntitiesChangedHandler = undefined;
        (_b = this.onEntityAddedHandler) === null || _b === void 0 ? void 0 : _b.dispose();
        this.onEntityAddedHandler = undefined;
        (_c = this.resizeObserver) === null || _c === void 0 ? void 0 : _c.disconnect();
    }
    updateViewport() {
        this.elementBounds = getMarkupBoundingClientRect(this.hostEl);
    }
    setDepthBuffers() {
        if (this.pins.length > 0 &&
            this.viewer != null &&
            this.viewer.depthBuffers == null) {
            this.stateMap.shouldClearDepthBuffers = true;
            this.viewer.depthBuffers = 'final';
        }
    }
    resetDepthBuffers() {
        if (this.stateMap.shouldClearDepthBuffers && this.viewer != null) {
            this.viewer.depthBuffers = undefined;
            this.stateMap.shouldClearDepthBuffers = undefined;
        }
    }
    setFeatureMaps() {
        if ((this.pins.length > 0 || this.mode === 'edit') &&
            this.viewer != null &&
            this.viewer.featureMaps == null) {
            this.stateMap.shouldClearFeatureMaps = true;
            this.viewer.featureMaps = 'final';
        }
    }
    resetFeatureMaps() {
        if (this.stateMap.shouldClearFeatureMaps && this.viewer != null) {
            this.viewer.featureMaps = undefined;
            this.stateMap.shouldClearFeatureMaps = undefined;
        }
    }
    setCameraAndKeyboardControls() {
        if (this.mode === 'edit' && this.viewer != null) {
            // Check camera controls
            if (this.viewer.cameraControls) {
                this.stateMap.shouldClearCameraControls = true;
                this.viewer.cameraControls = false;
            }
            // Check keyboard controls
            if (this.viewer.keyboardControls) {
                this.stateMap.shouldClearKeyboardControls = true;
                this.viewer.keyboardControls = false;
            }
        }
    }
    resetCameraAndKeyboardControls() {
        if (this.viewer != null) {
            if (this.stateMap.shouldClearCameraControls) {
                this.viewer.cameraControls = true;
                this.stateMap.shouldClearCameraControls = undefined;
            }
            if (this.stateMap.shouldClearKeyboardControls) {
                this.viewer.keyboardControls = true;
                this.stateMap.shouldClearKeyboardControls = undefined;
            }
        }
    }
    get hostEl() { return getElement(this); }
    static get watchers() { return {
        "mode": [{
                "watchModeChange": 0
            }],
        "tool": [{
                "watchTypeChange": 0
            }],
        "accentColor": [{
                "watchAccentColorChange": 0
            }],
        "primaryColor": [{
                "watchPrimaryColorChange": 0
            }],
        "pins": [{
                "watchPinsChange": 0
            }],
        "viewer": [{
                "handleViewerChanged": 0
            }]
    }; }
};
ViewerPinTool.style = viewerPinToolCss();

export { ViewerPinTool as vertex_viewer_pin_tool };
//# sourceMappingURL=vertex-viewer-pin-tool.entry.js.map

//# sourceMappingURL=vertex-viewer-pin-tool.entry.js.map