// #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 { IntlController } from '../../../../Intl/IntlController';
import { Appearanceable } from '../../../Behaviors/Appearanceable';
import { Disableable } from '../../../Behaviors/Disableable';
import { Themeable } from '../../../Behaviors/Themeable';
import { Variantable } from '../../../Behaviors/Variantable';
import { Attribute } from '../../../Decorators/AttributeDecorator';
import { Component } from '../../../Decorators/ComponentDecorator';
import { CustomElement } from '../../Abstracts/CustomElement';
import { ButtonElement } from '../../Buttons/Button/ButtonElement';
import { SelectElement } from '../../Inputs/Select/SelectElement';
import { TextElement } from '../Text/TextElement';
import { IPaginatorElementProps } from './IPaginatorElementProps';
import { PaginatorElementIntl } from './PaginatorElementIntl';
import { paginatorElementTemplate } from './PaginatorElementTemplate';
import { paginatorElementCosmopolitanStyle } from './Themes/PaginatorElement.Cosmopolitan';
import { paginatorElementJoyStyle } from './Themes/PaginatorElement.Joy';
import { paginatorElementMemphisStyle } from './Themes/PaginatorElement.Memphis';
// #endregion
/**
 * Paginator - A component that provides pagination controls for navigating through large datasets.
 *
 * @description The Paginator component is designed to allow users to navigate through paginated content. It typically includes controls like "Next", "Previous", and page numbers, enabling users to move between different pages of a dataset without needing to load everything at once.
 *
 * @name Paginator
 * @element mosaik-paginator
 * @category UI Components
 *
 * @slot previous - The slot for the "Previous" button in the paginator.
 * @slot next - The slot for the "Next" button in the paginator.
 * @slot pages - The slot for the page number buttons.
 *
 * @csspart container - The main container element.
 * @csspart first - The first page button.
 * @csspart previous - The previous page button.
 * @csspart pages-container - The container for the page number buttons.
 * @csspart page - Individual page button.
 * @csspart next - The next page button.
 * @csspart last - The last page button.
 * @csspart range-container - The container for the page range display.
 * @csspart range - The range display showing current page range.
 * @csspart size-selector-container - The container for the page size selector.
 * @csspart size-selector - The page size selector itself.
 *
 * @cssprop {String} --paginator-font-family - The font-family property for the paginator text.
 * @cssprop {String} --paginator-font-size - The font-size property for the paginator text.
 * @cssprop {String} --paginator-font-line-height - The line-height property for the paginator text.
 * @cssprop {String} --paginator-font-weight - The font-weight property for the paginator text.
 * @cssprop {String} --paginator-font-letter-spacing - The letter-spacing property for the paginator text.
 * @cssprop {String} --paginator-font-text-decoration - The text-decoration property for the paginator text.
 * @cssprop {String} --paginator-font-text-transform - The text-transform property for the paginator text.
 * @cssprop {Color} --paginator-background-color - The background-color property for the paginator.
 * @cssprop {Color} --paginator-border-color - The border-color property for the paginator.
 * @cssprop {Color} --paginator-foreground-color - The foreground-color property for the paginator.
 * @cssprop {String} --paginator-border-width - The border-width property for the paginator.
 * @cssprop {String} --paginator-border-radius - The border-radius property for the paginator.
 * @cssprop {String} --paginator-border-style - The border-style property for the paginator.
 * @cssprop {String} --paginator-shadow - The shadow property for the paginator.
 * @cssprop {String} --paginator-gap - The gap property between paginator elements.
 *
 * @dependency {ButtonElement} - The Button element used for pagination controls.
 * @dependency {TextElement} - The Text element used for displaying page numbers.
 * @dependency {SelectElement} - The Select element used for selecting page sizes.
 *
 * @fires pageChanged {PageChangedEvent} - Fired when the current page changes.
 * @fires pageSizeChanged {PageSizeChangedEvent} - Fired when the page size changes.
 *
 * @example
 * Basic paginator:
 * ```html
 * <mosaik-paginator total="100" size="20"></mosaik-paginator>
 * ```
 *
 * @example
 * Paginator with page size selector:
 * ```html
 * <mosaik-paginator
 *   total="250"
 *   size="50"
 *   show-sizes
 *   .sizes="${[25, 50, 100]}">
 * </mosaik-paginator>
 * ```
 *
 * @public
 */
