import * as tslib_1 from "tslib";
import './utils';
import WidgetBase from '@dojo/framework/core/WidgetBase';
import diffProperty from '@dojo/framework/core/decorators/diffProperty';
import { reference } from '@dojo/framework/core/diff';
import Dimensions from '@dojo/framework/core/meta/Dimensions';
import Resize from '@dojo/framework/core/meta/Resize';
import I18nMixin from '@dojo/framework/core/mixins/I18n';
import ThemedMixin, { theme } from '@dojo/framework/core/mixins/Themed';
import { v, w } from '@dojo/framework/core/vdom';
import { Store } from '@dojo/framework/stores/Store';
import * as css from '../theme/default/grid.m.css';
import Body from './Body';
import Footer from './Footer';
import Header from './Header';
import PaginatedBody from './PaginatedBody';
import PaginatedFooter from './PaginatedFooter';
import { clearSelectionProcess, fetcherProcess, filterProcess, pageChangeProcess, selectionProcess, sortProcess, updaterProcess } from './processes';
import * as fixedCss from './styles/grid.m.css';
const defaultGridMeta = {
    page: 1,
    total: undefined,
    sort: undefined,
    filter: undefined,
    isSorting: false,
    editedRow: undefined,
    selection: []
};
const MIN_COLUMN_WIDTH = 100;
let Grid = class Grid extends I18nMixin(ThemedMixin(WidgetBase)) {
    constructor() {
        super();
        this._store = new Store();
        this._scrollLeft = 0;
        this._pageSize = 100;
        this._gridWidth = 0;
        this._handle = this._store.onChange(this._store.path('_grid'), this.invalidate.bind(this));
    }
    onStoreProperty(previous, current) {
        const { storeId = '_grid' } = current;
        this._handle.remove();
        this._store = current.store;
        this._handle = this._store.onChange(this._store.path(storeId), () => {
            this.invalidate();
        });
    }
    _getProperties() {
        const { storeId = '_grid' } = this.properties;
        return Object.assign({}, this.properties, { storeId });
    }
    _getBodyDimensions() {
        const { height } = this.properties;
        const headerWrapper = this.meta(Dimensions).get('header-wrapper');
        const { size: { height: headerHeight, width: bodyWidth } } = this.meta(Dimensions).get('header');
        const { size: { height: footerHeight } } = this.meta(Dimensions).get('footer');
        return {
            headerWidth: headerWrapper.size.width,
            bodyHeight: footerHeight && footerHeight ? height - headerHeight - footerHeight : 0,
            bodyWidth
        };
    }
    _onColumnResize(index, value) {
        const { columnConfig } = this.properties;
        if (!this._columnWidths) {
            return;
        }
        const currentColumnWidth = this._columnWidths[columnConfig[index].id];
        if (currentColumnWidth <= MIN_COLUMN_WIDTH && value < 0) {
            return;
        }
        if (currentColumnWidth + value <= MIN_COLUMN_WIDTH) {
            value = value - (currentColumnWidth + value - MIN_COLUMN_WIDTH);
        }
        this._columnWidths = Object.assign({}, this._columnWidths, { [columnConfig[index].id]: currentColumnWidth + value });
        this.invalidate();
    }
    _fetcher(page, pageSize) {
        const { storeId, fetcher } = this._getProperties();
        fetcherProcess(this._store)({ id: storeId, fetcher, page, pageSize });
    }
    _sorter(columnId, direction) {
        const { storeId, fetcher, onRowSelect } = this._getProperties();
        if (onRowSelect) {
            const selectedIndexes = this._store.get(this._store.path(storeId, 'meta', 'selection')) || [];
            selectedIndexes.length && onRowSelect([]);
        }
        sortProcess(this._store)({ id: storeId, fetcher, columnId, direction });
    }
    _filterer(columnId, value) {
        const { storeId, fetcher, onRowSelect } = this._getProperties();
        if (onRowSelect) {
            const selectedIndexes = this._store.get(this._store.path(storeId, 'meta', 'selection')) || [];
            selectedIndexes.length && onRowSelect([]);
        }
        filterProcess(this._store)({ id: storeId, fetcher, filterOptions: { columnId, value } });
    }
    _updater(page, rowNumber, columnId, value) {
        const { storeId, updater } = this._getProperties();
        updaterProcess(this._store)({ id: storeId, page, columnId, rowNumber, value, updater });
    }
    _pageChange(page) {
        const { pagination, storeId } = this._getProperties();
        if (pagination) {
            clearSelectionProcess(this._store)({ id: storeId });
        }
        pageChangeProcess(this._store)({ id: storeId, page });
    }
    _selection(index, type) {
        const { storeId, onRowSelect } = this._getProperties();
        selectionProcess(this._store)({ id: storeId, index, type });
        const selectedIndexes = this._store.get(this._store.path(storeId, 'meta', 'selection')) || [];
        const items = [];
        const data = this._store.get(this._store.path(storeId, 'data', 'pages'));
        const pageNumber = this._store.get(this._store.path(storeId, 'meta', 'page'));
        for (let i = 0; i < selectedIndexes.length; i++) {
            const selectedIndex = selectedIndexes[i];
            const offset = Math.floor(selectedIndex / this._pageSize) + 1;
            const itemIndex = selectedIndex - (offset - 1) * this._pageSize;
            if (data[`page-${pageNumber}`]) {
                items.push(data[`page-${pageNumber}`][itemIndex]);
            }
        }
        onRowSelect && onRowSelect(items);
    }
    _onScroll(value) {
        this._scrollLeft = value;
        this.invalidate();
    }
    render() {
        const { i18nBundle, columnConfig, storeId, theme, classes, pagination = false, customRenderers = {}, onRowSelect } = this._getProperties();
        const { sortRenderer, filterRenderer } = customRenderers;
        if (!columnConfig || !this.properties.fetcher) {
            return null;
        }
        const meta = this._store.get(this._store.path(storeId, 'meta')) || defaultGridMeta;
        const pages = this._store.get(this._store.path(storeId, 'data', 'pages')) || {};
        const hasFilters = columnConfig.some((config) => !!config.filterable);
        const hasResizableColumns = columnConfig.some((config) => !!config.resizable);
        const { bodyHeight, bodyWidth, headerWidth } = this._getBodyDimensions();
        this.meta(Resize).get('root');
        if (bodyWidth && headerWidth && hasResizableColumns && !this._columnWidths) {
            const width = headerWidth / columnConfig.length;
            this._columnWidths = columnConfig.reduce((sizes, { id }) => {
                sizes[id] = Math.max(MIN_COLUMN_WIDTH, width);
                return sizes;
            }, {});
            this._gridWidth = Math.max(bodyWidth, MIN_COLUMN_WIDTH * columnConfig.length);
        }
        return v('div', {
            key: 'root',
            classes: [this.variant(), this.theme(css.root), fixedCss.rootFixed],
            role: 'table',
            'aria-rowcount': meta.total ? `${meta.total}` : undefined
        }, [
            v('div', {
                key: 'header',
                scrollLeft: this._scrollLeft,
                styles: hasResizableColumns && this._gridWidth
                    ? {
                        width: `${this._gridWidth}px`
                    }
                    : {},
                classes: [
                    this.theme(css.header),
                    fixedCss.headerFixed,
                    hasFilters ? this.theme(css.filterGroup) : null
                ],
                row: 'rowgroup'
            }, [
                v('div', { key: 'header-wrapper' }, [
                    w(Header, {
                        key: 'header-row',
                        i18nBundle,
                        theme,
                        columnWidths: this._columnWidths,
                        classes,
                        columnConfig,
                        sorter: this._sorter,
                        sort: meta.sort,
                        filter: meta.filter,
                        filterer: this._filterer,
                        sortRenderer,
                        filterRenderer,
                        onColumnResize: this._onColumnResize
                    })
                ])
            ]),
            bodyHeight
                ? pagination
                    ? w(PaginatedBody, {
                        key: 'paginated-body',
                        i18nBundle,
                        theme,
                        classes,
                        pages,
                        columnWidths: this._columnWidths,
                        pageNumber: meta.page,
                        pageSize: this._pageSize,
                        onScroll: this._onScroll,
                        columnConfig,
                        fetcher: this._fetcher,
                        updater: this._updater,
                        height: bodyHeight,
                        width: hasResizableColumns ? this._gridWidth : undefined,
                        onRowSelect: onRowSelect ? this._selection : undefined,
                        selectedRows: meta.selection
                    })
                    : w(Body, {
                        key: 'body',
                        i18nBundle,
                        theme,
                        classes,
                        pages,
                        columnWidths: this._columnWidths,
                        totalRows: meta.total,
                        pageSize: this._pageSize,
                        columnConfig,
                        fetcher: this._fetcher,
                        pageChange: this._pageChange,
                        updater: this._updater,
                        onScroll: this._onScroll,
                        height: bodyHeight,
                        width: hasResizableColumns ? this._gridWidth : undefined,
                        onRowSelect: onRowSelect ? this._selection : undefined,
                        selectedRows: meta.selection
                    })
                : null,
            v('div', { key: 'footer' }, [
                pagination
                    ? w(PaginatedFooter, {
                        i18nBundle,
                        theme,
                        classes,
                        total: meta.total,
                        page: meta.page,
                        pageSize: this._pageSize,
                        onPageChange: (page) => {
                            this._pageChange(page);
                        }
                    })
                    : w(Footer, {
                        key: 'footer-row',
                        i18nBundle,
                        theme,
                        classes,
                        total: meta.total,
                        page: meta.page,
                        pageSize: this._pageSize
                    })
            ])
        ]);
    }
};
tslib_1.__decorate([
    diffProperty('store', reference),
    tslib_1.__metadata("design:type", Function),
    tslib_1.__metadata("design:paramtypes", [Object, Object]),
    tslib_1.__metadata("design:returntype", void 0)
], Grid.prototype, "onStoreProperty", null);
Grid = tslib_1.__decorate([
    theme(css),
    tslib_1.__metadata("design:paramtypes", [])
], Grid);
export default Grid;

/*# sourceMappingURL=index.mjs.map*/