/**
 * DevExtreme (esm/__internal/grids/grid_core/column_headers/m_column_headers.js)
 * Version: 23.1.6 (build 23316-0110)
 * Build date: Sun Nov 12 2023
 *
 * Copyright (c) 2012 - 2023 Developer Express Inc. ALL RIGHTS RESERVED
 * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
 */
import domAdapter from "../../../../core/dom_adapter";
import $ from "../../../../core/renderer";
import {
    extend
} from "../../../../core/utils/extend";
import {
    each
} from "../../../../core/utils/iterator";
import {
    getHeight
} from "../../../../core/utils/size";
import {
    isDefined
} from "../../../../core/utils/type";
import eventsEngine from "../../../../events/core/events_engine";
import messageLocalization from "../../../../localization/message";
import {
    registerKeyboardAction
} from "../m_accessibility";
import {
    ColumnsView
} from "../views/m_columns_view";
var CELL_CONTENT_CLASS = "text-content";
var HEADERS_CLASS = "headers";
var NOWRAP_CLASS = "nowrap";
var ROW_CLASS_SELECTOR = ".dx-row";
var HEADER_ROW_CLASS = "dx-header-row";
var COLUMN_LINES_CLASS = "dx-column-lines";
var CONTEXT_MENU_SORT_ASC_ICON = "context-menu-sort-asc";
var CONTEXT_MENU_SORT_DESC_ICON = "context-menu-sort-desc";
var CONTEXT_MENU_SORT_NONE_ICON = "context-menu-sort-none";
var CELL_FOCUS_DISABLED_CLASS = "dx-cell-focus-disabled";
var VISIBILITY_HIDDEN_CLASS = "dx-visibility-hidden";
var TEXT_CONTENT_ALIGNMENT_CLASS_PREFIX = "dx-text-content-alignment-";
var SORT_INDICATOR_CLASS = "dx-sort-indicator";
var SORT_INDEX_INDICATOR_CLASS = "dx-sort-index-indicator";
var HEADER_FILTER_CLASS_SELECTOR = ".dx-header-filter";
var HEADER_FILTER_INDICATOR_CLASS = "dx-header-filter-indicator";
var MULTI_ROW_HEADER_CLASS = "dx-header-multi-row";
var LINK = "dx-link";
export var columnHeadersModule = {
    defaultOptions: () => ({
        showColumnHeaders: true,
        cellHintEnabled: true
    }),
    views: {
        columnHeadersView: ColumnsView.inherit(function() {
            var createCellContent = function(that, $cell, options) {
                var $cellContent = $("<div>").addClass(that.addWidgetPrefix(CELL_CONTENT_CLASS));
                that.setAria("role", "presentation", $cellContent);
                addCssClassesToCellContent(that, $cell, options.column, $cellContent);
                var showColumnLines = that.option("showColumnLines");
                var contentAlignment = that.getController("columns").getHeaderContentAlignment(options.column.alignment);
                return $cellContent[showColumnLines || "right" === contentAlignment ? "appendTo" : "prependTo"]($cell)
            };

            function addCssClassesToCellContent(that, $cell, column, $cellContent) {
                var $indicatorElements = that._getIndicatorElements($cell, true);
                var $visibleIndicatorElements = that._getIndicatorElements($cell);
                var indicatorCount = $indicatorElements && $indicatorElements.length;
                var columnAlignment = that._getColumnAlignment(column.alignment);
                var sortIndicatorClassName = ".".concat(that._getIndicatorClassName("sort"));
                var sortIndexIndicatorClassName = ".".concat(that._getIndicatorClassName("sortIndex"));
                var $sortIndicator = $visibleIndicatorElements.filter(sortIndicatorClassName);
                var $sortIndexIndicator = $visibleIndicatorElements.children().filter(sortIndexIndicatorClassName);
                $cellContent = $cellContent || $cell.children(".".concat(that.addWidgetPrefix(CELL_CONTENT_CLASS)));
                $cellContent.toggleClass(TEXT_CONTENT_ALIGNMENT_CLASS_PREFIX + columnAlignment, indicatorCount > 0).toggleClass(TEXT_CONTENT_ALIGNMENT_CLASS_PREFIX + ("left" === columnAlignment ? "right" : "left"), indicatorCount > 0 && "center" === column.alignment).toggleClass(SORT_INDICATOR_CLASS, !!$sortIndicator.length).toggleClass(SORT_INDEX_INDICATOR_CLASS, !!$sortIndexIndicator.length).toggleClass(HEADER_FILTER_INDICATOR_CLASS, !!$visibleIndicatorElements.filter(".".concat(that._getIndicatorClassName("headerFilter"))).length)
            }
            var members = {
                _createTable() {
                    var $table = this.callBase.apply(this, arguments);
                    eventsEngine.on($table, "mousedown selectstart", this.createAction(e => {
                        var {
                            event: event
                        } = e;
                        if (event.shiftKey) {
                            event.preventDefault()
                        }
                    }));
                    return $table
                },
                _isLegacyKeyboardNavigation() {
                    return this.option("useLegacyKeyboardNavigation")
                },
                _getDefaultTemplate(column) {
                    var that = this;
                    return function($container, options) {
                        var {
                            caption: caption
                        } = column;
                        var needCellContent = !column.command || caption && "expand" !== column.command;
                        if ("empty" === column.command) {
                            that._renderEmptyMessage($container, options)
                        } else if (needCellContent) {
                            var $content = createCellContent(that, $container, options);
                            $content.text(caption)
                        } else if (column.command) {
                            $container.html("&nbsp;")
                        }
                    }
                },
                _renderEmptyMessage($container, options) {
                    var textEmpty = this._getEmptyHeaderText();
                    if (!textEmpty) {
                        $container.html("&nbsp;");
                        return
                    }
                    var $cellContent = createCellContent(this, $container, options);
                    var needSplit = textEmpty.includes("{0}");
                    if (needSplit) {
                        var [leftPart, rightPart] = textEmpty.split("{0}");
                        var columnChooserTitle = messageLocalization.format("dxDataGrid-emptyHeaderColumnChooserText");
                        var columnChooserView = this.component.getView("columnChooserView");
                        var $link = $("<a>").text(columnChooserTitle).addClass(LINK);
                        eventsEngine.on($link, "click", this.createAction(() => columnChooserView.showColumnChooser()));
                        $cellContent.append(domAdapter.createTextNode(leftPart)).append($link).append(domAdapter.createTextNode(rightPart))
                    } else {
                        $cellContent.text(textEmpty)
                    }
                },
                _getEmptyHeaderText() {
                    var hasHiddenColumns = !!this.component.getView("columnChooserView").hasHiddenColumns();
                    var hasGroupedColumns = !!this.component.getView("headerPanel").hasGroupedColumns();
                    switch (true) {
                        case hasHiddenColumns && hasGroupedColumns:
                            return messageLocalization.format("dxDataGrid-emptyHeaderWithColumnChooserAndGroupPanelText");
                        case hasGroupedColumns:
                            return messageLocalization.format("dxDataGrid-emptyHeaderWithGroupPanelText");
                        case hasHiddenColumns:
                            return messageLocalization.format("dxDataGrid-emptyHeaderWithColumnChooserText");
                        default:
                            return ""
                    }
                },
                _getHeaderTemplate(column) {
                    return column.headerCellTemplate || {
                        allowRenderToDetachedContainer: true,
                        render: this._getDefaultTemplate(column)
                    }
                },
                _processTemplate(template, options) {
                    var that = this;
                    var resultTemplate;
                    var {
                        column: column
                    } = options;
                    var renderingTemplate = that.callBase(template);
                    if ("header" === options.rowType && renderingTemplate && column.headerCellTemplate && !column.command) {
                        resultTemplate = {
                            render(options) {
                                var $content = createCellContent(that, options.container, options.model);
                                renderingTemplate.render(extend({}, options, {
                                    container: $content
                                }))
                            }
                        }
                    } else {
                        resultTemplate = renderingTemplate
                    }
                    return resultTemplate
                },
                _handleDataChanged(e) {
                    if ("refresh" !== e.changeType) {
                        return
                    }
                    if (this._isGroupingChanged || this._requireReady) {
                        this._isGroupingChanged = false;
                        this.render()
                    }
                },
                _renderCell($row, options) {
                    var $cell = this.callBase($row, options);
                    if ("header" === options.row.rowType) {
                        $cell.addClass(CELL_FOCUS_DISABLED_CLASS);
                        if (!this._isLegacyKeyboardNavigation()) {
                            if (options.column && !options.column.type) {
                                $cell.attr("tabindex", this.option("tabindex") || 0)
                            }
                        }
                    }
                    return $cell
                },
                _setCellAriaAttributes($cell, cellOptions) {
                    this.callBase($cell, cellOptions);
                    if ("header" === cellOptions.rowType) {
                        if (!cellOptions.column.type) {
                            this.setAria("role", "columnheader", $cell)
                        }
                        if (cellOptions.column && !cellOptions.column.command && !cellOptions.column.isBand) {
                            $cell.attr("id", cellOptions.column.headerId);
                            this.setAria("label", "".concat(messageLocalization.format("dxDataGrid-ariaColumn"), " ").concat(cellOptions.column.caption), $cell)
                        }
                    }
                },
                _createRow(row) {
                    var $row = this.callBase.apply(this, arguments);
                    $row.toggleClass(COLUMN_LINES_CLASS, this.option("showColumnLines"));
                    if ("header" === row.rowType) {
                        $row.addClass(HEADER_ROW_CLASS);
                        if (!this._isLegacyKeyboardNavigation()) {
                            registerKeyboardAction("columnHeaders", this, $row, "td", this._handleActionKeyDown.bind(this))
                        }
                    }
                    return $row
                },
                _handleActionKeyDown(args) {
                    var {
                        event: event
                    } = args;
                    var $target = $(event.target);
                    this._lastActionElement = event.target;
                    if ($target.is(HEADER_FILTER_CLASS_SELECTOR)) {
                        var headerFilterController = this.getController("headerFilter");
                        var $column = $target.closest("td");
                        var columnIndex = this.getColumnIndexByElement($column);
                        if (columnIndex >= 0) {
                            headerFilterController.showHeaderFilterMenu(columnIndex, false)
                        }
                    } else {
                        var $row = $target.closest(ROW_CLASS_SELECTOR);
                        this._processHeaderAction(event, $row)
                    }
                    event.preventDefault()
                },
                _renderCore() {
                    var $container = this.element();
                    var change = {};
                    if (this._tableElement && !this._dataController.isLoaded() && !this._hasRowElements) {
                        return
                    }
                    $container.addClass(this.addWidgetPrefix(HEADERS_CLASS)).toggleClass(this.addWidgetPrefix(NOWRAP_CLASS), !this.option("wordWrapEnabled")).empty();
                    this.setAria("role", "presentation", $container);
                    var deferred = this._updateContent(this._renderTable({
                        change: change
                    }), change);
                    if (this.getRowCount() > 1) {
                        $container.addClass(MULTI_ROW_HEADER_CLASS)
                    }
                    this.callBase.apply(this, arguments);
                    return deferred
                },
                _renderRows() {
                    if (this._dataController.isLoaded() || this._hasRowElements) {
                        this.callBase.apply(this, arguments);
                        this._hasRowElements = true
                    }
                },
                _renderRow($table, options) {
                    var rowIndex = 1 === this.getRowCount() ? null : options.row.rowIndex;
                    options.columns = this.getColumns(rowIndex);
                    this.callBase($table, options)
                },
                _createCell(options) {
                    var {
                        column: column
                    } = options;
                    var $cellElement = this.callBase.apply(this, arguments);
                    column.rowspan > 1 && "header" === options.rowType && $cellElement.attr("rowSpan", column.rowspan);
                    return $cellElement
                },
                _getRows() {
                    var result = [];
                    var rowCount = this.getRowCount();
                    if (this.option("showColumnHeaders")) {
                        for (var i = 0; i < rowCount; i++) {
                            result.push({
                                rowType: "header",
                                rowIndex: i
                            })
                        }
                    }
                    return result
                },
                _getCellTemplate(options) {
                    if ("header" === options.rowType) {
                        return this._getHeaderTemplate(options.column)
                    }
                },
                _columnOptionChanged(e) {
                    var {
                        changeTypes: changeTypes
                    } = e;
                    var {
                        optionNames: optionNames
                    } = e;
                    if (changeTypes.grouping || changeTypes.groupExpanding) {
                        if (changeTypes.grouping) {
                            this._isGroupingChanged = true
                        }
                        return
                    }
                    this.callBase(e);
                    if (optionNames.width || optionNames.visible) {
                        this.resizeCompleted.fire()
                    }
                },
                _isElementVisible: elementOptions => elementOptions && elementOptions.visible,
                _alignCaptionByCenter($cell) {
                    var $indicatorsContainer = this._getIndicatorContainer($cell, true);
                    if ($indicatorsContainer && $indicatorsContainer.length) {
                        $indicatorsContainer.filter(".".concat(VISIBILITY_HIDDEN_CLASS)).remove();
                        $indicatorsContainer = this._getIndicatorContainer($cell);
                        $indicatorsContainer.clone().addClass(VISIBILITY_HIDDEN_CLASS).css("float", "").insertBefore($cell.children(".".concat(this.addWidgetPrefix(CELL_CONTENT_CLASS))))
                    }
                },
                _updateCell($cell, options) {
                    if ("header" === options.rowType && "center" === options.column.alignment) {
                        this._alignCaptionByCenter($cell)
                    }
                    this.callBase.apply(this, arguments)
                },
                _updateIndicator($cell, column, indicatorName) {
                    var $indicatorElement = this.callBase.apply(this, arguments);
                    if ("center" === column.alignment) {
                        this._alignCaptionByCenter($cell)
                    }
                    addCssClassesToCellContent(this, $cell, column);
                    return $indicatorElement
                },
                _getIndicatorContainer($cell, returnAll) {
                    var $indicatorsContainer = this.callBase($cell);
                    return returnAll ? $indicatorsContainer : $indicatorsContainer.filter(":not(.".concat(VISIBILITY_HIDDEN_CLASS, ")"))
                },
                _isSortableElement: () => true,
                getHeadersRowHeight() {
                    var $tableElement = this.getTableElement();
                    var $headerRows = $tableElement && $tableElement.find(".".concat(HEADER_ROW_CLASS));
                    return $headerRows && $headerRows.toArray().reduce((sum, headerRow) => sum + getHeight(headerRow), 0) || 0
                },
                getHeaderElement(index) {
                    var columnElements = this.getColumnElements();
                    return columnElements && columnElements.eq(index)
                },
                getColumnElements(index, bandColumnIndex) {
                    var that = this;
                    var $cellElement;
                    var columnsController = that._columnsController;
                    var rowCount = that.getRowCount();
                    if (that.option("showColumnHeaders")) {
                        if (rowCount > 1 && (!isDefined(index) || isDefined(bandColumnIndex))) {
                            var result = [];
                            var visibleColumns = isDefined(bandColumnIndex) ? columnsController.getChildrenByBandColumn(bandColumnIndex, true) : columnsController.getVisibleColumns();
                            each(visibleColumns, (_, column) => {
                                var rowIndex = isDefined(index) ? index : columnsController.getRowIndex(column.index);
                                $cellElement = that._getCellElement(rowIndex, columnsController.getVisibleIndex(column.index, rowIndex));
                                $cellElement && result.push($cellElement.get(0))
                            });
                            return $(result)
                        }
                        if (!index || index < rowCount) {
                            return that.getCellElements(index || 0)
                        }
                    }
                },
                getColumnIndexByElement($cell) {
                    var cellIndex = this.getCellIndex($cell);
                    var $row = $cell.closest(".dx-row");
                    var {
                        rowIndex: rowIndex
                    } = $row[0];
                    var column = this.getColumns(rowIndex)[cellIndex];
                    return column ? column.index : -1
                },
                getVisibleColumnIndex(columnIndex, rowIndex) {
                    var column = this.getColumns()[columnIndex];
                    return column ? this._columnsController.getVisibleIndex(column.index, rowIndex) : -1
                },
                getColumnWidths() {
                    var $columnElements = this.getColumnElements();
                    if ($columnElements && $columnElements.length) {
                        return this._getWidths($columnElements)
                    }
                    return this.callBase.apply(this, arguments)
                },
                allowDragging(column) {
                    var rowIndex = column && this._columnsController.getRowIndex(column.index);
                    var columns = this.getColumns(rowIndex);
                    var isReorderingEnabled = this.option("allowColumnReordering") || this._columnsController.isColumnOptionUsed("allowReordering");
                    return isReorderingEnabled && column.allowReordering && columns.length > 1
                },
                getBoundingRect() {
                    var $columnElements = this.getColumnElements();
                    if ($columnElements && $columnElements.length) {
                        var offset = this.getTableElement().offset();
                        return {
                            top: offset.top
                        }
                    }
                    return null
                },
                getName: () => "headers",
                getColumnCount() {
                    var $columnElements = this.getColumnElements();
                    return $columnElements ? $columnElements.length : 0
                },
                isVisible() {
                    return this.option("showColumnHeaders")
                },
                optionChanged(args) {
                    switch (args.name) {
                        case "showColumnHeaders":
                        case "wordWrapEnabled":
                        case "showColumnLines":
                            this._invalidate(true, true);
                            args.handled = true;
                            break;
                        default:
                            this.callBase(args)
                    }
                },
                getHeight() {
                    return this.getElementHeight()
                },
                getContextMenuItems(options) {
                    var that = this;
                    var {
                        column: column
                    } = options;
                    if (options.row && ("header" === options.row.rowType || "detailAdaptive" === options.row.rowType)) {
                        var sortingOptions = that.option("sorting");
                        if (sortingOptions && "none" !== sortingOptions.mode && column && column.allowSorting) {
                            var onItemClick = function(params) {
                                setTimeout(() => {
                                    that._columnsController.changeSortOrder(column.index, params.itemData.value)
                                })
                            };
                            return [{
                                text: sortingOptions.ascendingText,
                                value: "asc",
                                disabled: "asc" === column.sortOrder,
                                icon: CONTEXT_MENU_SORT_ASC_ICON,
                                onItemClick: onItemClick
                            }, {
                                text: sortingOptions.descendingText,
                                value: "desc",
                                disabled: "desc" === column.sortOrder,
                                icon: CONTEXT_MENU_SORT_DESC_ICON,
                                onItemClick: onItemClick
                            }, {
                                text: sortingOptions.clearText,
                                value: "none",
                                disabled: !column.sortOrder,
                                icon: CONTEXT_MENU_SORT_NONE_ICON,
                                onItemClick: onItemClick
                            }]
                        }
                    }
                    return
                },
                getRowCount() {
                    return this._columnsController && this._columnsController.getRowCount()
                },
                setRowsOpacity(columnIndex, value, rowIndex) {
                    var i;
                    var columnElements;
                    var rowCount = this.getRowCount();
                    var columns = this._columnsController.getColumns();
                    var column = columns && columns[columnIndex];
                    var columnID = column && column.isBand && column.index;
                    var setColumnOpacity = (column, index) => {
                        if (column.ownerBand === columnID) {
                            columnElements.eq(index).css({
                                opacity: value
                            });
                            if (column.isBand) {
                                this.setRowsOpacity(column.index, value, i + 1)
                            }
                        }
                    };
                    if (isDefined(columnID)) {
                        rowIndex = rowIndex || 0;
                        for (i = rowIndex; i < rowCount; i++) {
                            columnElements = this.getCellElements(i);
                            if (columnElements) {
                                var rowColumns = this.getColumns(i);
                                rowColumns.forEach(setColumnOpacity)
                            }
                        }
                    }
                }
            };
            return members
        }())
    }
};
