// #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 { HTMLElementEventEmitter } from '@breadstone/mosaik-elements';
import { Emit } from '../../../../events/Decorators/EmitDecorator';
import { addIntlController } from '../../../../Intl/IntlController';
import { Appearanceable } from '../../../Behaviors/Appearanceable';
import { Slottable } from '../../../Behaviors/Slottable';
import { Themeable } from '../../../Behaviors/Themeable';
import { addInheritanceProviderController } from '../../../Controllers/InheritanceProviderController';
import { Attribute } from '../../../Decorators/AttributeDecorator';
import { Component } from '../../../Decorators/ComponentDecorator';
import { TableSelectionMode } from '../../../Types/TableSelectionMode';
import { TableSelectionType } from '../../../Types/TableSelectionType';
import { CustomElement } from '../../Abstracts/CustomElement';
import { TextElement } from '../../Primitives/Text/TextElement';
import { TableElementIntl } from './intl/TableElementIntl';
import { tableElementTemplate } from './TableElementTemplate';
import { TABLE_INHERITANCE_CONTEXT } from './TableInheritanceContext';
import { tableElementCosmopolitanStyle } from './Themes/TableElement.Cosmopolitan';
import { tableElementJoyStyle } from './Themes/TableElement.Joy';
import { tableElementMemphisStyle } from './Themes/TableElement.Memphis';
// #endregion
/**
 * Table - A structured display of data in rows and columns.
 *
 * @element mosaik-table
 *
 * @slot  - The default slot.
 * @slot caption - The caption slot for the table title or description.
 *
 * @csspart caption - The caption part.
 *
 * @cssprop {String} --table-alternating-color - The alternating color CSS custom property.
 * @cssprop {String} --table-background-color - The background color CSS custom property.
 * @cssprop {String} --table-border-color - The border color CSS custom property.
 * @cssprop {String} --table-border-radius - The border radius CSS custom property.
 * @cssprop {String} --table-border-style - The border style CSS custom property.
 * @cssprop {String} --table-border-width - The border width CSS custom property.
 * @cssprop {String} --table-column-border-color - The column border color CSS custom property.
 * @cssprop {String} --table-column-border-radius - The column border radius CSS custom property.
 * @cssprop {String} --table-column-border-style - The column border style CSS custom property.
 * @cssprop {String} --table-column-border-width - The column border width CSS custom property.
 * @cssprop {String} --table-font-family - The font family CSS custom property.
 * @cssprop {String} --table-font-letter-spacing - The font letter spacing CSS custom property.
 * @cssprop {String} --table-font-line-height - The font line height CSS custom property.
 * @cssprop {String} --table-font-size - The font size CSS custom property.
 * @cssprop {String} --table-font-text-decoration - The font text decoration CSS custom property.
 * @cssprop {String} --table-font-text-transform - The font text transform CSS custom property.
 * @cssprop {String} --table-font-weight - The font weight CSS custom property.
 * @cssprop {String} --table-foreground-color - The foreground color CSS custom property.
 * @cssprop {String} --table-gap - The gap CSS custom property.
 * @cssprop {String} --table-line-thickness - The line thickness CSS custom property.
 * @cssprop {String} --table-padding-bottom - The padding bottom CSS custom property.
 * @cssprop {String} --table-padding-left - The padding left CSS custom property.
 * @cssprop {String} --table-padding-right - The padding right CSS custom property.
 * @cssprop {String} --table-padding-top - The padding top CSS custom property.
 * @cssprop {String} --table-row-border-color - The row border color CSS custom property.
 * @cssprop {String} --table-row-border-radius - The row border radius CSS custom property.
 * @cssprop {String} --table-row-border-style - The row border style CSS custom property.
 * @cssprop {String} --table-row-border-width - The row border width CSS custom property.
 * @cssprop {String} --table-shadow - The shadow CSS custom property.
 * @cssprop {String} --table-shadow-blur - The shadow blur CSS custom property.
 * @cssprop {String} --table-shadow-color - The shadow color CSS custom property.
 * @cssprop {String} --table-shadow-offset-x - The shadow offset x CSS custom property.
 * @cssprop {String} --table-shadow-offset-y - The shadow offset y CSS custom property.
 * @cssprop {String} --table-shadow-spread - The shadow spread CSS custom property.
 * @cssprop {String} --table-transition-duration - The transition duration CSS custom property.
 * @cssprop {String} --table-transition-mode - The transition mode CSS custom property.
 * @cssprop {String} --table-transition-property - The transition property CSS custom property.
 * @cssprop {String} --table-translate - The translate CSS custom property.
 *
 * @fires columnsChanged {TableColumnsChangedEvent} - Fired when the columns of the table has changed.
 * @fires tableSelectionChanged {TableSelectionChangedEvent} - Fired when the selection of the table has changed.
 * @fires tableChooseColumns {TableChooseColumnsEvent} - Fired when the choose columns action is requested from a header cell menu.
 *
 * @dependency mosaik-text - The Text element.
 *
 * @example
 * Basic data table:
 * ```html
 * <mosaik-table>
 *   <mosaik-table-header>
 *     <mosaik-table-row>
 *       <mosaik-table-cell text="Name" sortable></mosaik-table-cell>
 *       <mosaik-table-cell text="Role"></mosaik-table-cell>
 *     </mosaik-table-row>
 *   </mosaik-table-header>
 *   <mosaik-table-body>
 *     <mosaik-table-row>
 *       <mosaik-table-cell text="Alice"></mosaik-table-cell>
 *       <mosaik-table-cell text="Admin"></mosaik-table-cell>
 *     </mosaik-table-row>
 *   </mosaik-table-body>
 * </mosaik-table>
 * ```
 *
 * @public
 */
