// #region Imports
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { emit, HTMLElementEventEmitter } from '@breadstone/mosaik-elements';
import { Themeable } from '../../../Behaviors/Themeable';
import { SlotController } from '../../../Controllers/SlotController';
import { Attribute } from '../../../Decorators/AttributeDecorator';
import { Component } from '../../../Decorators/ComponentDecorator';
import { CustomElement } from '../../Abstracts/CustomElement';
import { tileManagerElementCosmopolitanStyle } from './Themes/TileManagerElement.Cosmopolitan';
import { tileManagerElementJoyStyle } from './Themes/TileManagerElement.Joy';
import { tileManagerElementMemphisStyle } from './Themes/TileManagerElement.Memphis';
import { tileManagerElementTemplate } from './TileManagerElementTemplate';
import { createTileManagerTilesState } from './TileManagerPosition';
import { TileManagerSerializer } from './TileManagerSerializer';
// #endregion
/**
 * The tile manager component is a layout container used to display a group of tiles.
 * The tiles can be dragged to a different position, resized, maximized, or made full-screen.
 * The layout of tiles within the tile manager can be saved for later use.
 *
 * @element mosaik-tile-manager
 * @category Layout
 *
 * @fires layoutChanged {LayoutChangedEvent} - Fired when the layout changes.
 *
 * @slot - Default slot for tile elements.
 *
 * @csspart base - The wrapper for the entire tile manager content.
 * @csspart maximized-overlay - The overlay shown when a tile is maximized.
 *
 * @public
 */
