/*!
 * Built by Revolist OU ❤️
 */
import { h, } from "@stencil/core";
import { getItemByIndex } from "../../store/index";
import { HEADER_ACTUAL_ROW_CLASS, HEADER_ROW_CLASS } from "../../utils/consts";
import HeaderRenderer from "./header-renderer";
import GroupHeaderRenderer from "./header-group-renderer";
export class RevogrHeaderComponent {
    constructor() {
        /**
         * Grouping depth, how many levels of grouping
         */
        this.groupingDepth = 0;
        /**
         * Extra properties to pass into header renderer, such as vue or react components to handle parent
         */
        this.additionalData = {};
    }
    onResize({ width }, index) {
        const col = this.colData[index];
        const event = this.beforeResize.emit([
            Object.assign(Object.assign({}, col), { size: width || undefined }),
        ]);
        if (event.defaultPrevented) {
            return;
        }
        this.headerresize.emit({ [index]: width || 0 });
    }
    onResizeGroup(changedX, startIndex, endIndex) {
        const sizes = {};
        const change = changedX / (endIndex - startIndex + 1);
        for (let i = startIndex; i <= endIndex; i++) {
            const item = getItemByIndex(this.dimensionCol.state, i);
            sizes[i] = item.end - item.start + change;
        }
        this.headerresize.emit(sizes);
    }
    componentDidRender() {
        this.afterHeaderRender.emit(this.providers);
    }
    render() {
        var _a;
        const cols = this.viewportCol.get('items');
        const range = (_a = this.selectionStore) === null || _a === void 0 ? void 0 : _a.get('range');
        const { cells } = this.renderHeaderColumns(cols, range);
        const groupRow = this.renderGroupingColumns();
        return [
            h("div", { key: '3cc466db6bc4df0cd61c47a22c3a0473318e5dd8', class: "group-rgRow" }, groupRow),
            h("div", { key: '9742a3fa4d4b75073aef5544806f42386ebffdea', class: `${HEADER_ROW_CLASS} ${HEADER_ACTUAL_ROW_CLASS}` }, cells),
        ];
    }
    renderHeaderColumns(cols, range) {
        const columnsToRender = [];
        const renderOffset = this.viewportCol.get('renderOffset') || 0;
        for (let rgCol of cols) {
            const colData = this.colData[rgCol.itemIndex];
            const props = {
                range,
                column: rgCol,
                data: Object.assign(Object.assign({}, colData), { index: rgCol.itemIndex, providers: this.providers }),
                canFilter: !!this.columnFilter,
                canResize: this.canResize,
                renderOffset,
                active: this.resizeHandler,
                additionalData: this.additionalData,
                onResize: e => this.onResize(e, rgCol.itemIndex),
                onDblClick: e => this.headerdblClick.emit(e),
                onClick: e => this.initialHeaderClick.emit(e),
            };
            const event = this.beforeHeaderRender.emit(props);
            if (!event.defaultPrevented) {
                columnsToRender.push(event.detail);
            }
        }
        const duplicateProps = this.getDuplicateHeaderProps(columnsToRender);
        const cells = columnsToRender.map(detail => h(HeaderRenderer, Object.assign({ key: this.getHeaderCellKey(detail.data, this.type, duplicateProps) }, detail)));
        return { cells };
    }
    renderGroupingColumns() {
        const visibleGroupRange = this.getVisibleGroupRange();
        return Array.from({ length: this.groupingDepth }, (_, level) => this.renderGroupRow(level, visibleGroupRange)).flat();
    }
    renderGroupRow(level, visibleGroupRange) {
        const groupCells = (this.groups[level] || [])
            .map(group => this.renderGroupColumn(group, level, visibleGroupRange))
            .filter((cell) => !!cell);
        return [
            ...groupCells,
            h('div', {
                key: `group-row-${level}`,
                class: {
                    [HEADER_ROW_CLASS]: true,
                    group: true,
                },
            }),
        ];
    }
    renderGroupColumn(group, level, visibleGroupRange) {
        const groupRange = this.getGroupIndexRange(group);
        const groupBounds = this.getGroupBounds(groupRange);
        const props = {
            level,
            providers: this.providers,
            start: groupBounds.start,
            end: groupBounds.end,
            group,
            renderOffset: this.viewportCol.get('renderOffset') || 0,
            active: this.resizeHandler,
            canResize: this.canResize,
            additionalData: this.additionalData,
            onResize: e => {
                var _a;
                return groupRange
                    ? this.onResizeGroup((_a = e.changedX) !== null && _a !== void 0 ? _a : 0, groupRange.startIndex, groupRange.endIndex)
                    : undefined;
            },
        };
        const event = this.beforeGroupHeaderRender.emit(props);
        if (event.defaultPrevented) {
            return;
        }
        const renderRange = this.getGroupIndexRange(event.detail.group);
        if (!renderRange ||
            !visibleGroupRange ||
            !isGroupInVisibleRange(renderRange.startIndex, renderRange.endIndex, visibleGroupRange)) {
            return;
        }
        if (event.detail.onResize === props.onResize) {
            event.detail.onResize = e => {
                var _a;
                return this.onResizeGroup((_a = e.changedX) !== null && _a !== void 0 ? _a : 0, renderRange.startIndex, renderRange.endIndex);
            };
        }
        const renderBounds = this.getGroupBounds(renderRange);
        if (event.detail.start === props.start) {
            event.detail.start = renderBounds.start;
        }
        if (event.detail.end === props.end) {
            event.detail.end = renderBounds.end;
        }
        return h(GroupHeaderRenderer, Object.assign({ key: this.getGroupHeaderCellKey(event.detail.group, level) }, event.detail));
    }
    getGroupIndexRange(group) {
        var _a;
        const startIndex = (_a = group.indexes[0]) !== null && _a !== void 0 ? _a : -1;
        if (startIndex < 0) {
            return;
        }
        const endIndex = group.indexes[group.indexes.length - 1];
        return {
            startIndex,
            endIndex,
        };
    }
    getGroupBounds(range) {
        if (!range) {
            return { start: 0, end: 0 };
        }
        return {
            start: getItemByIndex(this.dimensionCol.state, range.startIndex).start,
            end: getItemByIndex(this.dimensionCol.state, range.endIndex).end,
        };
    }
    getVisibleGroupRange() {
        const visibleColumns = this.viewportCol.get('items');
        if (!visibleColumns.length) {
            return;
        }
        return visibleColumns.reduce((range, column) => ({
            start: Math.min(range.start, column.itemIndex),
            end: Math.max(range.end, column.itemIndex),
        }), {
            start: visibleColumns[0].itemIndex,
            end: visibleColumns[0].itemIndex,
        });
    }
    getHeaderCellKey(column, type, duplicateProps) {
        if ((column === null || column === void 0 ? void 0 : column.prop) === undefined) {
            return `${type}-${String(column === null || column === void 0 ? void 0 : column.index)}`;
        }
        const propKey = String(column.prop);
        if (duplicateProps.has(propKey)) {
            return `${type}-${propKey}-${String(column.index)}`;
        }
        return `${type}-${propKey}`;
    }
    getDuplicateHeaderProps(columns) {
        const seenProps = new Set();
        const duplicateProps = new Set();
        columns.forEach(({ data }) => {
            if ((data === null || data === void 0 ? void 0 : data.prop) !== undefined) {
                const propKey = String(data.prop);
                if (seenProps.has(propKey)) {
                    duplicateProps.add(propKey);
                }
                else {
                    seenProps.add(propKey);
                }
            }
        });
        return duplicateProps;
    }
    getGroupHeaderCellKey(group, level) {
        return `group-${level}-${group.name}-${group.indexes.join('-')}`;
    }
    get providers() {
        return {
            type: this.type,
            readonly: this.readonly,
            data: this.colData,
            viewport: this.viewportCol,
            dimension: this.dimensionCol,
            selection: this.selectionStore,
        };
    }
    static get is() { return "revogr-header"; }
    static get originalStyleUrls() {
        return {
            "$": ["revogr-header-style.scss"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["revogr-header-style.css"]
        };
    }
    static get properties() {
        return {
            "viewportCol": {
                "type": "unknown",
                "mutable": false,
                "complexType": {
                    "original": "Observable<ViewportState>",
                    "resolved": "ViewportState",
                    "references": {
                        "Observable": {
                            "location": "import",
                            "path": "../../utils",
                            "id": "src/utils/index.ts::Observable",
                            "referenceLocation": "Observable"
                        },
                        "ViewportState": {
                            "location": "import",
                            "path": "@type",
                            "id": "src/types/index.ts::ViewportState",
                            "referenceLocation": "ViewportState"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Viewport X"
                },
                "getter": false,
                "setter": false
            },
            "dimensionCol": {
                "type": "unknown",
                "mutable": false,
                "complexType": {
                    "original": "Observable<DimensionSettingsState>",
                    "resolved": "DimensionSettingsState",
                    "references": {
                        "Observable": {
                            "location": "import",
                            "path": "../../utils",
                            "id": "src/utils/index.ts::Observable",
                            "referenceLocation": "Observable"
                        },
                        "DimensionSettingsState": {
                            "location": "import",
                            "path": "@type",
                            "id": "src/types/index.ts::DimensionSettingsState",
                            "referenceLocation": "DimensionSettingsState"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Dimension settings X"
                },
                "getter": false,
                "setter": false
            },
            "selectionStore": {
                "type": "unknown",
                "mutable": false,
                "complexType": {
                    "original": "Observable<SelectionStoreState>",
                    "resolved": "{ range: RangeArea | null; tempRange: RangeArea | null; tempRangeType: string | null; focus: Cell | null; edit: EditCellStore | null; lastCell: Cell | null; nextFocus: Cell | null; }",
                    "references": {
                        "Observable": {
                            "location": "import",
                            "path": "../../utils",
                            "id": "src/utils/index.ts::Observable",
                            "referenceLocation": "Observable"
                        },
                        "SelectionStoreState": {
                            "location": "import",
                            "path": "@type",
                            "id": "src/types/index.ts::SelectionStoreState",
                            "referenceLocation": "SelectionStoreState"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Selection, range, focus"
                },
                "getter": false,
                "setter": false
            },
            "groups": {
                "type": "unknown",
                "mutable": false,
                "complexType": {
                    "original": "Groups",
                    "resolved": "{ [x: number]: Group[]; }",
                    "references": {
                        "Groups": {
                            "location": "import",
                            "path": "@store",
                            "id": "src/store/index.ts::Groups",
                            "referenceLocation": "Groups"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Column groups"
                },
                "getter": false,
                "setter": false
            },
            "groupingDepth": {
                "type": "number",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Grouping depth, how many levels of grouping"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "grouping-depth",
                "defaultValue": "0"
            },
            "readonly": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Readonly mode"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "readonly"
            },
            "canResize": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "If columns can be resized"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "can-resize"
            },
            "resizeHandler": {
                "type": "unknown",
                "mutable": false,
                "complexType": {
                    "original": "ResizeProps['active']",
                    "resolved": "(\"r\" | \"b\" | \"rt\" | \"lt\" | \"rb\" | \"lb\" | \"l\" | \"t\")[]",
                    "references": {
                        "ResizeProps": {
                            "location": "import",
                            "path": "./resizable.directive",
                            "id": "src/components/header/resizable.directive.tsx::ResizeProps",
                            "referenceLocation": "ResizeProps"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Defines resize position"
                },
                "getter": false,
                "setter": false
            },
            "colData": {
                "type": "unknown",
                "mutable": false,
                "complexType": {
                    "original": "ColumnRegular[]",
                    "resolved": "ColumnRegular<ColumnProp, DataType<any, ColumnProp>>[]",
                    "references": {
                        "ColumnRegular": {
                            "location": "import",
                            "path": "@type",
                            "id": "src/types/index.ts::ColumnRegular",
                            "referenceLocation": "ColumnRegular"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Columns - defines an array of grid columns."
                },
                "getter": false,
                "setter": false
            },
            "columnFilter": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Column filter"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "column-filter"
            },
            "type": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "DimensionCols | 'rowHeaders'",
                    "resolved": "\"colPinEnd\" | \"colPinStart\" | \"rgCol\" | \"rowHeaders\"",
                    "references": {
                        "DimensionCols": {
                            "location": "import",
                            "path": "@type",
                            "id": "src/types/index.ts::DimensionCols",
                            "referenceLocation": "DimensionCols"
                        }
                    }
                },
                "required": true,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Column type"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "type"
            },
            "additionalData": {
                "type": "any",
                "mutable": false,
                "complexType": {
                    "original": "any",
                    "resolved": "any",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Extra properties to pass into header renderer, such as vue or react components to handle parent"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "additional-data",
                "defaultValue": "{}"
            }
        };
    }
    static get events() {
        return [{
                "method": "initialHeaderClick",
                "name": "beforeheaderclick",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "On initial header click"
                },
                "complexType": {
                    "original": "InitialHeaderClick",
                    "resolved": "{ index: number; originalEvent: MouseEvent; column: ColumnRegular<ColumnProp, DataType<any, ColumnProp>>; providers: ProvidersColumns<DimensionCols | \"rowHeaders\">; }",
                    "references": {
                        "InitialHeaderClick": {
                            "location": "import",
                            "path": "@type",
                            "id": "src/types/index.ts::InitialHeaderClick",
                            "referenceLocation": "InitialHeaderClick"
                        }
                    }
                }
            }, {
                "method": "headerresize",
                "name": "headerresize",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "On header resize"
                },
                "complexType": {
                    "original": "ViewSettingSizeProp",
                    "resolved": "{ [x: string]: number; }",
                    "references": {
                        "ViewSettingSizeProp": {
                            "location": "import",
                            "path": "@type",
                            "id": "src/types/index.ts::ViewSettingSizeProp",
                            "referenceLocation": "ViewSettingSizeProp"
                        }
                    }
                }
            }, {
                "method": "beforeResize",
                "name": "beforeheaderresize",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "On before header resize"
                },
                "complexType": {
                    "original": "ColumnRegular[]",
                    "resolved": "ColumnRegular<ColumnProp, DataType<any, ColumnProp>>[]",
                    "references": {
                        "ColumnRegular": {
                            "location": "import",
                            "path": "@type",
                            "id": "src/types/index.ts::ColumnRegular",
                            "referenceLocation": "ColumnRegular"
                        }
                    }
                }
            }, {
                "method": "headerdblClick",
                "name": "headerdblclick",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "On header double click"
                },
                "complexType": {
                    "original": "InitialHeaderClick",
                    "resolved": "{ index: number; originalEvent: MouseEvent; column: ColumnRegular<ColumnProp, DataType<any, ColumnProp>>; providers: ProvidersColumns<DimensionCols | \"rowHeaders\">; }",
                    "references": {
                        "InitialHeaderClick": {
                            "location": "import",
                            "path": "@type",
                            "id": "src/types/index.ts::InitialHeaderClick",
                            "referenceLocation": "InitialHeaderClick"
                        }
                    }
                }
            }, {
                "method": "beforeHeaderRender",
                "name": "beforeheaderrender",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Before each header cell render function. Allows to override cell properties"
                },
                "complexType": {
                    "original": "HeaderRenderProps",
                    "resolved": "{ column: VirtualPositionItem; additionalData: any; data: ColumnTemplateProp<ColumnProp>; range?: RangeArea | null | undefined; canResize?: boolean | undefined; canFilter?: boolean | undefined; renderOffset?: number | undefined; onResize?(e: ResizeEvent): void; onClick?(data: InitialHeaderClick): void; onDblClick?(data: InitialHeaderClick): void; } & Partial<Pick<ResizeProps, \"active\">>",
                    "references": {
                        "HeaderRenderProps": {
                            "location": "import",
                            "path": "./header-renderer",
                            "id": "src/components/header/header-renderer.tsx::HeaderRenderProps",
                            "referenceLocation": "HeaderRenderProps"
                        }
                    }
                }
            }, {
                "method": "beforeGroupHeaderRender",
                "name": "beforegroupheaderrender",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Before each group header cell render function. Allows to override group header cell properties"
                },
                "complexType": {
                    "original": "HeaderGroupRendererProps",
                    "resolved": "{ level: number; start: number; end: number; group: Group; providers: ProvidersColumns<DimensionCols | \"rowHeaders\">; additionalData: any; canResize?: boolean | undefined; renderOffset?: number | undefined; onResize?(e: ResizeEvent): void; } & Partial<Pick<ResizeProps, \"active\">>",
                    "references": {
                        "HeaderGroupRendererProps": {
                            "location": "import",
                            "path": "./header-group-renderer",
                            "id": "src/components/header/header-group-renderer.tsx::HeaderGroupRendererProps",
                            "referenceLocation": "HeaderGroupRendererProps"
                        }
                    }
                }
            }, {
                "method": "afterHeaderRender",
                "name": "afterheaderrender",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "After all header cells rendered. Finalizes cell rendering."
                },
                "complexType": {
                    "original": "ProvidersColumns",
                    "resolved": "ProvidersColumns<DimensionCols | \"rowHeaders\">",
                    "references": {
                        "ProvidersColumns": {
                            "location": "import",
                            "path": "@type",
                            "id": "src/types/index.ts::ProvidersColumns",
                            "referenceLocation": "ProvidersColumns"
                        }
                    }
                }
            }];
    }
    static get elementRef() { return "element"; }
}
function isGroupInVisibleRange(groupStartIndex, groupEndIndex, visibleRange) {
    return (groupStartIndex <= visibleRange.end &&
        groupEndIndex >= visibleRange.start);
}
