import { __decorate, __param } from 'tslib';
import { Directive, ContentChildren, TemplateRef, Input, Component, ChangeDetectionStrategy, ViewEncapsulation, Optional, Host, Attribute, HostListener, forwardRef, NgModule } from '@angular/core';
import { DataSourceRequest } from '@bravobit/bb-foundation/api';
import { tap, map, catchError, debounceTime, distinctUntilChanged, startWith, share } from 'rxjs/operators';
import { of, combineLatest, BehaviorSubject } from 'rxjs';
import { FormControl, FormGroup, NG_VALUE_ACCESSOR, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { mixinDisabled } from '@bravobit/bb-foundation';
import { ElementsModule } from '@bravobit/bb-foundation/elements';
import { LocalizeModule } from '@bravobit/bb-foundation/localize';
import { CommonModule } from '@angular/common';

let BbTableColumnDef = class BbTableColumnDef {
};
BbTableColumnDef = __decorate([
    Directive({
        selector: '[bbTableColumnDef]'
    })
], BbTableColumnDef);
let BbTable = class BbTable {
    constructor() {
        // Inputs.
        this.identifier = null;
        this.queryFields = [];
        this.sortingStrategy = 'single';
        this.header = true;
        this.footer = true;
        // Sizes.
        this._sizes = [25, 50, 75, 100];
        // Optimizations.
        this.trackByFn = (index, item) => this.identifier ? item[this.identifier] : index;
        this.trackByValue = (index, item) => item;
        this.queryControl = new FormControl('');
    }
    get sizes() {
        return this._sizes;
    }
    set sizes(newValue) {
        this.updateSizes(newValue);
    }
    ngOnInit() {
        this.composeForm();
        this.watchDataChanges();
    }
    ngOnDestroy() {
        this._subscription && this._subscription.unsubscribe();
    }
    get sortControl() {
        return this.form.get('sort');
    }
    get pageNumberControl() {
        return this.form.get('pageNumber');
    }
    get pageSizeControl() {
        return this.form.get('pageSize');
    }
    refresh() {
        return this.request.update();
    }
    updateSizes(newValue) {
        // Validate the sizes has at least one value.
        if (newValue.length <= 0) {
            throw new Error('Cannot set an empty array as the sizes.');
        }
        // Set the new size.
        this._sizes = newValue;
        // Validate that the form exists already.
        if (!this.form) {
            return;
        }
        // Check if the current selected value is
        // in the new sizes array.
        const pageSizeControl = this.form.get('pageSize');
        if (this._sizes.includes(pageSizeControl.value)) {
            return;
        }
        // Set the first value in the array as
        // the new value.
        const firstValue = this._sizes[0];
        pageSizeControl.setValue(firstValue);
    }
    composeForm() {
        // Setup the form.
        this.form = new FormGroup({
            pageSize: new FormControl(this._sizes[0]),
            pageNumber: new FormControl(1),
            sort: new FormGroup({})
        });
    }
    watchDataChanges() {
        // Create a new request.
        this.request = new DataSourceRequest();
        this.isLoading$ = this.request.loading;
        if (!this.dataSource) {
            this.data$ = of({ state: 'error_datasource' }).pipe(tap(() => this.request.stopLoading()));
            return;
        }
        // Pass the request to the data source.
        this.data$ = this.dataSource.handle(this.request).pipe(tap(() => this.request.stopLoading()), map(result => {
            const count = (result && result.data && result.data.length) || 0;
            if (count <= 0) {
                return { state: 'empty', result };
            }
            return { state: 'success', result };
        }), catchError((error) => {
            this.request.stopLoading();
            const states = {
                401: 'error_unauthorized',
                403: 'error_forbidden',
                404: 'error_not_found',
                500: 'error_server'
            };
            return of({ state: states[error.status] || 'error_unknown', statusCode: error.status });
        }));
        // Subscribe to the data changes.
        this.subscribeToChanges();
    }
    subscribeToChanges() {
        const form$ = this.getFormChanges();
        const query$ = this.getQueryChanges();
        this._subscription = combineLatest([form$, query$]).subscribe(([form, query]) => {
            const { pageNumber, pageSize } = form;
            const sort = Object.keys(form.sort)
                .map(name => ({ name, direction: form.sort[name] }))
                .filter(item => ['asc', 'desc'].includes(item.direction));
            this.request.startLoading();
            return this.request.update({
                sort,
                query,
                pageSize,
                pageNumber,
                queryFields: this.queryFields
            });
        });
    }
    getQueryChanges() {
        return this.queryControl.valueChanges.pipe(debounceTime(400), distinctUntilChanged(), startWith(this.queryControl.value));
    }
    getFormChanges() {
        return this.form.valueChanges.pipe(startWith(this.form.value));
    }
};
__decorate([
    ContentChildren(BbTableColumnDef, { read: TemplateRef })
], BbTable.prototype, "tableColumnTemplates", void 0);
__decorate([
    Input()
], BbTable.prototype, "identifier", void 0);
__decorate([
    Input()
], BbTable.prototype, "dataSource", void 0);
__decorate([
    Input()
], BbTable.prototype, "queryFields", void 0);
__decorate([
    Input()
], BbTable.prototype, "sortingStrategy", void 0);
__decorate([
    Input()
], BbTable.prototype, "header", void 0);
__decorate([
    Input()
], BbTable.prototype, "footer", void 0);
__decorate([
    Input()
], BbTable.prototype, "sizes", null);
BbTable = __decorate([
    Component({
        selector: 'bb-table',
        template: "<!--\n    This is the header of the table. It can be a user\n    defined custom header or just the default header.\n-->\n\n<header *ngIf=\"(header === true ? headerTemplate : header) as template\"\n        class=\"bb-table-top-actions\">\n    <ng-container *ngTemplateOutlet=\"template\"></ng-container>\n</header>\n\n<!--\n    This is the table that contains the\n    rows and columns.\n-->\n\n<div class=\"bb-table-wrapper\">\n    <div *ngIf=\"isLoading$ | async\"\n         class=\"bb-table-progress\">\n        <div class=\"bb-table-indeterminate\"></div>\n    </div>\n    <table class=\"bb-table-container\">\n        <thead>\n            <tr>\n                <ng-content select=\"bb-table-header-cell\"></ng-content>\n            </tr>\n        </thead>\n        <tbody *ngIf=\"data$ | async as data; else isLoadingTemplate\"\n               [ngSwitch]=\"data?.state\">\n            <ng-container *ngSwitchCase=\"'success'\">\n                <tr *ngFor=\"let item of data?.result?.data; trackBy: trackByFn\">\n                    <ng-container *ngFor=\"let template of tableColumnTemplates\">\n                        <ng-container *ngTemplateOutlet=\"template; context: {item: item}\"></ng-container>\n                    </ng-container>\n                </tr>\n            </ng-container>\n\n            <ng-container *ngSwitchCase=\"'empty'\">\n                <ng-container\n                    *ngTemplateOutlet=\"errorTemplate; context: data\"></ng-container>\n            </ng-container>\n\n            <ng-container *ngSwitchCase=\"'error_datasource'\">\n                <ng-container\n                    *ngTemplateOutlet=\"errorTemplate; context: data\"></ng-container>\n            </ng-container>\n\n            <ng-container *ngSwitchCase=\"'error_not_found'\">\n                <ng-container\n                    *ngTemplateOutlet=\"errorTemplate; context: data\"></ng-container>\n            </ng-container>\n\n            <ng-container *ngSwitchCase=\"'error_server'\">\n                <ng-container\n                    *ngTemplateOutlet=\"errorTemplate; context: data\"></ng-container>\n            </ng-container>\n\n            <ng-container *ngSwitchDefault>\n                <ng-container\n                    *ngTemplateOutlet=\"errorTemplate; context: data\"></ng-container>\n            </ng-container>\n        </tbody>\n    </table>\n</div>\n\n<footer *ngIf=\"(footer === true ? footerTemplate : footer) as template\"\n        class=\"bb-table-bottom-actions\">\n    <ng-container *ngTemplateOutlet=\"template\"></ng-container>\n</footer>\n\n<ng-template #isLoadingTemplate>\n    <tr>\n        <td [attr.colspan]=\"tableColumnTemplates?.length\"\n            class=\"bb-table-template\">\n            <div class=\"bb-table-template-content\">\n                {{ 'tables.loading' | bbLocalize }}\n            </div>\n        </td>\n    </tr>\n</ng-template>\n\n<!--\n    This is the template that will be used when the user has not\n    supplied a custom header template.\n-->\n\n<ng-template #headerTemplate>\n    <ng-content></ng-content>\n    <bb-form-control>\n        <input [formControl]=\"queryControl\"\n               [placeholder]=\"'tables.search' | bbLocalize\"\n               bbInput\n               autocomplete=\"off\">\n        <bb-icon *ngIf=\"queryControl?.value?.length <= 0; else closeButtonTemplate\"\n                 bbSuffix\n                 src=\"material:search\">\n        </bb-icon>\n    </bb-form-control>\n</ng-template>\n\n<!--\n    This is the template that will be used when the user has not\n    supplied a custom footer template.\n-->\n\n<ng-template #footerTemplate>\n    <bb-form-control *ngIf=\"sizes?.length > 1\">\n        <select [formControl]=\"pageSizeControl\"\n                bbInput\n                title=\"Sizes\">\n            <option *ngFor=\"let item of sizes; trackBy: trackByValue\"\n                    [ngValue]=\"item\">\n                {{ item }} / {{ 'tables.page' | bbLocalize }}\n            </option>\n        </select>\n    </bb-form-control>\n\n    <bb-table-pager [totalPages]=\"(data$ | async)?.result?.totalPages\"\n                    [formControl]=\"pageNumberControl\">\n    </bb-table-pager>\n</ng-template>\n\n<!--\n    This the template that will be used when the user\n    has filled in some data in the query control.\n-->\n\n<ng-template #closeButtonTemplate>\n    <button bbSuffix\n            (click)=\"queryControl?.patchValue('')\"\n            type=\"button\"\n            class=\"bb-table-progress-close-query\">\n        <bb-icon src=\"material:close\"></bb-icon>\n    </button>\n</ng-template>\n\n<ng-template #errorTemplate let-state=\"state\" let-status=\"statusCode\">\n    <tr>\n        <td [attr.colspan]=\"tableColumnTemplates?.length\"\n            class=\"bb-table-template\">\n            <div class=\"bb-table-template-content\">\n                <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"64\" height=\"41\">\n                    <g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(0 1)\">\n                        <ellipse cx=\"32\" cy=\"33\" fill=\"#F5F5F5\" rx=\"32\" ry=\"7\"></ellipse>\n                        <g fill-rule=\"nonzero\" stroke=\"#D9D9D9\">\n                            <path\n                                d=\"M55 12.7605604L44.8543047 1.25739633C44.3674414.47382661 43.6558789 0 42.9067617 0H21.0932383c-.7491172 0-1.4606797.47395025-1.947543 1.25739633L9 12.7605604V22h46v-9.2394396z\"></path>\n                            <path fill=\"#FAFAFA\"\n                                  d=\"M41.6132813 15.9315c0-1.6056489.9936718-2.931266 2.2264179-2.9315H55v18.1371277C55 33.2589574 53.6793867 35 52.0504297 35H11.94957031C10.32052344 35 9 33.2588404 9 31.1371277V13h11.1603008c1.2327461 0 2.226418 1.3228085 2.226418 2.9284574v.0211809c0 1.6056489 1.0049921 2.9015426 2.2377382 2.9015426h14.751086c1.2327461 0 2.2377383-1.3078298 2.2377383-2.9134788V15.9315z\"></path>\n                        </g>\n                    </g>\n                </svg>\n                <span *ngIf=\"state as stateLabel\">{{ ('tables.' + stateLabel) | bbLocalize }}</span>\n                <span *ngIf=\"status as statusCode\"\n                      class=\"bb-table-template-content-code\">(HTTP {{ statusCode }})</span>\n            </div>\n        </td>\n    </tr>\n</ng-template>\n",
        host: { 'class': 'bb-table' },
        changeDetection: ChangeDetectionStrategy.OnPush,
        encapsulation: ViewEncapsulation.None,
        preserveWhitespaces: false,
        styles: [".bb-table{width:100%;display:block;box-shadow:0 6px 6px -6px rgba(0,0,0,.1)}.bb-table.plain{box-shadow:none}.bb-table.plain>.bb-table-wrapper{border-top-left-radius:0;border-top-right-radius:0}.bb-table-wrapper{overflow-x:auto;position:relative;background-color:#fff;border-top-left-radius:4px;border-top-right-radius:4px}.bb-table-container{width:100%}.bb-table-container td{border-bottom:1px solid #d8d8d8}.bb-table-top-actions{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;padding:20px 20px 10px;background-color:#fff;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom:1px solid #d8d8d8}.bb-table-top-actions>*{margin-left:0;margin-bottom:10px}.bb-table-top-actions+.bb-table-wrapper{border-radius:0}.bb-table-bottom-actions{height:60px;display:-webkit-box;display:-ms-flexbox;display:flex;padding:0 20px;overflow-x:auto;-webkit-box-align:center;-ms-flex-align:center;align-items:center;background-color:#fff;border-bottom-left-radius:4px;border-bottom-right-radius:4px}.bb-table-template{border:none;background-color:#f5f5f5;border-bottom:1px solid #d8d8d8}.bb-table-template-content{padding:20px;display:-webkit-box;display:-ms-flexbox;display:flex;color:#3d464d;font-size:14px;line-height:1.2;font-weight:400;min-height:140px;text-align:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.bb-table-template-content>svg{margin-bottom:12px}.bb-table-template-content-code{opacity:.5;margin-top:5px;display:inline-block}.bb-table-progress{top:0;left:0;right:0;opacity:0;width:100%;height:4px;display:block;overflow:hidden;position:absolute;background-color:rgba(47,64,139,.3);-webkit-animation:250ms cubic-bezier(0,0,.2,1) .1s forwards fadeIn;animation:250ms cubic-bezier(0,0,.2,1) .1s forwards fadeIn}.bb-table-progress .bb-table-indeterminate{background-color:#2f408b}.bb-table-progress .bb-table-indeterminate:before{top:0;left:0;bottom:0;content:\"\";position:absolute;will-change:left,right;background-color:inherit;-webkit-animation:2.1s cubic-bezier(.65,.815,.735,.395) infinite indeterminate;animation:2.1s cubic-bezier(.65,.815,.735,.395) infinite indeterminate}.bb-table-progress .bb-table-indeterminate:after{top:0;left:0;bottom:0;content:\"\";position:absolute;-webkit-animation-delay:1.15s;animation-delay:1.15s;will-change:left,right;background-color:inherit;-webkit-animation:2.1s cubic-bezier(.165,.84,.44,1) infinite indeterminate-short;animation:2.1s cubic-bezier(.165,.84,.44,1) infinite indeterminate-short}.bb-table-progress-close-query{padding:0;border:none;border-radius:4px;background-color:transparent;-webkit-transition:background-color 250ms cubic-bezier(0,0,.2,1);transition:background-color 250ms cubic-bezier(0,0,.2,1)}.bb-table-progress-close-query:hover{background-color:rgba(0,0,0,.08)}.bb-table-progress-close-query:focus{background-color:rgba(0,0,0,.12)}.bb-table-progress-close-query:active{background-color:rgba(0,0,0,.16)}@-webkit-keyframes fadeIn{from{opacity:0}to{opacity:1}}@keyframes fadeIn{from{opacity:0}to{opacity:1}}@-webkit-keyframes indeterminate{0%{left:-35%;right:100%}100%,60%{left:100%;right:-90%}}@keyframes indeterminate{0%{left:-35%;right:100%}100%,60%{left:100%;right:-90%}}@-webkit-keyframes indeterminate-short{0%{left:-200%;right:100%}100%,60%{left:107%;right:-8%}}@keyframes indeterminate-short{0%{left:-200%;right:100%}100%,60%{left:107%;right:-8%}}@media only screen and (min-width:768px){.bb-table-top-actions{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.bb-table-top-actions>:not(:first-child){margin-left:10px;margin-bottom:10px}}"]
    })
], BbTable);

let BbTableCell = class BbTableCell {
};
BbTableCell = __decorate([
    Component({
        selector: 'bb-table-cell',
        template: "<div>\n    <ng-content></ng-content>\n</div>",
        changeDetection: ChangeDetectionStrategy.OnPush,
        host: { 'class': 'bb-table-cell' },
        encapsulation: ViewEncapsulation.None,
        preserveWhitespaces: false,
        styles: [".bb-table-cell{color:#848f99;font-size:14px;text-align:left;line-height:1.2;font-weight:400;padding:12px 20px;display:table-cell;word-wrap:break-word;vertical-align:middle;background-color:#f5f5f5;border-bottom:1px solid #d8d8d8}.bb-table-cell:not(:last-child){border-right:1px solid #d8d8d8}.bb-table-cell.fit{width:1%;white-space:nowrap}.bb-table-cell.left{text-align:left}.bb-table-cell.center{text-align:center}.bb-table-cell.right{text-align:right}"]
    })
], BbTableCell);

class BbTableHeaderCellBase {
}
const BbTableHeaderCellMixinBase = mixinDisabled(BbTableHeaderCellBase);
let BbTableHeaderCell = class BbTableHeaderCell extends BbTableHeaderCellMixinBase {
    constructor(_table, _name) {
        super();
        this._table = _table;
        this._name = _name;
        // Constants.
        this._sortDirections = ['none', 'asc', 'desc'];
        this._control = new FormControl(this._sortDirections[0]);
        this.logWarning = (message) => {
            console && console.warn && console.warn(message);
        };
    }
    // Sort.
    set sort(value) {
        // Check if the new value is a valid value.
        if (!this._sortDirections.includes(value)) {
            return;
        }
        // Set the value.
        this._control.setValue(value);
    }
    get sort() {
        return this._control.value;
    }
    ngOnInit() {
        // Validate that the name and table are set.
        if (!this._table || !this._name) {
            return;
        }
        // Check if the control already exists in the table.
        if (this._table.sortControl.contains(this._name)) {
            this.disabled = true;
            return this.logWarning(`BbTableHeaderCell: The name "${this._name}" is not unique in the table; Control was not registered.`);
        }
        // Register the header cell with the table.
        this._table.sortControl.addControl(this._name, this._control);
        // Get all the value changes.
        this.valueChanges$ = this._control.valueChanges.pipe(startWith(this._control.value));
    }
    ngOnDestroy() {
        // Validate that the name and table are set.
        if (!this._table || !this._name) {
            return;
        }
        // Un-register the header cell with the table.
        if (this._table.sortControl.contains(this._name)) {
            this._table.sortControl.removeControl(this._name);
        }
    }
    get isDisabled() {
        return this.disabled || !this._name;
    }
    onClick() {
        // Check if the header cell is disabled.
        if (this.isDisabled) {
            return;
        }
        // Find the index of the current sort and
        // create the new index.
        const index = this._sortDirections.findIndex(item => item === this._control.value);
        const newIndex = (index + 1) % this._sortDirections.length;
        const newSort = this._sortDirections[newIndex];
        // Set the new sort.
        return this.updateTableAndHeaderCell(newSort);
    }
    updateTableAndHeaderCell(value) {
        // Check if the new value is a valid value.
        if (!this._sortDirections.includes(value)) {
            return;
        }
        // Validate the table exists.
        if (!this._table) {
            return this._control.setValue(value);
        }
        // Handle the single sorting strategy.
        if (this._table.sortingStrategy === 'single') {
            return this.handleSingleSortingStrategy(value);
        }
        // Default case when no other strategy
        // is used.
        return this._control.setValue(value);
    }
    handleSingleSortingStrategy(value) {
        // Get the sort control.
        const control = this._table.sortControl;
        // Set each value to false since we only want to
        // sort on one property at a time with this strategy.
        const newValue = Object.keys(control.controls).reduce((previous, current) => {
            previous[current] = current === this._name ? value : 'none';
            return previous;
        }, {});
        // Patch the entire sort value.
        this._table.sortControl.patchValue(newValue);
    }
};
BbTableHeaderCell.ctorParameters = () => [
    { type: BbTable, decorators: [{ type: Optional }, { type: Host }] },
    { type: String, decorators: [{ type: Optional }, { type: Attribute, args: ['name',] }] }
];
__decorate([
    Input()
], BbTableHeaderCell.prototype, "sort", null);
__decorate([
    HostListener('click')
], BbTableHeaderCell.prototype, "onClick", null);
BbTableHeaderCell = __decorate([
    Component({
        selector: 'bb-table-header-cell',
        template: "<!-- The content. -->\n<ng-content></ng-content>\n\n<!-- The indicator for the sort direction. -->\n<ng-container *ngIf=\"valueChanges$ | async as value\">\n    <button *ngIf=\"!isDisabled\"\n            [class.asc]=\"value === 'asc'\"\n            [class.desc]=\"value === 'desc'\"\n            class=\"bb-table-header-cell-toggle\"\n            type=\"button\"></button>\n</ng-container>\n",
        changeDetection: ChangeDetectionStrategy.OnPush,
        host: {
            'class': 'bb-table-header-cell',
            '[class.disabled]': 'isDisabled'
        },
        inputs: ['disabled'],
        encapsulation: ViewEncapsulation.None,
        preserveWhitespaces: false,
        styles: [".bb-table-header-cell{height:50px;color:#212529;cursor:pointer;font-size:16px;font-weight:500;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;padding:10px 20px;position:relative;display:table-cell;vertical-align:middle;border-bottom:1px solid #d8d8d8}.bb-table-header-cell:active>.bb-table-header-cell-toggle{background-color:rgba(0,0,0,.08)}.bb-table-header-cell:not(.disabled){padding-right:52px}.bb-table-header-cell.fit{width:1%;white-space:nowrap}.bb-table-header-cell.left{text-align:left}.bb-table-header-cell.center{text-align:center}.bb-table-header-cell.right{text-align:right}.bb-table-header-cell.disabled{cursor:default;pointer-events:none}.bb-table-header-cell-toggle{top:50%;right:14px;width:22px;border:none;height:22px;margin-left:auto;position:absolute;border-radius:4px;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%);background-position:center;background-repeat:no-repeat;background-color:transparent;-webkit-transition:background-color .2s cubic-bezier(0,0,.2,1);transition:background-color .2s cubic-bezier(0,0,.2,1);background-image:url('data:image/svg+xml,%3Csvg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 9 15\" width=\"9\" height=\"15\"%3E%3Cpath fill=\"%23dcdcdc\" d=\"M4.5 0L0 7h9z\"%3E%3C/path%3E%3Cpath fill=\"%23dcdcdc\" d=\"M4.5 15L9 8H0z\"%3E%3C/path%3E%3C/svg%3E')}.bb-table-header-cell-toggle.desc{background-image:url('data:image/svg+xml,%3Csvg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 9 15\" width=\"9\" height=\"15\"%3E%3Cpath fill=\"%23dcdcdc\" d=\"M4.5 0L0 7h9z\"%3E%3C/path%3E%3Cpath fill=\"black\" d=\"M4.5 15L9 8H0z\"%3E%3C/path%3E%3C/svg%3E')}.bb-table-header-cell-toggle.asc{background-image:url('data:image/svg+xml,%3Csvg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 9 15\" width=\"9\" height=\"15\"%3E%3Cpath fill=\"black\" d=\"M4.5 0L0 7h9z\"%3E%3C/path%3E%3Cpath fill=\"%23dcdcdc\" d=\"M4.5 15L9 8H0z\"%3E%3C/path%3E%3C/svg%3E')}"]
    }),
    __param(0, Optional()), __param(0, Host()),
    __param(1, Optional()), __param(1, Attribute('name'))
], BbTableHeaderCell);

var BbTablePager_1;
class BbTablePagerBase {
}
const BbTablePagerMixinBase = mixinDisabled(BbTablePagerBase);
let BbTablePager = BbTablePager_1 = class BbTablePager extends BbTablePagerMixinBase {
    constructor() {
        super(...arguments);
        // Inputs.
        this.amountOfButtons = 5;
        this.showArrowButtons = true;
        // Methods.
        this.onChange = () => ({});
        this.onTouched = () => ({});
        this.trackByIndex = (index, item) => item.page;
        // Data.
        this._totalPages$ = new BehaviorSubject(1);
        this._pageNumber$ = new BehaviorSubject(1);
    }
    ngOnInit() {
        // Validate the previous button is disabled.
        this.isPreviousDisabled$ = this._pageNumber$.pipe(map(pageNumber => pageNumber === 1));
        // Validate the next button is disabled.
        this.isNextDisabled$ = combineLatest([this._pageNumber$, this._totalPages$]).pipe(map(([pageNumber, totalPages]) => pageNumber === totalPages));
        // Create the list with page numbers.
        this.list$ = combineLatest([this._pageNumber$, this._totalPages$]).pipe(map(([pageNumber, totalPages]) => this.filterActivePages(pageNumber, totalPages)), share());
    }
    get pageNumber() {
        return this._pageNumber$.getValue();
    }
    set pageNumber(newValue) {
        this.update(newValue);
    }
    get totalPages() {
        return this._totalPages$.getValue();
    }
    set totalPages(newValue) {
        const newTotalPages = Math.max(1, newValue);
        this._totalPages$.next(newTotalPages);
    }
    registerOnChange(fn) {
        this.onChange = fn;
    }
    registerOnTouched(fn) {
        this.onTouched = fn;
    }
    setDisabledState(isDisabled) {
        this.disabled = isDisabled;
    }
    writeValue(newValue) {
        this.update(newValue, false);
    }
    goToPrevious() {
        const newValue = this._pageNumber$.getValue() - 1;
        return this.update(newValue);
    }
    goToNext() {
        const newValue = this._pageNumber$.getValue() + 1;
        return this.update(newValue);
    }
    goToIndex(index) {
        return this.update(index);
    }
    update(pageNumber, notify = true) {
        // You can only update when not disabled.
        if (this.disabled) {
            return;
        }
        // Calculate the new value.
        const newValue = Math.min(this.totalPages, Math.max(1, pageNumber));
        // Don't do anything if the page number is the same.
        if (this._pageNumber$.getValue() === newValue) {
            return;
        }
        // Push the new value.
        this._pageNumber$.next(newValue);
        if (notify) {
            return this.onChange(pageNumber);
        }
    }
    calculatePages(pageNumber) {
        const min = 1;
        const max = this.totalPages;
        const amount = Math.max(1, this.amountOfButtons);
        const data = Array(amount)
            .fill(0)
            .map((_, index) => pageNumber + (index - 1));
        // Validate if the minimum value less than
        // the first value.
        if (data[0] < min) {
            return data.map(item => item + 1);
        }
        // Calculate the difference with the max
        // if this value is higher than 0 we should minus it.
        const lastValueInArray = data[data.length - 1];
        const differenceWithMax = lastValueInArray - max;
        if (differenceWithMax > 0) {
            return data.map(item => item - differenceWithMax);
        }
        // Just return the default data.
        return data;
    }
    filterActivePages(pageNumber, totalPages) {
        return this.calculatePages(pageNumber)
            .filter(page => page > 0 && page <= totalPages)
            .map(page => ({ page, active: pageNumber === page }));
    }
};
__decorate([
    Input()
], BbTablePager.prototype, "amountOfButtons", void 0);
__decorate([
    Input()
], BbTablePager.prototype, "showArrowButtons", void 0);
__decorate([
    Input()
], BbTablePager.prototype, "pageNumber", null);
__decorate([
    Input()
], BbTablePager.prototype, "totalPages", null);
BbTablePager = BbTablePager_1 = __decorate([
    Component({
        selector: 'bb-table-pager',
        template: "<ul class=\"bb-pager-list\">\n    <!-- The previous page arrow button. -->\n    <li *ngIf=\"showArrowButtons\"\n        class=\"bb-pager-list-item\"\n        title=\"Previous page\">\n        <button [disabled]=\"isPreviousDisabled$ | async\"\n                (click)=\"goToPrevious()\"\n                class=\"bb-pager-list-button\"\n                type=\"button\">\n            <bb-icon src=\"material:keyboard_arrow_left\"></bb-icon>\n        </button>\n    </li>\n\n    <!-- The list of number buttons to navigate through the list. -->\n    <ng-container *ngIf=\"list$ | async as list\">\n        <li *ngFor=\"let item of list; trackBy: trackByIndex\"\n            [title]=\"'Page ' + item?.page\"\n            class=\"bb-pager-list-item\">\n            <button (click)=\"goToIndex(item?.page)\"\n                    [class.active]=\"item?.active\"\n                    class=\"bb-pager-list-button\"\n                    type=\"button\">\n                {{ item?.page }}\n            </button>\n        </li>\n    </ng-container>\n\n    <!-- The next page arrow button. -->\n    <li *ngIf=\"showArrowButtons\"\n        class=\"bb-pager-list-item\"\n        title=\"Next page\">\n        <button [disabled]=\"isNextDisabled$ | async\"\n                (click)=\"goToNext()\"\n                class=\"bb-pager-list-button\"\n                type=\"button\">\n            <bb-icon src=\"material:keyboard_arrow_right\"></bb-icon>\n        </button>\n    </li>\n</ul>\n",
        changeDetection: ChangeDetectionStrategy.OnPush,
        host: {
            'class': 'bb-table-pager',
            '[class.disabled]': 'disabled'
        },
        inputs: ['disabled'],
        encapsulation: ViewEncapsulation.None,
        preserveWhitespaces: false,
        providers: [
            { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => BbTablePager_1), multi: true }
        ],
        styles: [".bb-table-pager{-webkit-box-flex:1;-ms-flex:1;flex:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.bb-table-pager.disabled{opacity:.5;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;pointer-events:none}.bb-pager-list{display:-webkit-box;display:-ms-flexbox;display:flex}.bb-pager-list-item{margin-left:8px}.bb-pager-list-button{padding:0;color:#3d464d;line-height:1;min-width:32px;font-size:16px;-webkit-appearance:none;-moz-appearance:none;appearance:none;font-weight:500;min-height:32px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border-radius:4px;-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;border:1px solid #b6bbc1;-webkit-transition-duration:.2s;transition-duration:.2s;background-color:transparent;-webkit-transition-timing-function:cubic-bezier(0,0,.2,1);transition-timing-function:cubic-bezier(0,0,.2,1);-webkit-transition-property:color,border-color,opacity,background-color;transition-property:color,border-color,opacity,background-color;box-shadow:inset 0 3px 0 0 rgba(183,188,194,.2),0 6px 6px -6px rgba(0,0,0,.1)}.bb-pager-list-button:focus,.bb-pager-list-button:hover{background-color:rgba(0,0,0,.04)}.bb-pager-list-button.active,.bb-pager-list-button.active:hover{color:#2196f3;cursor:default;border-color:#2196f3;background-color:transparent}.bb-pager-list-button:disabled{opacity:.35;cursor:default;pointer-events:none}"]
    })
], BbTablePager);

const DECLARATIONS_EXPORTS = [
    BbTable,
    BbTableColumnDef,
    BbTableHeaderCell,
    BbTableCell
];
let TableModule = class TableModule {
};
TableModule = __decorate([
    NgModule({
        imports: [CommonModule, FormsModule, ReactiveFormsModule, ElementsModule, LocalizeModule],
        declarations: [BbTablePager, ...DECLARATIONS_EXPORTS],
        exports: [...DECLARATIONS_EXPORTS]
    })
], TableModule);

/**
 * Generated bundle index. Do not edit.
 */

export { BbTable, BbTableCell, BbTableColumnDef, BbTableHeaderCell, TableModule, BbTablePager as ɵa };
//# sourceMappingURL=bravobit-bb-foundation-table.js.map