let TileManagerElement = class TileManagerElement extends Themeable(CustomElement) {
    // #region Fields
    _resizeMode;
    _dragMode;
    _columnCount;
    _minColumnWidth;
    _minRowHeight;
    _gap;
    _tilesState;
    _serializer;
    _slotController;
    _layoutChange;
    // #endregion
    // #region Ctor
    /**
     * Constructs a new instance of the `TileManagerElement` class.
     *
     * @public
     */
    constructor() {
        super();
        this._resizeMode = 'none';
        this._dragMode = 'tile';
        this._columnCount = null;
        this._minColumnWidth = 200;
        this._minRowHeight = 200;
        this._gap = 16;
        this._tilesState = createTileManagerTilesState();
        this._serializer = new TileManagerSerializer();
        this._slotController = new SlotController(this);
        this._layoutChange = new HTMLElementEventEmitter(this, 'layoutChanged');
    }
    // #endregion
    // #region Properties
    /**
     * Returns the `{@link is}` property.
     *
     * @public
     * @static
     * @readonly
     */
    static get is() {
        return 'mosaik-tile-manager';
    }
    /**
     * Gets or sets the `resizeMode` property.
     * Determines when the resize handles are visible.
     *
     * - `none` - Resize handles are not visible.
     * - `hover` - Resize handles are visible on hover.
     * - `always` - Resize handles are always visible.
     *
     * @public
     * @attr resize-mode
     */
    get resizeMode() {
        return this._resizeMode;
    }
    set resizeMode(value) {
        if (this._resizeMode !== value) {
            this._resizeMode = value;
            this.requestUpdate('resizeMode');
        }
    }
    /**
     * Gets or sets the `dragMode` property.
     * Determines how the tiles can be dragged.
     *
     * - `none` - Tiles cannot be dragged.
     * - `tile` - Tiles can be dragged from any part of the tile.
     * - `tile-header` - Tiles can be dragged from the tile header only.
     *
     * @public
     * @attr drag-mode
     */
    get dragMode() {
        return this._dragMode;
    }
    set dragMode(value) {
        if (this._dragMode !== value) {
            this._dragMode = value;
            this.requestUpdate('dragMode');
        }
    }
    /**
     * Gets or sets the `columnCount` property.
     * Specifies the number of columns in the grid.
     *
     * @public
     * @attr column-count
     */
    get columnCount() {
        return this._columnCount;
    }
    set columnCount(value) {
        if (this._columnCount !== value) {
            this._columnCount = value;
            this.requestUpdate('columnCount');
        }
    }
    /**
     * Gets or sets the `minColumnWidth` property.
     * Specifies the minimum column width in pixels.
     * Used with auto-fit columns.
     *
     * @public
     * @attr min-column-width
     */
    get minColumnWidth() {
        return this._minColumnWidth;
    }
    set minColumnWidth(value) {
        if (this._minColumnWidth !== value) {
            this._minColumnWidth = value;
            this.requestUpdate('minColumnWidth');
        }
    }
    /**
     * Gets or sets the `minRowHeight` property.
     * Specifies the minimum row height in pixels.
     *
     * @public
     * @attr min-row-height
     */
    get minRowHeight() {
        return this._minRowHeight;
    }
    set minRowHeight(value) {
        if (this._minRowHeight !== value) {
            this._minRowHeight = value;
            this.requestUpdate('minRowHeight');
        }
    }
    /**
     * Gets or sets the `gap` property.
     * Specifies the gap between tiles in pixels.
     *
     * @public
     * @attr
     */
    get gap() {
        return this._gap;
    }
    set gap(value) {
        if (this._gap !== value) {
            this._gap = value;
            this.requestUpdate('gap');
        }
    }
    /**
     * Gets all tile elements in the tile manager.
     *
     * @public
     * @readonly
     */
    get tiles() {
        return Array.from(this.querySelectorAll('mosaik-tile-manager-tile'));
    }
    /**
     * Gets the currently maximized tile, if any.
     *
     * @public
     * @readonly
     */
    get maximizedTile() {
        return this.tiles.find((tile) => tile.maximized) ?? null;
    }
    /**
     * Gets the layoutChange event emitter.
     *
     * @public
     * @readonly
     */
    get layoutChangeEvent() {
        return this._layoutChange;
    }
    // #endregion
    // #region Methods
    /**
     * @public
     * @override
     */
    connectedCallback() {
        super.connectedCallback();
        this.setAttribute('role', 'grid');
    }
    /**
     * Handles slot changes to update tile positions.
     *
     * @public
     */
    handleSlotChange() {
        this._tilesState.update(this.tiles);
        const tiles = this.tiles;
        tiles.forEach((tile, index) => {
            if (tile.position < 0) {
                tile.position = index;
            }
        });
    }
    /**
     * Saves the current layout state.
     *
     * @returns An array of serialized tile states.
     *
     * @public
     */
    saveLayout() {
        return this._serializer.save(this.tiles);
    }
    /**
     * Saves the current layout state as a JSON string.
     *
     * @returns A JSON string representing the layout.
     *
     * @public
     */
    saveLayoutAsJSON() {
        return this._serializer.saveAsJSON(this.tiles);
    }
    /**
     * Loads a previously saved layout.
     *
     * @param layout - The serialized layout to load.
     *
     * @public
     */
    loadLayout(layout) {
        this._serializer.load(this.tiles, layout);
        emit(this, 'layoutChange', {
            tiles: this.saveLayout()
        });
    }
    /**
     * Loads a layout from a JSON string.
     *
     * @param json - The JSON string representing the layout.
     *
     * @public
     */
    loadLayoutFromJSON(json) {
        this._serializer.loadFromJSON(this.tiles, json);
        emit(this, 'layoutChange', {
            tiles: this.saveLayout()
        });
    }
};
__decorate([
    Attribute({ type: String }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], TileManagerElement.prototype, "resizeMode", null);
__decorate([
    Attribute({ type: String }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], TileManagerElement.prototype, "dragMode", null);
__decorate([
    Attribute({ type: Number }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [Object])
], TileManagerElement.prototype, "columnCount", null);
__decorate([
    Attribute({ type: Number }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [Object])
], TileManagerElement.prototype, "minColumnWidth", null);
__decorate([
    Attribute({ type: Number }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [Object])
], TileManagerElement.prototype, "minRowHeight", null);
__decorate([
    Attribute({ type: Number }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [Object])
], TileManagerElement.prototype, "gap", null);
TileManagerElement = __decorate([
    Component({
        selector: 'mosaik-tile-manager',
        template: tileManagerElementTemplate,
        themes: {
            joy: tileManagerElementJoyStyle,
            memphis: tileManagerElementMemphisStyle,
            cosmopolitan: tileManagerElementCosmopolitanStyle
        },
        imports: []
    }),
    __metadata("design:paramtypes", [])
], TileManagerElement);
export { TileManagerElement };
//# sourceMappingURL=TileManagerElement.js.map