/*!
 * Built by Revolist OU ❤️
 */
import { Host, h, } from "@stencil/core";
import ColumnService from "./column.service";
import { DATA_COL, DATA_ROW, ROW_FOCUSED_CLASS } from "../../utils/consts";
import { getSourceItem } from "../../store/index";
import RowRenderer, { PADDING_DEPTH } from "./row-renderer";
import GroupingRowRenderer from "../../plugins/groupingRow/grouping.row.renderer";
import { isGrouping } from "../../plugins/groupingRow/grouping.service";
import { RowHighlightPlugin } from "./row-highlight.plugin";
import { convertVNodeToHTML } from "../vnode/vnode.utils";
import { CellRenderer } from "./cell-renderer";
/**
 * This component is responsible for rendering data
 * Rows, columns, groups and cells
 */
export class RevogrData {
    constructor() {
        /**
         * Prevent rendering until job is done.
         * Can be used for initial rendering performance improvement.
         * When several plugins require initial rendering this will prevent double initial rendering.
         */
        this.jobsBeforeRender = [];
        /**
         * Rendered rows - virtual index vs vnode
         */
        this.renderedRows = new Map();
    }
    /**
     * Pointed cell update.
     */
    async updateCell(e) {
        var _a, _b, _c;
        // Stencil tweak to update cell content
        const cell = (_b = (_a = this.renderedRows.get(e.row)) === null || _a === void 0 ? void 0 : _a.$children$) === null || _b === void 0 ? void 0 : _b[e.col];
        if ((_c = cell === null || cell === void 0 ? void 0 : cell.$attrs$) === null || _c === void 0 ? void 0 : _c.redraw) {
            const children = await convertVNodeToHTML(this.element, cell.$attrs$.redraw);
            cell.$elm$.innerHTML = children.html;
            cell.$key$ = Math.random();
        }
    }
    onDataStoreChange() {
        this.onStoreChange();
    }
    onColDataChange() {
        this.onStoreChange();
    }
    onStoreChange() {
        var _a, _b;
        (_a = this.columnService) === null || _a === void 0 ? void 0 : _a.destroy();
        this.columnService = new ColumnService(this.dataStore, this.colData);
        // make sure we have correct data, before render
        this.providers = {
            type: this.type,
            colType: this.colType,
            readonly: this.readonly,
            data: this.dataStore,
            columns: this.colData,
            viewport: this.viewportCol,
            dimension: this.dimensionRow,
            selection: this.rowSelectionStore,
        };
        (_b = this.rangeUnsubscribe) === null || _b === void 0 ? void 0 : _b.call(this);
        this.rangeUnsubscribe = this.rowSelectionStore.onChange('range', (e) => this.rowHighlightPlugin.selectionChange(e, this.renderedRows));
    }
    connectedCallback() {
        this.rowHighlightPlugin = new RowHighlightPlugin();
        this.onStoreChange();
    }
    disconnectedCallback() {
        var _a, _b;
        (_a = this.columnService) === null || _a === void 0 ? void 0 : _a.destroy();
        (_b = this.rangeUnsubscribe) === null || _b === void 0 ? void 0 : _b.call(this);
    }
    async componentWillRender() {
        this.beforeDataRender.emit({
            rowType: this.type,
            colType: this.colType,
        });
        return Promise.all(this.jobsBeforeRender.map(p => typeof p === 'function' ? p() : p));
    }
    componentDidRender() {
        this.afterrender.emit({ type: this.type });
    }
    render() {
        this.renderedRows = new Map();
        const columnsData = this.columnService.columns;
        if (!columnsData.length) {
            return;
        }
        const rows = this.viewportRow.get('items');
        if (!rows.length) {
            return;
        }
        const cols = this.viewportCol.get('items');
        if (!cols.length) {
            return;
        }
        const rowsEls = [];
        const depth = this.dataStore.get('groupingDepth');
        const groupingCustomRenderer = this.dataStore.get('groupingCustomRenderer');
        const groupDepth = this.columnService.hasGrouping ? depth : 0;
        const rowRenderOffset = this.viewportRow.get('renderOffset') || 0;
        const colRenderOffset = this.viewportCol.get('renderOffset') || 0;
        for (let rgRow of rows) {
            const dataItem = getSourceItem(this.dataStore, rgRow.itemIndex);
            // #region Grouping
            if (isGrouping(dataItem)) {
                const gmodel = Object.assign(Object.assign({}, rgRow), { start: rgRow.start - rowRenderOffset, index: rgRow.itemIndex, model: dataItem, groupingCustomRenderer,
                    // Only show expand button if grouping is enabled and not in row headers
                    hasExpand: this.columnService.hasGrouping && this.colType !== 'rowHeaders', columnItems: cols, providers: this.providers });
                rowsEls.push(h(GroupingRowRenderer, Object.assign({}, gmodel)));
                continue;
            }
            // #endregion
            const cells = [];
            // #region Cells
            for (let rgCol of cols) {
                const smodel = Object.assign(Object.assign({}, this.columnService.rowDataModel(rgRow.itemIndex, rgCol.itemIndex)), { providers: this.providers });
                // call before cell render
                const cellEvent = this.triggerBeforeCellRender(smodel, rgRow, rgCol);
                // if event was prevented
                if (cellEvent.defaultPrevented) {
                    continue;
                }
                const { detail: { column: columnProps, row: rowProps, model: schemaModel }, } = cellEvent;
                const defaultProps = {
                    [DATA_COL]: columnProps.itemIndex,
                    [DATA_ROW]: rowProps.itemIndex,
                    style: {
                        width: `${columnProps.size}px`,
                        transform: `translateX(${columnProps.start - colRenderOffset}px)`,
                        height: rowProps.size ? `${rowProps.size}px` : undefined,
                    },
                };
                /**
                 * For grouping, can be removed in the future and replaced with event
                 */
                if (groupDepth && !columnProps.itemIndex && defaultProps.style) {
                    defaultProps.style.paddingLeft = `${PADDING_DEPTH * groupDepth}px`;
                }
                const props = this.columnService.mergeProperties(rowProps.itemIndex, columnProps.itemIndex, defaultProps, schemaModel);
                // Never use webcomponent for cell render
                // It's very slow because of webcomponent initialization takes time
                const cellNode = h(CellRenderer, { renderProps: {
                        schemaModel,
                        additionalData: this.additionalData,
                        dragStartCell: this.dragStartCell,
                    }, cellProps: props });
                cells.push(cellNode);
            }
            // #endregion
            // #region Rows
            let rowClass = this.rowClass
                ? this.columnService.getRowClass(rgRow.itemIndex, this.rowClass)
                : '';
            if (this.rowHighlightPlugin.isRowFocused(rgRow.itemIndex)) {
                rowClass += ` ${ROW_FOCUSED_CLASS}`;
            }
            const row = (h(RowRenderer, { index: rgRow.itemIndex, rowClass: rowClass, size: rgRow.size, start: rgRow.start - rowRenderOffset, groupingLevel: groupDepth || undefined }, cells));
            this.beforerowrender.emit({
                node: row,
                item: rgRow,
                model: dataItem,
                colType: this.columnService.type,
                rowType: this.type,
            });
            rowsEls.push(row);
            this.renderedRows.set(rgRow.itemIndex, row);
            // #endregion
        }
        return (h(Host, null, h("slot", null), rowsEls));
    }
    triggerBeforeCellRender(model, row, column) {
        const detail = {
            column,
            row,
            model,
            rowType: model.type,
            colType: model.colType,
        };
        return this.beforeCellRender.emit(detail);
    }
    static get is() { return "revogr-data"; }
    static get originalStyleUrls() {
        return {
            "$": ["revogr-data-style.scss"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["revogr-data-style.css"]
        };
    }
    static get properties() {
        return {
            "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"
            },
            "range": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Range allowed"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "range"
            },
            "rowClass": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Defines property from which to read row class"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "row-class"
            },
            "additionalData": {
                "type": "any",
                "mutable": false,
                "complexType": {
                    "original": "any",
                    "resolved": "any",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Additional data to pass to renderer\nUsed in plugins such as vue or react to pass root app entity to cells"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "additional-data"
            },
            "rowSelectionStore": {
                "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": true,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Selection, range, focus for row selection"
                },
                "getter": false,
                "setter": false
            },
            "viewportRow": {
                "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": true,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Viewport Y"
                },
                "getter": false,
                "setter": false
            },
            "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": true,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Viewport X"
                },
                "getter": false,
                "setter": false
            },
            "dimensionRow": {
                "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": true,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Dimension settings Y"
                },
                "getter": false,
                "setter": false
            },
            "colData": {
                "type": "unknown",
                "mutable": false,
                "complexType": {
                    "original": "Observable<DSourceState<ColumnRegular, DimensionCols>>",
                    "resolved": "\"colPinEnd\" | \"colPinStart\" | \"rgCol\" | ColumnRegular<ColumnProp, DataType<any, ColumnProp>>",
                    "references": {
                        "Observable": {
                            "location": "import",
                            "path": "../../utils",
                            "id": "src/utils/index.ts::Observable",
                            "referenceLocation": "Observable"
                        },
                        "DSourceState": {
                            "location": "import",
                            "path": "@store",
                            "id": "src/store/index.ts::DSourceState",
                            "referenceLocation": "DSourceState"
                        },
                        "ColumnRegular": {
                            "location": "import",
                            "path": "@type",
                            "id": "src/types/index.ts::ColumnRegular",
                            "referenceLocation": "ColumnRegular"
                        },
                        "DimensionCols": {
                            "location": "import",
                            "path": "@type",
                            "id": "src/types/index.ts::DimensionCols",
                            "referenceLocation": "DimensionCols"
                        }
                    }
                },
                "required": true,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Column source"
                },
                "getter": false,
                "setter": false
            },
            "dataStore": {
                "type": "unknown",
                "mutable": false,
                "complexType": {
                    "original": "Observable<DSourceState<DataType, DimensionRows>>",
                    "resolved": "\"rgRow\" | \"rowPinEnd\" | \"rowPinStart\" | D | K",
                    "references": {
                        "Observable": {
                            "location": "import",
                            "path": "../../utils",
                            "id": "src/utils/index.ts::Observable",
                            "referenceLocation": "Observable"
                        },
                        "DSourceState": {
                            "location": "import",
                            "path": "@store",
                            "id": "src/store/index.ts::DSourceState",
                            "referenceLocation": "DSourceState"
                        },
                        "DataType": {
                            "location": "import",
                            "path": "@type",
                            "id": "src/types/index.ts::DataType",
                            "referenceLocation": "DataType"
                        },
                        "DimensionRows": {
                            "location": "import",
                            "path": "@type",
                            "id": "src/types/index.ts::DimensionRows",
                            "referenceLocation": "DimensionRows"
                        }
                    }
                },
                "required": true,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Data rows source"
                },
                "getter": false,
                "setter": false
            },
            "type": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "DimensionRows",
                    "resolved": "\"rgRow\" | \"rowPinEnd\" | \"rowPinStart\"",
                    "references": {
                        "DimensionRows": {
                            "location": "import",
                            "path": "@type",
                            "id": "src/types/index.ts::DimensionRows",
                            "referenceLocation": "DimensionRows"
                        }
                    }
                },
                "required": true,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Row data type"
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "type"
            },
            "colType": {
                "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 data type"
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "col-type"
            },
            "jobsBeforeRender": {
                "type": "unknown",
                "mutable": false,
                "complexType": {
                    "original": "(Promise<any> | (() => Promise<any>))[]",
                    "resolved": "(Promise<any> | (() => Promise<any>))[]",
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Prevent rendering until job is done.\nCan be used for initial rendering performance improvement.\nWhen several plugins require initial rendering this will prevent double initial rendering."
                },
                "getter": false,
                "setter": false,
                "defaultValue": "[]"
            }
        };
    }
    static get states() {
        return {
            "providers": {}
        };
    }
    static get events() {
        return [{
                "method": "beforerowrender",
                "name": "beforerowrender",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Before each row render"
                },
                "complexType": {
                    "original": "BeforeRowRenderEvent",
                    "resolved": "BeforeRowRenderEvent<any>",
                    "references": {
                        "BeforeRowRenderEvent": {
                            "location": "import",
                            "path": "@type",
                            "id": "src/types/index.ts::BeforeRowRenderEvent",
                            "referenceLocation": "BeforeRowRenderEvent"
                        }
                    }
                }
            }, {
                "method": "afterrender",
                "name": "afterrender",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "When data render finished for the designated type"
                },
                "complexType": {
                    "original": "{ type: DimensionRows }",
                    "resolved": "{ type: DimensionRows; }",
                    "references": {
                        "DimensionRows": {
                            "location": "import",
                            "path": "@type",
                            "id": "src/types/index.ts::DimensionRows",
                            "referenceLocation": "DimensionRows"
                        }
                    }
                }
            }, {
                "method": "beforeCellRender",
                "name": "beforecellrender",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Before each cell render function. Allows to override cell properties"
                },
                "complexType": {
                    "original": "BeforeCellRenderEvent<CellTemplateProp>",
                    "resolved": "BeforeCellRenderEvent<CellTemplateProp<DataType<any, ColumnProp>, ColumnRegular<ColumnProp, DataType<any, ColumnProp>>, ColumnProp>>",
                    "references": {
                        "BeforeCellRenderEvent": {
                            "location": "import",
                            "path": "@type",
                            "id": "src/types/index.ts::BeforeCellRenderEvent",
                            "referenceLocation": "BeforeCellRenderEvent"
                        },
                        "CellTemplateProp": {
                            "location": "import",
                            "path": "@type",
                            "id": "src/types/index.ts::CellTemplateProp",
                            "referenceLocation": "CellTemplateProp"
                        }
                    }
                }
            }, {
                "method": "beforeDataRender",
                "name": "beforedatarender",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Before data render"
                },
                "complexType": {
                    "original": "AllDimensionType",
                    "resolved": "AllDimensionType",
                    "references": {
                        "AllDimensionType": {
                            "location": "import",
                            "path": "@type",
                            "id": "src/types/index.ts::AllDimensionType",
                            "referenceLocation": "AllDimensionType"
                        }
                    }
                }
            }, {
                "method": "dragStartCell",
                "name": "dragstartcell",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Event emitted on cell drag start"
                },
                "complexType": {
                    "original": "DragStartEvent",
                    "resolved": "DragStartEvent<DataType<any, ColumnProp>, ColumnRegular<ColumnProp, DataType<any, ColumnProp>>>",
                    "references": {
                        "DragStartEvent": {
                            "location": "import",
                            "path": "@type",
                            "id": "src/types/index.ts::DragStartEvent",
                            "referenceLocation": "DragStartEvent"
                        }
                    }
                }
            }];
    }
    static get methods() {
        return {
            "updateCell": {
                "complexType": {
                    "signature": "(e: { row: number; col: number; }) => Promise<void>",
                    "parameters": [{
                            "name": "e",
                            "type": "{ row: number; col: number; }",
                            "docs": ""
                        }],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "Pointed cell update.",
                    "tags": []
                }
            }
        };
    }
    static get elementRef() { return "element"; }
    static get watchers() {
        return [{
                "propName": "dataStore",
                "methodName": "onDataStoreChange"
            }, {
                "propName": "colData",
                "methodName": "onColDataChange"
            }];
    }
}