let PaginatorElement = class PaginatorElement extends Themeable(Disableable(Variantable(Appearanceable(CustomElement)))) {
    // #region Fields
    _intl;
    _pageChanged;
    _pageSizeChanged;
    _total;
    _size;
    _sizes;
    _showSizes;
    _currentPage;
    _showFirstLastButtons;
    // #endregion
    // #region Ctor
    /**
     * @public
     */
    constructor() {
        super();
        this._intl = new IntlController(this, {
            factory: () => new PaginatorElementIntl()
        });
        this._pageChanged = new HTMLElementEventEmitter(this, 'pageChanged');
        this._pageSizeChanged = new HTMLElementEventEmitter(this, 'pageSizeChanged');
        this._total = IPaginatorElementProps.DEFAULTS.total;
        this._size = IPaginatorElementProps.DEFAULTS.size;
        this._sizes = IPaginatorElementProps.DEFAULTS.sizes;
        this._showSizes = IPaginatorElementProps.DEFAULTS.showSizes;
        this._currentPage = IPaginatorElementProps.DEFAULTS.currentPage;
        this._showFirstLastButtons = IPaginatorElementProps.DEFAULTS.showFirstLastButtons;
    }
    // #endregion
    // #region Properties
    /**
     * Returns the `{@link is}` property.
     * The `{@link is}` property represents natural name of this element.
     *
     * @public
     * @static
     * @readonly
     */
    static get is() {
        return 'mosaik-paginator';
    }
    /**
     * Gets or sets the `total` property.
     *
     * @public
     * @attr
     */
    get total() {
        return this._total;
    }
    set total(value) {
        if (this._total !== value) {
            this._total = value;
            this.requestUpdate('total');
        }
    }
    /**
     * Gets or sets the `size` property.
     *
     * @public
     * @attr
     */
    get size() { return this._size; }
    set size(value) {
        if (this._size !== value) {
            this._size = value;
            this.requestUpdate('size');
        }
    }
    /**
     * Gets or sets the `sizes` property.
     *
     * @public
     * @attr
     */
    get sizes() {
        return this._sizes;
    }
    set sizes(value) {
        if (this._sizes !== value) {
            this._sizes = value;
            this.requestUpdate('sizes');
        }
    }
    /**
     * Gets or sets the `showSizes` property.
     *
     * @public
     * @attr
     */
    get showSizes() {
        return this._showSizes;
    }
    set showSizes(value) {
        if (this._showSizes !== value) {
            this._showSizes = value;
            this.requestUpdate('showSizes');
        }
    }
    /**
     * Returns the `intl` property.
     *
     * @public
     * @readonly
     */
    get intl() {
        return this._intl.intl;
    }
    /**
     * Gets or sets the `currentPage` property (0-based index).
     *
     * @public
     * @attr
     */
    get currentPage() {
        return this._currentPage;
    }
    set currentPage(value) {
        const clampedValue = Math.max(0, Math.min(value, this.totalPages - 1));
        if (this._currentPage !== clampedValue) {
            this._currentPage = clampedValue;
            this.requestUpdate('currentPage');
        }
    }
    /**
     * Gets or sets the `showFirstLastButtons` property.
     *
     * @public
     * @attr
     */
    get showFirstLastButtons() {
        return this._showFirstLastButtons;
    }
    set showFirstLastButtons(value) {
        if (this._showFirstLastButtons !== value) {
            this._showFirstLastButtons = value;
            this.requestUpdate('showFirstLastButtons');
        }
    }
    /**
     * Gets the total number of pages.
     *
     * @public
     * @readonly
     */
    get totalPages() {
        if (this._total <= 0 || this._size <= 0) {
            return 0;
        }
        return Math.ceil(this._total / this._size);
    }
    /**
     * Gets the start index of the current page range (1-based).
     *
     * @public
     * @readonly
     */
    get rangeStart() {
        if (this._total === 0) {
            return 0;
        }
        return this._currentPage * this._size + 1;
    }
    /**
     * Gets the end index of the current page range (1-based).
     *
     * @public
     * @readonly
     */
    get rangeEnd() {
        if (this._total === 0) {
            return 0;
        }
        return Math.min((this._currentPage + 1) * this._size, this._total);
    }
    /**
     * Gets a value indicating whether there is a previous page.
     *
     * @public
     * @readonly
     */
    get hasPreviousPage() {
        return this._currentPage > 0;
    }
    /**
     * Gets a value indicating whether there is a next page.
     *
     * @public
     * @readonly
     */
    get hasNextPage() {
        return this._currentPage < this.totalPages - 1;
    }
    /**
     * Called when the page changes.
     * Provides reference to the `IEventEmitter` as event argument.
     *
     * @public
     * @eventProperty
     * @readonly
     */
    get pageChanged() {
        return this._pageChanged;
    }
    /**
     * Called when the page size changes.
     * Provides reference to the `IEventEmitter` as event argument.
     *
     * @public
     * @eventProperty
     * @readonly
     */
    get pageSizeChanged() {
        return this._pageSizeChanged;
    }
    // #endregion
    // #region Methods
    /**
     * Navigates to the first page.
     *
     * @public
     */
    goToFirstPage() {
        if (this.hasPreviousPage && !this.disabled) {
            this.goToPage(0);
        }
    }
    /**
     * Navigates to the last page.
     *
     * @public
     */
    goToLastPage() {
        if (this.hasNextPage && !this.disabled) {
            this.goToPage(this.totalPages - 1);
        }
    }
    /**
     * Navigates to the next page.
     *
     * @public
     */
    goToNextPage() {
        if (this.hasNextPage && !this.disabled) {
            this.goToPage(this._currentPage + 1);
        }
    }
    /**
     * Navigates to the previous page.
     *
     * @public
     */
    goToPreviousPage() {
        if (this.hasPreviousPage && !this.disabled) {
            this.goToPage(this._currentPage - 1);
        }
    }
    /**
     * Navigates to a specific page (0-based index).
     *
     * @public
     * @param pageIndex - The page index to navigate to.
     */
    goToPage(pageIndex) {
        if (this.disabled) {
            return;
        }
        const previousPage = this._currentPage;
        this.currentPage = pageIndex;
        if (previousPage !== this._currentPage) {
            this._pageChanged.emit({
                pageIndex: this._currentPage,
                pageSize: this._size,
                totalItems: this._total
            });
        }
    }
    /**
     * Changes the page size and resets to the first page.
     *
     * @public
     * @param newSize - The new page size.
     */
    changePageSize(newSize) {
        if (this.disabled || newSize <= 0) {
            return;
        }
        const previousSize = this._size;
        this._size = newSize;
        this._currentPage = 0;
        this.requestUpdate('size');
        this.requestUpdate('currentPage');
        if (previousSize !== this._size) {
            this._pageSizeChanged.emit({
                pageIndex: this._currentPage,
                pageSize: this._size,
                totalItems: this._total
            });
        }
    }
    /**
     * Calculates the page buttons for pagination.
     *
     * @private
     * @template
     * @param total - Total number of items.
     * @param size - Number of items per page.
     * @returns An array of page numbers.
     */
    calculatePages(total, size) {
        if (total <= 0 || size <= 0) {
            return [];
        }
        const totalPages = Math.ceil(total / size);
        const pages = [];
        for (let i = 1; i <= totalPages; i++) {
            pages.push(i);
        }
        return pages;
    }
};
__decorate([
    Attribute({ type: Number }),
    __metadata("design:type", Number),
    __metadata("design:paramtypes", [Number])
], PaginatorElement.prototype, "total", null);
__decorate([
    Attribute({ type: Number }),
    __metadata("design:type", Number),
    __metadata("design:paramtypes", [Number])
], PaginatorElement.prototype, "size", null);
__decorate([
    Attribute({ type: (Array) }),
    __metadata("design:type", Array),
    __metadata("design:paramtypes", [Array])
], PaginatorElement.prototype, "sizes", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], PaginatorElement.prototype, "showSizes", null);
__decorate([
    Attribute({ type: Number }),
    __metadata("design:type", Number),
    __metadata("design:paramtypes", [Number])
], PaginatorElement.prototype, "currentPage", null);
__decorate([
    Attribute({ type: Boolean, useDefault: true }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], PaginatorElement.prototype, "showFirstLastButtons", null);
__decorate([
    Emit({ eventName: 'pageChanged' }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [])
], PaginatorElement.prototype, "pageChanged", null);
__decorate([
    Emit({ eventName: 'pageSizeChanged' }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [])
], PaginatorElement.prototype, "pageSizeChanged", null);
PaginatorElement = __decorate([
    Component({
        selector: 'mosaik-paginator',
        template: paginatorElementTemplate,
        themes: {
            joy: paginatorElementJoyStyle,
            memphis: paginatorElementMemphisStyle,
            cosmopolitan: paginatorElementCosmopolitanStyle
        },
        imports: [
            ButtonElement,
            TextElement,
            SelectElement
        ]
    }),
    __metadata("design:paramtypes", [])
], PaginatorElement);
export { PaginatorElement };
//# sourceMappingURL=PaginatorElement.js.map