/*!
 * Copyright (c) 2026 Vertex Software LLC. All rights reserved.
 */
import { h, Host, } from "@stencil/core";
import { getWindowDevicePixelRatio } from "../../lib/dom";
import { writeDOM } from "../../lib/stencil";
import { getMarkupBoundingClientRect } from "../viewer-markup/dom";
import { isValidPointData, isValidStartEvent, translatePointToScreen, } from "../viewer-markup/markup-utils";
import { SvgShadow } from "../viewer-markup/viewer-markup-components";
import { ArrowMarkupInteractionHandler } from "./interactions";
import { arrowheadPointsToCirclePoints, arrowheadPointsToHashPoints, arrowheadPointsToPathPoints, arrowheadPointsToPolygonPoints, createLineAnchorStylePoints, parsePoint, } from "./utils";
import { BoundingBox1d } from "./viewer-markup-arrow-components";
export class ViewerMarkupArrow {
    constructor() {
        /**
         * Defines the behavior of the provided markup when the originating viewport is smaller
         * than the current viewport, or is scaled to a size smaller than the current viewport
         * using the `scale` property.
         *
         * Options:
         * - `x-only`: Markup will be centered horizontally, but not vertically.
         * - `y-only`: Markup will be centered vertically, but not horizontally.
         * - `both`: Markup will be centered both horizontally and vertically.
         * - `none`: Markup will not be centered (default).
         */
        this.centeringBehavior = 'none';
        /**
         * The scale to render this markup at. This value is used to scale the element's bounds
         * along with any `offset` to determine the final computed coordinates.
         *
         * When provided, all computed coordinates will be scaled by this amount.
         */
        this.scale = 1;
        /**
         * The style of the starting anchor. This defaults to none.
         */
        this.startLineAnchorStyle = 'none';
        /**
         * The style of the ending anchor. This defaults to 'arrow-triangle.'
         */
        this.endLineAnchorStyle = 'arrow-triangle';
        /**
         * A mode that specifies how the markup component should behave. When
         * unset, the component will not respond to interactions with the handles.
         * When `edit`, the markup anchors are interactive and the user is able
         * to reposition them. When `create`, anytime the user clicks on the canvas,
         * a new markup will be performed.
         */
        this.mode = '';
        this.interactionHandler = new ArrowMarkupInteractionHandler(this.hostEl, this.interactionBegin, this.interactionEnd, {
            scale: this.scale,
            offset: this.offset,
            originatingViewport: this.originatingViewport,
            centeringBehavior: this.centeringBehavior,
        });
        this.handleWindowPointerDown = (event) => {
            if (isValidStartEvent(event)) {
                this.interactionHandler.startInteraction(event);
            }
        };
        this.handleTouchStart = (event) => {
            event.preventDefault();
        };
    }
    /**
     * @ignore
     */
    componentWillLoad() {
        this.updateViewport();
        this.handleViewerChanged(this.viewer);
        this.handleScaleChange();
        this.handleScalingConfigurationChange();
        this.updatePointsFromProps();
    }
    componentDidLoad() {
        this.updatePointsFromProps();
        const resize = new ResizeObserver(() => this.updateViewport());
        resize.observe(this.hostEl);
        if (this.mode === 'create') {
            window.addEventListener('pointerdown', this.handleWindowPointerDown);
        }
    }
    componentDidRender() {
        if (this.mode === '') {
            this.viewRendered.emit();
        }
    }
    disconnectedCallback() {
        this.dispose();
    }
    async dispose() {
        var _a;
        (_a = this.registeredInteraction) === null || _a === void 0 ? void 0 : _a.dispose();
        this.registeredInteraction = undefined;
        window.removeEventListener('pointerdown', this.handleWindowPointerDown);
    }
    /**
     * @ignore
     */
    async handleViewerChanged(newViewer) {
        var _a;
        (_a = this.registeredInteraction) === null || _a === void 0 ? void 0 : _a.dispose();
        this.registeredInteraction = undefined;
        if (newViewer != null) {
            this.registeredInteraction =
                await newViewer.registerBasicInteractionHandler(this.interactionHandler);
        }
    }
    handleStartJsonChange() {
        this.updatePointsFromProps();
    }
    handleEndJsonChange() {
        this.updatePointsFromProps();
    }
    handleModeChange() {
        if (this.mode !== 'create') {
            window.removeEventListener('pointerdown', this.handleWindowPointerDown);
        }
    }
    handleScalingConfigurationChange() {
        this.interactionHandler.updateScalingOptions({
            scale: this.scale,
            offset: this.offset,
            originatingViewport: this.originatingViewport,
            centeringBehavior: this.centeringBehavior,
        });
    }
    handleScaleChange() {
        writeDOM(() => {
            var _a, _b;
            this.hostEl.style.setProperty('--viewer-markup-arrow-scale', (_b = (_a = this.scale) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : '1');
        });
    }
    updateViewport() {
        const rect = getMarkupBoundingClientRect(this.hostEl);
        this.elementBounds = rect;
    }
    updatePointsFromProps() {
        this.start = this.start || parsePoint(this.startJson);
        this.end = this.end || parsePoint(this.endJson);
    }
    renderLineAnchorStyle(anchorStyle, arrowheadPoints) {
        if (anchorStyle === 'arrow-triangle') {
            return (h("polygon", { id: "line-anchor-arrow-triangle", class: "head", points: arrowheadPointsToPolygonPoints(arrowheadPoints, this.scale) }));
        }
        else if (anchorStyle === 'arrow-line') {
            return (h("path", { id: "line-anchor-arrow-line", class: "head", d: arrowheadPointsToPathPoints(arrowheadPoints, this.scale) }));
        }
        else if (anchorStyle === 'hash') {
            const hashPoints = arrowheadPointsToHashPoints(arrowheadPoints, this.scale);
            return h("line", { id: "line-anchor-hash", class: "head", ...hashPoints });
        }
        else if (anchorStyle === 'dot') {
            const circlePoints = arrowheadPointsToCirclePoints(arrowheadPoints, this.scale);
            return h("circle", { id: "line-anchor-circle", class: "head", ...circlePoints });
        }
        else {
            return h("div", null);
        }
    }
    render() {
        var _a, _b, _c, _d;
        if (this.start != null && this.end != null && this.elementBounds != null) {
            const elementBounds = this.elementBounds;
            const offsetX = ((_b = (_a = this.offset) === null || _a === void 0 ? void 0 : _a.x) !== null && _b !== void 0 ? _b : 0) / getWindowDevicePixelRatio();
            const offsetY = ((_d = (_c = this.offset) === null || _c === void 0 ? void 0 : _c.y) !== null && _d !== void 0 ? _d : 0) / getWindowDevicePixelRatio();
            const screenStart = translatePointToScreen(this.start, elementBounds, this.originatingViewport, this.centeringBehavior, this.scale);
            const screenEnd = translatePointToScreen(this.end, elementBounds, this.originatingViewport, this.centeringBehavior, this.scale);
            if (isValidPointData(screenStart, screenEnd)) {
                const arrowheadStartPoints = createLineAnchorStylePoints(screenEnd, screenStart);
                const arrowheadEndPoints = createLineAnchorStylePoints(screenStart, screenEnd);
                return (h(Host, null, h("svg", { class: "svg", onTouchStart: this.handleTouchStart }, h("defs", null, h(SvgShadow, { id: "arrow-shadow", scale: this.scale })), h("g", { transform: `translate(${offsetX} ${offsetY})`, filter: "url(#arrow-shadow)" }, this.renderLineAnchorStyle(this.startLineAnchorStyle, arrowheadStartPoints), h("line", { id: "arrow-line", class: "line", x1: arrowheadEndPoints.tip.x, y1: arrowheadEndPoints.tip.y, x2: arrowheadStartPoints.tip.x, y2: arrowheadStartPoints.tip.y }), this.renderLineAnchorStyle(this.endLineAnchorStyle, arrowheadEndPoints)), this.mode === 'edit' && (h("g", { transform: `translate(${offsetX} ${offsetY})` }, h("line", { id: "bounding-box-1d-line", class: "bounds-line", x1: screenStart.x, y1: screenStart.y, x2: screenEnd.x, y2: screenEnd.y })))), this.mode === 'edit' && (h(BoundingBox1d, { start: screenStart, end: screenEnd, offset: { x: offsetX, y: offsetY }, onStartAnchorPointerDown: (event) => this.interactionHandler.editAnchor('start', event), onCenterAnchorPointerDown: (event) => this.interactionHandler.editAnchor('center', event), onEndAnchorPointerDown: (event) => this.interactionHandler.editAnchor('end', event) })), this.mode === 'create' && (h("div", { class: "create-overlay", onTouchStart: this.handleTouchStart }))));
            }
            else {
                return h(Host, null);
            }
        }
        else {
            return (h(Host, null, h("div", { class: "create-overlay", onTouchStart: this.handleTouchStart })));
        }
    }
    static get is() { return "vertex-viewer-markup-arrow"; }
    static get encapsulation() { return "shadow"; }
    static get originalStyleUrls() {
        return {
            "$": ["viewer-markup-arrow.css"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["viewer-markup-arrow.css"]
        };
    }
    static get properties() {
        return {
            "start": {
                "type": "unknown",
                "mutable": true,
                "complexType": {
                    "original": "Point.Point",
                    "resolved": "Point | undefined",
                    "references": {
                        "Point": {
                            "location": "import",
                            "path": "@vertexvis/geometry",
                            "id": "../geometry/dist/index.d.ts::\"/home/runner/work/vertex-web-sdk/vertex-web-sdk/packages/geometry/dist/point\"",
                            "referenceLocation": "Point"
                        }
                    }
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "The position of the starting anchor. Can either be an instance of a\n`Point` or a JSON string representation in the format of `[x, y]` or\n`{\"x\": 0, \"y\": 0}`.\n\nPoints are expected to be relative coordinates from `[-0.5, 0.5]`,\ne.g. `[0, 0]` corresponds to a point in the center of the viewport."
                },
                "getter": false,
                "setter": false
            },
            "startJson": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string | undefined",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "The position of the starting anchor, as a JSON string. Can either be an\ninstance of a `Point` or a JSON string representation in the format of\n`[x, y]` or `{\"x\": 0, \"y\": 0}`.\n\nPoints are expected to be relative coordinates from `[-0.5, 0.5]`,\ne.g. `[0, 0]` corresponds to a point in the center of the viewport."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "start"
            },
            "end": {
                "type": "unknown",
                "mutable": true,
                "complexType": {
                    "original": "Point.Point",
                    "resolved": "Point | undefined",
                    "references": {
                        "Point": {
                            "location": "import",
                            "path": "@vertexvis/geometry",
                            "id": "../geometry/dist/index.d.ts::\"/home/runner/work/vertex-web-sdk/vertex-web-sdk/packages/geometry/dist/point\"",
                            "referenceLocation": "Point"
                        }
                    }
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "The position of the ending anchor. Can either be an instance of a `Point`\nor a JSON string representation in the format of `[x, y]` or `{\"x\": 0,\n\"y\": 0}`.\n\nPoints are expected to be relative coordinates from `[-0.5, 0.5]`,\ne.g. `[0, 0]` corresponds to a point in the center of the viewport."
                },
                "getter": false,
                "setter": false
            },
            "endJson": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string | undefined",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "The position of the ending anchor, as a JSON string. Can either be an\ninstance of a `Point` or a JSON string representation in the format of\n`[x, y]` or `{\"x\": 0, \"y\": 0}`.\n\nPoints are expected to be relative coordinates from `[-0.5, 0.5]`,\ne.g. `[0, 0]` corresponds to a point in the center of the viewport."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "end"
            },
            "originatingViewport": {
                "type": "unknown",
                "mutable": false,
                "complexType": {
                    "original": "Dimensions.Dimensions",
                    "resolved": "Dimensions | undefined",
                    "references": {
                        "Dimensions": {
                            "location": "import",
                            "path": "@vertexvis/geometry",
                            "id": "../geometry/dist/index.d.ts::\"/home/runner/work/vertex-web-sdk/vertex-web-sdk/packages/geometry/dist/dimensions\"",
                            "referenceLocation": "Dimensions"
                        }
                    }
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "The original viewport dimensions where this markup was created. This value is used\nto determine where the markup should be rendered relative to the current viewport,\nenabling some markup to appear \"off-screen\".\n\nWhen provided, all NDC values will be considered relative to this viewport."
                },
                "getter": false,
                "setter": false
            },
            "centeringBehavior": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "MarkupCenteringBehavior",
                    "resolved": "\"both\" | \"none\" | \"x-only\" | \"y-only\"",
                    "references": {
                        "MarkupCenteringBehavior": {
                            "location": "import",
                            "path": "../../lib/types/markup",
                            "id": "src/lib/types/markup.ts::MarkupCenteringBehavior",
                            "referenceLocation": "MarkupCenteringBehavior"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Defines the behavior of the provided markup when the originating viewport is smaller\nthan the current viewport, or is scaled to a size smaller than the current viewport\nusing the `scale` property.\n\nOptions:\n- `x-only`: Markup will be centered horizontally, but not vertically.\n- `y-only`: Markup will be centered vertically, but not horizontally.\n- `both`: Markup will be centered both horizontally and vertically.\n- `none`: Markup will not be centered (default)."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "centering-behavior",
                "defaultValue": "'none'"
            },
            "offset": {
                "type": "unknown",
                "mutable": false,
                "complexType": {
                    "original": "Point.Point",
                    "resolved": "Point | undefined",
                    "references": {
                        "Point": {
                            "location": "import",
                            "path": "@vertexvis/geometry",
                            "id": "../geometry/dist/index.d.ts::\"/home/runner/work/vertex-web-sdk/vertex-web-sdk/packages/geometry/dist/point\"",
                            "referenceLocation": "Point"
                        }
                    }
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "The current offset of the visible viewport. This value is used to determine where\nmarkup should be rendered relative to the current viewport, enabling some markup to appear \"off-screen\".\n\nWhen provided, all computed coordinates will be offset by this amount."
                },
                "getter": false,
                "setter": false
            },
            "scale": {
                "type": "number",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The scale to render this markup at. This value is used to scale the element's bounds\nalong with any `offset` to determine the final computed coordinates.\n\nWhen provided, all computed coordinates will be scaled by this amount."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "scale",
                "defaultValue": "1"
            },
            "startLineAnchorStyle": {
                "type": "string",
                "mutable": true,
                "complexType": {
                    "original": "LineAnchorStyle",
                    "resolved": "\"arrow-line\" | \"arrow-triangle\" | \"dot\" | \"hash\" | \"none\"",
                    "references": {
                        "LineAnchorStyle": {
                            "location": "import",
                            "path": "./utils",
                            "id": "src/components/viewer-markup-arrow/utils.ts::LineAnchorStyle",
                            "referenceLocation": "LineAnchorStyle"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The style of the starting anchor. This defaults to none."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "start-line-anchor-style",
                "defaultValue": "'none'"
            },
            "endLineAnchorStyle": {
                "type": "string",
                "mutable": true,
                "complexType": {
                    "original": "LineAnchorStyle",
                    "resolved": "\"arrow-line\" | \"arrow-triangle\" | \"dot\" | \"hash\" | \"none\"",
                    "references": {
                        "LineAnchorStyle": {
                            "location": "import",
                            "path": "./utils",
                            "id": "src/components/viewer-markup-arrow/utils.ts::LineAnchorStyle",
                            "referenceLocation": "LineAnchorStyle"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The style of the ending anchor. This defaults to 'arrow-triangle.'"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "end-line-anchor-style",
                "defaultValue": "'arrow-triangle'"
            },
            "mode": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "ViewerMarkupArrowMode",
                    "resolved": "\"\" | \"create\" | \"edit\"",
                    "references": {
                        "ViewerMarkupArrowMode": {
                            "location": "local",
                            "path": "/home/runner/work/vertex-web-sdk/vertex-web-sdk/packages/viewer/src/components/viewer-markup-arrow/viewer-markup-arrow.tsx",
                            "id": "src/components/viewer-markup-arrow/viewer-markup-arrow.tsx::ViewerMarkupArrowMode"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "A mode that specifies how the markup component should behave. When\nunset, the component will not respond to interactions with the handles.\nWhen `edit`, the markup anchors are interactive and the user is able\nto reposition them. When `create`, anytime the user clicks on the canvas,\na new markup will be performed."
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "mode",
                "defaultValue": "''"
            },
            "viewer": {
                "type": "unknown",
                "mutable": false,
                "complexType": {
                    "original": "BasicViewer",
                    "resolved": "BasicViewer | undefined",
                    "references": {
                        "BasicViewer": {
                            "location": "import",
                            "path": "@vertexvis/utils",
                            "id": "../utils/dist/index.d.ts::BasicViewer",
                            "referenceLocation": "BasicViewer"
                        }
                    }
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "The viewer to connect to markups.\n\nThis property will automatically be set when a child of a\n`<vertex-viewer-markup>` or `<vertex-viewer>` element."
                },
                "getter": false,
                "setter": false
            }
        };
    }
    static get states() {
        return {
            "elementBounds": {}
        };
    }
    static get events() {
        return [{
                "method": "interactionBegin",
                "name": "interactionBegin",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "An event that is dispatched anytime the user begins interacting with the\nmarkup."
                },
                "complexType": {
                    "original": "void",
                    "resolved": "void",
                    "references": {}
                }
            }, {
                "method": "interactionEnd",
                "name": "interactionEnd",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "An event that is dispatched when the user has finished interacting with the\nmarkup."
                },
                "complexType": {
                    "original": "MarkupInteraction",
                    "resolved": "MarkupInteraction",
                    "references": {
                        "MarkupInteraction": {
                            "location": "import",
                            "path": "../../lib/types/markup",
                            "id": "src/lib/types/markup.ts::MarkupInteraction",
                            "referenceLocation": "MarkupInteraction"
                        }
                    }
                }
            }, {
                "method": "viewRendered",
                "name": "viewRendered",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "An event that is dispatched when this markup element is in view\nmode (`this.mode === \"\"`), and it completes a rerender."
                },
                "complexType": {
                    "original": "void",
                    "resolved": "void",
                    "references": {}
                }
            }];
    }
    static get methods() {
        return {
            "dispose": {
                "complexType": {
                    "signature": "() => Promise<void>",
                    "parameters": [],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "",
                    "tags": []
                }
            }
        };
    }
    static get elementRef() { return "hostEl"; }
    static get watchers() {
        return [{
                "propName": "viewer",
                "methodName": "handleViewerChanged"
            }, {
                "propName": "start",
                "methodName": "handleStartJsonChange"
            }, {
                "propName": "end",
                "methodName": "handleEndJsonChange"
            }, {
                "propName": "mode",
                "methodName": "handleModeChange"
            }, {
                "propName": "offset",
                "methodName": "handleScalingConfigurationChange"
            }, {
                "propName": "originatingViewport",
                "methodName": "handleScalingConfigurationChange"
            }, {
                "propName": "centeringBehavior",
                "methodName": "handleScalingConfigurationChange"
            }, {
                "propName": "scale",
                "methodName": "handleScalingConfigurationChange"
            }, {
                "propName": "scale",
                "methodName": "handleScaleChange"
            }];
    }
}
//# sourceMappingURL=viewer-markup-arrow.js.map
