import { __esDecorate, __runInitializers } from "tslib";
import { html, LitElement, svg } from 'lit';
import { property } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
import { AssociationAnchors } from '../lib/AssociationAnchors.js';
import { SelectionManager } from '../lib/SelectionManager.js';
import { ShapeArtist } from '../lib/ShapeArtist.js';
import { WorkspaceEdges } from '../lib/WorkspaceEdges.js';
import { WorkspaceGestures } from '../lib/WorkspaceGestures.js';
import { WorkspaceSizing } from '../lib/WorkspaceSizing.js';
import elementStyles from './WorkspaceStyles.js';
const defaultCanvasWidth = 3840;
const defaultCanvasHeight = 2160;
export const canvasRef = Symbol('canvasRef');
export const svgRef = Symbol('svgRef');
export const attributeTypeEditHandler = Symbol('attributeTypeEditHandler');
export const attributeTypeDropdownClosedHandler = Symbol('attributeTypeDropdownClosedHandler');
export const attributeTypeSelectHandler = Symbol('attributeTypeSelectHandler');
export const geometryChangeHandler = Symbol('geometryChangeHandler');
export const notifyZoom = Symbol('notifyZoom');
export const zoomTimeout = Symbol('zoomTimeout');
let VizWorkspaceElement = (() => {
    let _classSuper = LitElement;
    let _zoom_decorators;
    let _zoom_initializers = [];
    let _zoom_extraInitializers = [];
    let _width_decorators;
    let _width_initializers = [];
    let _width_extraInitializers = [];
    let _height_decorators;
    let _height_initializers = [];
    let _height_extraInitializers = [];
    let _autoResize_decorators;
    let _autoResize_initializers = [];
    let _autoResize_extraInitializers = [];
    let _debug_decorators;
    let _debug_initializers = [];
    let _debug_extraInitializers = [];
    let _scale_decorators;
    let _scale_initializers = [];
    let _scale_extraInitializers = [];
    return class VizWorkspaceElement extends _classSuper {
        static {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
            __esDecorate(this, null, _zoom_decorators, { kind: "accessor", name: "zoom", static: false, private: false, access: { has: obj => "zoom" in obj, get: obj => obj.zoom, set: (obj, value) => { obj.zoom = value; } }, metadata: _metadata }, _zoom_initializers, _zoom_extraInitializers);
            __esDecorate(this, null, _width_decorators, { kind: "accessor", name: "width", static: false, private: false, access: { has: obj => "width" in obj, get: obj => obj.width, set: (obj, value) => { obj.width = value; } }, metadata: _metadata }, _width_initializers, _width_extraInitializers);
            __esDecorate(this, null, _height_decorators, { kind: "accessor", name: "height", static: false, private: false, access: { has: obj => "height" in obj, get: obj => obj.height, set: (obj, value) => { obj.height = value; } }, metadata: _metadata }, _height_initializers, _height_extraInitializers);
            __esDecorate(this, null, _autoResize_decorators, { kind: "accessor", name: "autoResize", static: false, private: false, access: { has: obj => "autoResize" in obj, get: obj => obj.autoResize, set: (obj, value) => { obj.autoResize = value; } }, metadata: _metadata }, _autoResize_initializers, _autoResize_extraInitializers);
            __esDecorate(this, null, _debug_decorators, { kind: "accessor", name: "debug", static: false, private: false, access: { has: obj => "debug" in obj, get: obj => obj.debug, set: (obj, value) => { obj.debug = value; } }, metadata: _metadata }, _debug_initializers, _debug_extraInitializers);
            __esDecorate(this, null, _scale_decorators, { kind: "accessor", name: "scale", static: false, private: false, access: { has: obj => "scale" in obj, get: obj => obj.scale, set: (obj, value) => { obj.scale = value; } }, metadata: _metadata }, _scale_initializers, _scale_extraInitializers);
            if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        }
        static get styles() {
            return [elementStyles];
        }
        #zoom_accessor_storage = __runInitializers(this, _zoom_initializers, 0
        /**
         * Gets or sets the number of pixels that an element's content is scrolled horizontally.
         * Unlike regular HTML elements, this can be a negative value as it is possible to
         * scroll outside the working area.
         */
        );
        /**
         * The zoom level of the current visualization
         * @attribute
         */
        get zoom() { return this.#zoom_accessor_storage; }
        set zoom(value) { this.#zoom_accessor_storage = value; }
        /**
         * Gets or sets the number of pixels that an element's content is scrolled horizontally.
         * Unlike regular HTML elements, this can be a negative value as it is possible to
         * scroll outside the working area.
         */
        get scrollLeft() {
            const s = this.gestures;
            return (s && s.left) || 0;
        }
        /**
         * @param value The x-axis position value
         */
        set scrollLeft(value) {
            this.gestures.left = value;
        }
        /**
         * Gets or sets the number of pixels that an element's content is scrolled vertically.
         * Unlike regular HTML elements, this can be a negative value as it is possible to
         * scroll outside the working area.
         */
        get scrollTop() {
            const s = this.gestures;
            return (s && s.top) || 0;
        }
        /**
         * @param value The y-axis position value
         */
        set scrollTop(value) {
            this.gestures.top = value;
        }
        [(_zoom_decorators = [property({ type: Number, reflect: true })], canvasRef)] = __runInitializers(this, _zoom_extraInitializers);
        get canvas() {
            if (!this[canvasRef]) {
                this[canvasRef] = this.shadowRoot?.querySelector('.canvas');
            }
            return this[canvasRef];
        }
        [svgRef];
        get associationSvg() {
            if (!this[svgRef]) {
                this[svgRef] = this.shadowRoot?.querySelector('.association');
            }
            return this[svgRef];
        }
        #width_accessor_storage = __runInitializers(this, _width_initializers, defaultCanvasWidth
        /**
         * The height of the canvas element, in pixels
         */
        );
        /**
         * The width of the canvas element, in pixels
         */
        get width() { return this.#width_accessor_storage; }
        set width(value) { this.#width_accessor_storage = value; }
        #height_accessor_storage = (__runInitializers(this, _width_extraInitializers), __runInitializers(this, _height_initializers, defaultCanvasHeight
        /**
         * When set it instruct the visualization workspace to grow over the currently set `width` and `height`
         * when a new added item is placed outside the bounds of the workspace.
         */
        ));
        /**
         * The height of the canvas element, in pixels
         */
        get height() { return this.#height_accessor_storage; }
        set height(value) { this.#height_accessor_storage = value; }
        #autoResize_accessor_storage = (__runInitializers(this, _height_extraInitializers), __runInitializers(this, _autoResize_initializers, false
        /**
         * Enables some limited debugging information.
         */
        ));
        /**
         * When set it instruct the visualization workspace to grow over the currently set `width` and `height`
         * when a new added item is placed outside the bounds of the workspace.
         */
        get autoResize() { return this.#autoResize_accessor_storage; }
        set autoResize(value) { this.#autoResize_accessor_storage = value; }
        #debug_accessor_storage = (__runInitializers(this, _autoResize_extraInitializers), __runInitializers(this, _debug_initializers, void 0));
        /**
         * Enables some limited debugging information.
         */
        get debug() { return this.#debug_accessor_storage; }
        set debug(value) { this.#debug_accessor_storage = value; }
        #scale_accessor_storage = (__runInitializers(this, _debug_extraInitializers), __runInitializers(this, _scale_initializers, 1));
        /**
         * The current scale of the visualization
         */
        get scale() { return this.#scale_accessor_storage; }
        set scale(value) { this.#scale_accessor_storage = value; }
        [(_width_decorators = [property({ type: Number })], _height_decorators = [property({ type: Number })], _autoResize_decorators = [property({ type: Boolean, reflect: true })], _debug_decorators = [property({ type: Boolean, reflect: true })], _scale_decorators = [property({ type: Number })], zoomTimeout)] = __runInitializers(this, _scale_extraInitializers);
        gestures = new WorkspaceGestures(this);
        selection = new SelectionManager(this);
        edges = new WorkspaceEdges(this);
        anchors = new AssociationAnchors(this);
        sizing = new WorkspaceSizing(this);
        constructor() {
            super();
            this.addEventListener('geometrychange', this[geometryChangeHandler].bind(this));
        }
        connectedCallback() {
            super.connectedCallback();
            this.gestures.connect();
            this.selection.connect();
            this.edges.connect();
            this.anchors.connect();
        }
        disconnectedCallback() {
            super.disconnectedCallback();
            this.gestures.disconnect();
            this.selection.disconnect();
            this.edges.disconnect();
            this.anchors.disconnect();
        }
        firstUpdated(cp) {
            super.firstUpdated(cp);
            const { top, left } = this.gestures;
            if (top === null || left === null) {
                this.gestures.scrollTo(0, 0);
                // this.center();
            }
            this.edges.listenContent();
        }
        willUpdate(cp) {
            if (cp.has('autoResize')) {
                const value = cp.get('autoResize');
                if (value === true) {
                    this.sizing.connect();
                }
                else if (this.sizing.connected) {
                    this.sizing.disconnect();
                }
            }
            if (cp.has('zoom')) {
                this.gestures.updateScale();
            }
        }
        /**
         * Clears the state of the workspace.
         */
        clear() {
            this.edges.clear();
            this.selection.deselectAll();
        }
        /**
         * Centers the workspace.
         */
        center() {
            const { width: cWidth = defaultCanvasWidth, height: cHeight = defaultCanvasHeight } = this;
            const { height, width } = this.getBoundingClientRect();
            const midWidth = cWidth / 2;
            const midHeight = cHeight / 2;
            const left = midWidth - width / 2;
            const top = midHeight - height / 2;
            this.gestures.left = -left;
            this.gestures.top = -top;
        }
        [notifyZoom]() {
            if (this[zoomTimeout]) {
                clearTimeout(this[zoomTimeout]);
            }
            this[zoomTimeout] = setTimeout(() => {
                this.dispatchEvent(new Event('zoomchange'));
            }, 1);
        }
        async [geometryChangeHandler](e) {
            const source = e.target;
            await this.edges.update(source.dataset.key);
        }
        /**
         * Scrolls the element by the given amount.
         * @param {ScrollToOptions|number} xCoordOrOptions The horizontal pixel value that you want to scroll by
         * or the scroll options. When passed value is the `ScrollToOptions` interface then
         * the second argument is ignored.
         * @param {number=} yCoord The vertical pixel value that you want to scroll by.
         */
        scrollBy(xCoordOrOptions, yCoord) {
            this.gestures.scrollBy(xCoordOrOptions, yCoord);
        }
        /**
         * Scrolls to a particular set of coordinates inside the element.
         *
         * @param xCoordOrOptions The pixel along the horizontal axis of the element
         * that you want displayed in the upper left. When passed value is the `ScrollToOptions` interface then
         * the second argument is ignored.
         * @param yCoord The pixel along the vertical axis of the element that you want displayed in the upper left.
         */
        scrollTo(xCoordOrOptions, yCoord) {
            this.gestures.scrollTo(xCoordOrOptions, yCoord);
        }
        /**
         * Scrolls the view if the position defined by `x` and `y` arguments requires
         * the view to be moved.
         *
         * @param x The x coordinate of the point
         * @param y The y coordinate of the point
         * @returns true if the canvas was moved
         */
        scrollIfNeeded(x, y) {
            return this.gestures.scrollIfNeeded(x, y);
        }
        render() {
            const { scale, scrollLeft, scrollTop } = this;
            const styles = {
                transform: `scale(${scale}) translate(${scrollLeft}px, ${scrollTop}px)`,
                width: `${this.width}px`,
                height: `${this.height}px`,
            };
            return html `
      <div class="content canvas" style="${styleMap(styles)}">
        ${this.renderLinesTemplate()}
        <slot></slot>
      </div>
    `;
        }
        /**
         * @return {SVGTemplateResult} The template for the associations
         */
        renderLinesTemplate() {
            const { debug } = this;
            const { edges } = this.edges;
            const primarySelected = [];
            const secondarySelected = [];
            const hovered = [];
            const rest = [];
            edges.forEach((item) => {
                const line = ShapeArtist.line(item, debug);
                const { shape } = item;
                const { selection = {} } = shape;
                if (selection.primary) {
                    primarySelected.push(line);
                }
                else if (selection.secondary) {
                    secondarySelected.push(line);
                }
                else if (selection.hover) {
                    hovered.push(line);
                }
                else {
                    rest.push(line);
                }
            });
            const edgesResult = primarySelected.concat(secondarySelected).concat(hovered).concat(rest).reverse();
            return svg `
    <svg width="100%" height="100%" class="association">
    ${edgesResult.length ? edgesResult : ''}
    </svg>`;
        }
    };
})();
/**
 * @fires positionchange
 */
export default VizWorkspaceElement;
//# sourceMappingURL=VizWorkspaceElement.js.map