let TableElement = class TableElement extends Themeable(Appearanceable(Slottable(CustomElement))) {
    // #region Fields
    _intl;
    _columnsChanged;
    _tableSelectionChanged;
    _tableChooseColumns;
    _columns;
    _caption;
    _alternating;
    _selectionType;
    _selectionMode;
    _resizable;
    _sortMode;
    _selectedRows;
    _selectedCells;
    // #endregion
    // #region Ctor
    /**
     * @public
     */
    constructor() {
        super();
        this._intl = addIntlController(this, {
            factory: () => new TableElementIntl()
        });
        addInheritanceProviderController(this, {
            context: TABLE_INHERITANCE_CONTEXT,
            values: () => ({
                appearance: this.appearance,
                alternating: this.alternating,
                selectionType: this.selectionType,
                selectionMode: this.selectionMode,
                resizable: this.resizable,
                intl: this.intl,
                sortMode: this.sortMode
            })
        });
        this._columns = '';
        this._caption = '';
        this._alternating = false;
        this._selectionType = TableSelectionType.Row;
        this._selectionMode = TableSelectionMode.None;
        this._resizable = false;
        this._sortMode = 'single';
        this._selectedRows = [];
        this._selectedCells = [];
        this._columnsChanged = new HTMLElementEventEmitter(this, 'columnsChanged');
        this._tableSelectionChanged = new HTMLElementEventEmitter(this, 'tableSelectionChanged');
        this._tableChooseColumns = new HTMLElementEventEmitter(this, 'tableChooseColumns');
    }
    // #endregion
    // #region Properties
    /**
     * Returns the `is` property.
     *
     * @public
     * @static
     * @readonly
    */
    static get is() {
        return 'mosaik-table';
    }
    /**
     * Returns the `intl` property.
     *
     * @public
     * @readonly
     */
    get intl() {
        return this._intl.intl;
    }
    /**
     * Gets or sets the `columns` property.
     *
     * @public
     * @attr
     */
    get columns() {
        return this._columns;
    }
    set columns(value) {
        if (this._columns !== value) {
            this._columns = value;
            this.requestUpdate('columns');
            this._columnsChanged.emit({
                columns: value
            });
        }
    }
    /**
     * Gets or sets the `caption` property.
     *
     * @public
     * @attr
     */
    get caption() {
        return this._caption;
    }
    set caption(value) {
        if (this._caption !== value) {
            this._caption = value;
            this.requestUpdate('caption');
        }
    }
    /**
     * Gets or sets the `alternating` property.
     *
     * @public
     * @attr
     */
    get alternating() {
        return this._alternating;
    }
    set alternating(value) {
        if (this._alternating !== value) {
            this._alternating = value;
            this.requestUpdate('alternating');
        }
    }
    /**
     * Gets or sets the `selectionType` property.
     *
     * @public
     * @attr
     */
    get selectionType() {
        return this._selectionType;
    }
    set selectionType(value) {
        if (this._selectionType !== value) {
            this._selectionType = value;
            this.requestUpdate('selectionType');
        }
    }
    /**
     * Gets or sets the `selectionMode` property.
     * Defines whether selection is disabled, single, or multiple.
     * If set to `none`, the configured `selectionType` remains available
     * but has no behavioral effect.
     *
     * @public
     * @attr
     */
    get selectionMode() {
        return this._selectionMode;
    }
    set selectionMode(value) {
        if (this._selectionMode !== value) {
            this._selectionMode = value;
            this.requestUpdate('selectionMode');
        }
    }
    /**
     * Gets or sets the `resizable` property.
     * When true, columns are resizable by default.
     *
     * @public
     * @attr
     */
    get resizable() {
        return this._resizable;
    }
    set resizable(value) {
        if (this._resizable !== value) {
            this._resizable = value;
            this.requestUpdate('resizable');
        }
    }
    /**
     * Gets or sets the `sortMode` property.
     * Defines whether sort is single-column (default) or multi-column.
     *
     * @public
     * @attr
     */
    get sortMode() {
        return this._sortMode;
    }
    set sortMode(value) {
        if (this._sortMode !== value) {
            this._sortMode = value;
            this.requestUpdate('sortMode');
        }
    }
    /**
     * Called when the columns of the table has changed.
     * Provides reference to `ITableColumnsChangedEventDetail` as event argument.
     *
     * @public
     * @readonly
     * @eventProperty
     * @type IEventEmitter<ITableColumnsChangedEventDetail>
     */
    get columnsChanged() {
        return this._columnsChanged;
    }
    /**
     * Called when the selection of the table has changed.
     * Provides reference to `ITableSelectionChangedEventDetail` as event argument.
     *
     * @public
     * @readonly
     * @eventProperty
     * @type IEventEmitter<ITableSelectionChangedEventDetail>
     */
    get tableSelectionChanged() {
        return this._tableSelectionChanged;
    }
    /**
     * Called when the choose columns action is requested.
     * Provides reference to `ITableChooseColumnsEventDetail` as event argument.
     *
     * @public
     * @readonly
     * @eventProperty
     * @type IEventEmitter<ITableChooseColumnsEventDetail>
     */
    get tableChooseColumns() {
        return this._tableChooseColumns;
    }
    /**
     * Gets the currently selected rows.
     *
     * @public
     * @readonly
     */
    get selectedRows() {
        return this._selectedRows;
    }
    /**
     * Gets the currently selected cells.
     *
     * @public
     * @readonly
     */
    get selectedCells() {
        return this._selectedCells;
    }
    // #endregion
    // #region Methods
    /**
     * Handles row selection triggered by a child `TableBodyRowElement`.
     *
     * @internal
     */
    handleRowSelect(row) {
        if (this._selectionMode === TableSelectionMode.None) {
            return;
        }
        const wasSelected = row.isSelected;
        if (this._selectionMode === TableSelectionMode.Single) {
            // Deselect all other rows
            for (const selected of this._selectedRows) {
                if (selected !== row) {
                    selected.deselect();
                }
            }
            this._selectedRows = [];
            if (!wasSelected) {
                row.select();
                this._selectedRows = [row];
            }
        }
        else if (this._selectionMode === TableSelectionMode.Multiple) {
            if (wasSelected) {
                row.deselect();
                this._selectedRows = this._selectedRows.filter((r) => r !== row);
            }
            else {
                row.select();
                this._selectedRows = [...this._selectedRows, row];
            }
        }
        this._tableSelectionChanged.emit({
            selectedRows: [...this._selectedRows],
            selectedCells: []
        });
    }
    /**
     * Handles cell selection triggered by a child `TableBodyCellElement`.
     *
     * @internal
     */
    handleCellSelect(cell) {
        if (this._selectionMode === TableSelectionMode.None) {
            return;
        }
        const wasSelected = cell.isSelected;
        if (this._selectionMode === TableSelectionMode.Single) {
            // Deselect all other cells
            for (const selected of this._selectedCells) {
                if (selected !== cell) {
                    selected.deselect();
                }
            }
            this._selectedCells = [];
            if (!wasSelected) {
                cell.select();
                this._selectedCells = [cell];
            }
        }
        else if (this._selectionMode === TableSelectionMode.Multiple) {
            if (wasSelected) {
                cell.deselect();
                this._selectedCells = this._selectedCells.filter((c) => c !== cell);
            }
            else {
                cell.select();
                this._selectedCells = [...this._selectedCells, cell];
            }
        }
        this._tableSelectionChanged.emit({
            selectedRows: [],
            selectedCells: [...this._selectedCells]
        });
    }
    /**
     * @public
     * @override
     */
    connectedCallback() {
        super.connectedCallback();
        this.addEventListener('tableColumnResized', this.handleColumnResized);
        this.addEventListener('tableRequestChooseColumns', this.handleRequestChooseColumns);
    }
    /**
     * @public
     * @override
     */
    disconnectedCallback() {
        super.disconnectedCallback();
        this.removeEventListener('tableColumnResized', this.handleColumnResized);
        this.removeEventListener('tableRequestChooseColumns', this.handleRequestChooseColumns);
    }
    /**
     * Updates the column width at the specified index.
     * If no explicit columns are set, initializes from current header cell widths.
     *
     * @public
     */
    updateColumnWidth(columnIndex, widthPx) {
        let parts = this._columns ? this._columns.trim().split(/\s+/) : [];
        // Initialize from current header cell widths if columns are not explicitly set
        // or contain relative units (e.g. 1fr) that would cause layout issues when mixed with px.
        const hasRelativeUnits = parts.some((p) => /fr|%|auto|min-content|max-content|minmax/i.test(p));
        if (parts.length === 0 || (parts.length === 1 && parts[0] === '') || hasRelativeUnits) {
            parts = this.initializeColumnsFromHeaderCells();
        }
        if (columnIndex < 0 || columnIndex >= parts.length) {
            return;
        }
        parts[columnIndex] = `${Math.round(widthPx)}px`;
        this.columns = parts.join(' ');
    }
    /**
     * Returns metadata for each column derived from header cells.
     * Used by rows to propagate pinning and hiding to body/footer cells.
     *
     * @public
     */
    getColumnMetadata() {
        const headerCells = this.querySelectorAll('mosaik-table-header-cell');
        return Array.from(headerCells).map((cell) => ({
            key: cell.key || '', pinned: cell.pinned || 'none',
            hidden: cell.columnHidden === true
        }));
    }
    /**
     * Returns an array of column editor items derived from header cells.
     * Each item contains the key, title, and current visibility state.
     *
     * @public
     */
    getColumnEditorItems() {
        const headerCells = this.querySelectorAll('mosaik-table-header-cell');
        return Array.from(headerCells).map((cell) => ({
            key: cell.getAttribute('key') || cell.textContent?.trim() || '',
            title: cell.getAttribute('text') || cell.textContent?.trim() || '',
            visible: !cell.columnHidden
        }));
    }
    /**
     * Handles the internal `tableRequestChooseColumns` event from header cells.
     *
     * @private
     */
    handleRequestChooseColumns = (event) => {
        event.stopPropagation();
        this._tableChooseColumns.emit({
            columns: this.getColumnEditorItems()
        });
    };
    /**
     * Handles column resized events from header cells.
     *
     * @private
     */
    handleColumnResized = (event) => {
        const { columnIndex, width } = event.detail;
        if (columnIndex >= 0) {
            this.updateColumnWidth(columnIndex, width);
        }
    };
    /**
     * Notifies all rows that column metadata (pinning/hiding) has changed.
     * Called directly by child header cells when pinning state changes.
     *
     * @private
     * @hidden
     */
    notifyColumnMetadataChanged() {
        this._columnsChanged.emit({
            columns: this._columns
        });
    }
    /**
     * Reads the current rendered widths of all header cells and returns them as pixel values.
     *
     * @private
     */
    initializeColumnsFromHeaderCells() {
        const headerCells = this.querySelectorAll('mosaik-table-header-cell');
        return Array.from(headerCells).map((cell) => {
            const width = cell.getBoundingClientRect().width;
            return `${Math.round(width)}px`;
        });
    }
    /**
     * Auto-sizes a column to fit the widest content across header and body cells.
     * Uses `getContentWidth()` on each cell for accurate measurement that handles
     * truncated text, flex-constrained layouts and shadow DOM content.
     *
     * @public
     */
    autoSizeColumn(columnIndex) {
        const headerCells = this.querySelectorAll('mosaik-table-header-cell');
        if (columnIndex < 0 || columnIndex >= headerCells.length) {
            return;
        }
        // Clear any leftover inline width on the target header cell
        headerCells[columnIndex].style.removeProperty('width');
        let maxWidth = headerCells[columnIndex].getContentWidth();
        const bodyRows = Array.from(this.querySelectorAll('mosaik-table-body-row'));
        for (const row of bodyRows) {
            const cells = row.querySelectorAll('mosaik-table-body-cell');
            if (columnIndex < cells.length) {
                maxWidth = Math.max(maxWidth, cells[columnIndex].getContentWidth());
            }
        }
        this.updateColumnWidth(columnIndex, Math.ceil(maxWidth));
    }
};
__decorate([
    Attribute({ type: String }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], TableElement.prototype, "columns", null);
__decorate([
    Attribute({ type: String }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], TableElement.prototype, "caption", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], TableElement.prototype, "alternating", null);
__decorate([
    Attribute({
        type: TableSelectionType
    }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], TableElement.prototype, "selectionType", null);
__decorate([
    Attribute({
        type: TableSelectionMode
    }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], TableElement.prototype, "selectionMode", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], TableElement.prototype, "resizable", null);
__decorate([
    Attribute({
        type: String,
        useDefault: true
    }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], TableElement.prototype, "sortMode", null);
__decorate([
    Emit({ eventName: 'columnsChanged' }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [])
], TableElement.prototype, "columnsChanged", null);
__decorate([
    Emit({ eventName: 'tableSelectionChanged' }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [])
], TableElement.prototype, "tableSelectionChanged", null);
__decorate([
    Emit({ eventName: 'tableChooseColumns' }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [])
], TableElement.prototype, "tableChooseColumns", null);
TableElement = __decorate([
    Component({
        selector: 'mosaik-table',
        template: tableElementTemplate,
        themes: {
            joy: tableElementJoyStyle,
            memphis: tableElementMemphisStyle,
            cosmopolitan: tableElementCosmopolitanStyle
        },
        imports: [
            TextElement
        ]
    }),
    __metadata("design:paramtypes", [])
], TableElement);
export { TableElement };
//# sourceMappingURL=TableElement.js.map