/*!
 * 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 { isValidStartEvent, translatePointToScreen, translateRectToScreen, } from "../viewer-markup/markup-utils";
import { SvgShadow } from "../viewer-markup/viewer-markup-components";
import { parseBounds } from "../viewer-markup-circle/utils";
import { BoundingBox2d } from "../viewer-markup-circle/viewer-markup-circle-components";
import { FreeformMarkupInteractionHandler } from "./interactions";
import { parsePoints } from "./utils";
export class ViewerMarkupFreeform {
    constructor() {
        /**
         * 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 = '';
        /**
         * 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;
        this.screenPoints = [];
        this.interactionHandler = new FreeformMarkupInteractionHandler(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() {
        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);
        }
    }
    recomputePointsFromProps() {
        this.updatePointsFromProps();
    }
    handleScalingConfigurationChange() {
        this.interactionHandler.updateScalingOptions({
            scale: this.scale,
            offset: this.offset,
            originatingViewport: this.originatingViewport,
            centeringBehavior: this.centeringBehavior,
        });
    }
    handleScaleChange() {
        writeDOM(() => {
            this.hostEl.style.setProperty('--viewer-markup-freeform-scale', this.scale.toString());
        });
    }
    handleModeChange() {
        if (this.mode !== 'create') {
            window.removeEventListener('pointerdown', this.handleWindowPointerDown);
        }
    }
    updateViewport() {
        var _a;
        const rect = getMarkupBoundingClientRect(this.hostEl);
        this.elementBounds = rect;
        this.screenPoints = (_a = this.convertPointsToScreen()) !== null && _a !== void 0 ? _a : this.screenPoints;
    }
    updatePointsFromProps() {
        var _a, _b, _c;
        this.points = (_a = this.points) !== null && _a !== void 0 ? _a : parsePoints(this.pointsJson);
        this.screenPoints = (_b = this.convertPointsToScreen()) !== null && _b !== void 0 ? _b : [];
        this.bounds = (_c = this.bounds) !== null && _c !== void 0 ? _c : parseBounds(this.boundsJson);
    }
    render() {
        var _a, _b, _c, _d;
        if (this.screenPoints.length > 0 && this.elementBounds != null) {
            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();
            return (h(Host, null, h("svg", { class: "svg", onTouchStart: this.handleTouchStart }, h("defs", null, h(SvgShadow, { id: "freeform-markup-shadow", scale: this.scale })), h("g", { transform: `translate(${offsetX} ${offsetY})`, filter: "url(#freeform-markup-shadow)" }, h("path", { class: "path", d: this.screenPoints.reduce((d, pt) => `${d}L${pt.x},${pt.y}`, `M${this.screenPoints[0].x},${this.screenPoints[0].y}`), fill: "none" }))), this.mode === 'edit' && this.bounds != null && (h(BoundingBox2d, { bounds: translateRectToScreen(this.bounds, this.elementBounds, this.originatingViewport, this.centeringBehavior, this.scale), offset: { x: offsetX, y: offsetY }, onTopLeftAnchorPointerDown: (e) => this.interactionHandler.editAnchor('top-left', e), onTopRightAnchorPointerDown: (e) => this.interactionHandler.editAnchor('top-right', e), onTopAnchorPointerDown: (e) => this.interactionHandler.editAnchor('top', e), onBottomLeftAnchorPointerDown: (e) => this.interactionHandler.editAnchor('bottom-left', e), onBottomRightAnchorPointerDown: (e) => this.interactionHandler.editAnchor('bottom-right', e), onBottomAnchorPointerDown: (e) => this.interactionHandler.editAnchor('bottom', e), onLeftAnchorPointerDown: (e) => this.interactionHandler.editAnchor('left', e), onRightAnchorPointerDown: (e) => this.interactionHandler.editAnchor('right', e), onCenterAnchorPointerDown: (e) => this.interactionHandler.editAnchor('center', e) })), this.mode === 'create' && (h("div", { class: "create-overlay", onTouchStart: this.handleTouchStart }))));
        }
        else {
            return (h(Host, null, h("div", { class: "create-overlay", onTouchStart: this.handleTouchStart })));
        }
    }
    convertPointsToScreen() {
        var _a;
        const elementBounds = this.elementBounds;
        if (elementBounds != null) {
            return (_a = this.points) === null || _a === void 0 ? void 0 : _a.map((pt) => translatePointToScreen(pt, elementBounds, this.originatingViewport, this.centeringBehavior, this.scale));
        }
    }
    static get is() { return "vertex-viewer-markup-freeform"; }
    static get encapsulation() { return "shadow"; }
    static get originalStyleUrls() {
        return {
            "$": ["viewer-markup-freeform.css"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["viewer-markup-freeform.css"]
        };
    }
    static get properties() {
        return {
            "points": {
                "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 positions of the various points of this freeform markup. Can either be an array of\n`Point`s or a JSON string representation in the format of `[[x1, y1], [x2, y2]]` or\n`[{\"x\": 0, \"y\": 0}, {\"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
            },
            "pointsJson": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string | undefined",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "The positions of the various points of this freeform markup. Can either be an array of\n`Point`s or a JSON string representation in the format of `[[x1, y1], [x2, y2]]` or\n`[{\"x\": 0, \"y\": 0}, {\"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": "points"
            },
            "bounds": {
                "type": "unknown",
                "mutable": true,
                "complexType": {
                    "original": "Rectangle.Rectangle",
                    "resolved": "Rectangle | undefined",
                    "references": {
                        "Rectangle": {
                            "location": "import",
                            "path": "@vertexvis/geometry",
                            "id": "../geometry/dist/index.d.ts::\"/home/runner/work/vertex-web-sdk/vertex-web-sdk/packages/geometry/dist/rectangle\"",
                            "referenceLocation": "Rectangle"
                        }
                    }
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "The bounds of the freeform. Can either be an instance of a `Rectangle` or\na JSON string representation in the format of `[x, y, width, height]` or\n`{\"x\": 0, \"y\": 0, \"width\": 10, \"height\": 10}`.\n\nBounds are expected to have relative coordinates, with `[x, y]` from `[-0.5, 0.5]`\nand `[width, height]` from `[0, 1]`, e.g. `[0, 0, 0.25, 0.25]`corresponds to a freeform\nwith a diameter of one fourth the viewport's smallest size in the center of the viewport."
                },
                "getter": false,
                "setter": false
            },
            "boundsJson": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string | undefined",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "The bounds of the freeform. Can either be an instance of a `Rectangle` or\na JSON string representation in the format of `[x, y, width, height]` or\n`{\"x\": 0, \"y\": 0, \"width\": 0.1, \"height\": 0.1}`.\n\nBounds are expected to have relative coordinates, with `[x, y]` from `[-0.5, 0.5]`\nand `[width, height]` from `[0, 1]`, e.g. `[0, 0, 0.25, 0.25]`corresponds to a freeform\nwith a diameter of one fourth the viewport's smallest size in the center of the viewport."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "bounds"
            },
            "mode": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "ViewerMarkupFreeformMode",
                    "resolved": "\"\" | \"create\" | \"edit\"",
                    "references": {
                        "ViewerMarkupFreeformMode": {
                            "location": "local",
                            "path": "/home/runner/work/vertex-web-sdk/vertex-web-sdk/packages/viewer/src/components/viewer-markup-freeform/viewer-markup-freeform.tsx",
                            "id": "src/components/viewer-markup-freeform/viewer-markup-freeform.tsx::ViewerMarkupFreeformMode"
                        }
                    }
                },
                "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
            },
            "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"
            }
        };
    }
    static get states() {
        return {
            "elementBounds": {},
            "screenPoints": {}
        };
    }
    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": "originatingViewport",
                "methodName": "recomputePointsFromProps"
            }, {
                "propName": "offset",
                "methodName": "recomputePointsFromProps"
            }, {
                "propName": "scale",
                "methodName": "recomputePointsFromProps"
            }, {
                "propName": "bounds",
                "methodName": "recomputePointsFromProps"
            }, {
                "propName": "points",
                "methodName": "recomputePointsFromProps"
            }, {
                "propName": "offset",
                "methodName": "handleScalingConfigurationChange"
            }, {
                "propName": "originatingViewport",
                "methodName": "handleScalingConfigurationChange"
            }, {
                "propName": "centeringBehavior",
                "methodName": "handleScalingConfigurationChange"
            }, {
                "propName": "scale",
                "methodName": "handleScalingConfigurationChange"
            }, {
                "propName": "scale",
                "methodName": "handleScaleChange"
            }, {
                "propName": "mode",
                "methodName": "handleModeChange"
            }];
    }
}
//# sourceMappingURL=viewer-markup-freeform.js.map
