import { classNameToList, createDomElement, toKebabCase } from '@slickgrid-universal/utils';
import { getTranslationPrefix } from '../services/index.js';
import { MenuBaseClass } from './menuBaseClass.js';
/**
 * A plugin to add drop-down menus to column headers.
 * To specify a custom button in a column header, extend the column definition like so:
 *   this.columnDefinitions = [{
 *     id: 'myColumn', name: 'My column',
 *     header: {
 *       menu: {
 *         commandItems: [{ ...menu item options... }, { ...menu item options... }]
 *       }
 *     }
 *   }];
 */
export class SlickHeaderMenu extends MenuBaseClass {
    /** Constructor of the SlickGrid 3rd party plugin, it can optionally receive options */
    constructor(extensionUtility, filterService, pubSubService, sharedService, sortService) {
        super(extensionUtility, pubSubService, sharedService);
        this.extensionUtility = extensionUtility;
        this.filterService = filterService;
        this.pubSubService = pubSubService;
        this.sharedService = sharedService;
        this.sortService = sortService;
        this._subMenuParentId = '';
        this._defaults = {
            autoAlign: true,
            autoAlignOffset: 0,
            buttonCssClass: null,
            buttonImage: null,
            minWidth: 100,
            hideColumnHideCommand: false,
            hideSortCommands: false,
            title: '',
            subMenuOpenByEvent: 'mouseover',
        };
        this.pluginName = 'HeaderMenu';
        this._menuCssPrefix = 'slick-menu';
        this._menuPluginCssPrefix = 'slick-header-menu';
        this._camelPluginName = 'headerMenu';
        this.init(sharedService.gridOptions.headerMenu);
    }
    /** Initialize plugin. */
    init(headerMenuOptions) {
        this._addonOptions = { ...this._defaults, ...headerMenuOptions };
        // when setColumns is called (could be via toggle filtering/sorting or anything else),
        // we need to recreate header menu items custom commands array before the `onHeaderCellRendered` gets called
        this._eventHandler.subscribe(this.grid.onBeforeSetColumns, (_e, args) => this.recreateHeaderMenu(args.newColumns));
        this._eventHandler.subscribe(this.grid.onHeaderCellRendered, this.handleHeaderCellRendered.bind(this));
        this._eventHandler.subscribe(this.grid.onBeforeHeaderCellDestroy, this.handleBeforeHeaderCellDestroy.bind(this));
        this._eventHandler.subscribe(this.grid.onClick, this.hideMenu.bind(this));
        // force the grid to re-render the header after the events are hooked up.
        this.grid.setColumns(this.grid.getColumns());
        // hide the menu when clicking outside the grid
        this._bindEventService.bind(document.body, 'mousedown', this.handleBodyMouseDown.bind(this));
    }
    /** Dispose (destroy) of the plugin */
    dispose() {
        super.dispose();
        this._menuElm = this._menuElm || document.body.querySelector(`.slick-header-menu${this.gridUidSelector}`);
        this._menuElm?.remove();
        this._activeHeaderColumnElm = undefined;
    }
    /** Hide a column from the grid */
    hideColumn(column) {
        if (this.grid) {
            // check if column freezing is allowed
            const isFrozenAllowed = this.grid.validateColumnFreeze(column.id, true);
            // when valid, update column hidden prop
            if (isFrozenAllowed) {
                this.grid.updateColumnById(column.id, { hidden: true });
                // then proceed with hiding the column in SlickGrid & trigger an event when done
                this.grid.updateColumns();
                this.pubSubService.publish('onHideColumns', { columns: this.grid.getVisibleColumns(), hiddenColumn: column });
            }
        }
    }
    /** Hide the Header Menu */
    hideMenu() {
        this.disposeSubMenus();
        this._menuElm?.remove();
        this._menuElm = undefined;
    }
    repositionSubMenu(e, item, level, columnDef) {
        // creating sub-menu, we'll also pass level & the item object since we might have "subMenuTitle" to show
        const subMenuElm = this.createCommandMenu(e.target, item.commandItems || [], columnDef, level + 1, item);
        document.body.appendChild(subMenuElm);
        this.repositionMenu(e, subMenuElm, undefined, this.addonOptions);
    }
    /** Translate the Header Menu titles, we need to loop through all column definition to re-translate them */
    translateHeaderMenu() {
        if (this.sharedService.gridOptions?.headerMenu) {
            this.resetHeaderMenuTranslations(this.grid.getColumns());
        }
    }
    // --
    // event handlers
    // ------------------
    /**
     * Event handler when column title header are being rendered
     * @param {Object} event - The event
     * @param {Object} args - object arguments
     */
    handleHeaderCellRendered(_e, args) {
        const column = args.column;
        const menu = column.header?.menu;
        if (menu && args.node) {
            // run the override function (when defined), if the result is false we won't go further
            if (!this.extensionUtility.runOverrideFunctionWhenExists(this.addonOptions.menuUsabilityOverride, args)) {
                return;
            }
            const headerButtonDivElm = createDomElement('div', { className: 'slick-header-menu-button', ariaLabel: 'Header Menu', tabIndex: 0 }, args.node);
            // Create icon element inside button container
            const iconElm = createDomElement('span', { className: 'slick-header-menu-icon' });
            headerButtonDivElm.appendChild(iconElm);
            if (this.addonOptions.buttonCssClass) {
                headerButtonDivElm.classList.add(...classNameToList(this.addonOptions.buttonCssClass));
            }
            if (this.addonOptions.tooltip) {
                headerButtonDivElm.title = this.addonOptions.tooltip;
            }
            // show the header menu dropdown list of commands on click or keyboard activation
            this._bindEventService.bind(headerButtonDivElm, 'click', ((e) => {
                this.disposeAllMenus(); // make sure there's only 1 parent menu opened at a time
                this.createParentMenu(e, args.column, menu);
            }));
            this._bindEventService.bind(headerButtonDivElm, 'keydown', ((e) => {
                if (e.key === 'Enter' || e.key === ' ') {
                    e.preventDefault();
                    this.disposeAllMenus(); // make sure there's only 1 parent menu opened at a time
                    this.createParentMenu(e, args.column, menu);
                }
            }));
        }
    }
    /**
     * Event handler before the header cell is being destroyed
     * @param {Object} event - The event
     * @param {Object} args.column - The column definition
     */
    handleBeforeHeaderCellDestroy(_e, args) {
        const column = args.column;
        if (column.header?.menu) {
            // Removing buttons will also clean up any event handlers and data.
            // NOTE: If you attach event handlers directly or using a different framework,
            //       you must also clean them up here to avoid events leaking.
            args.node.querySelectorAll('.slick-header-menu-button').forEach((elm) => elm.remove());
        }
    }
    /** Mouse down handler when clicking anywhere in the DOM body */
    handleBodyMouseDown(e) {
        if (this.menuElement) {
            let isMenuClicked = false;
            const parentMenuElm = e.target.closest(`.${this.menuCssClass}`);
            // did we click inside the menu or any of its sub-menu(s)
            if (this.menuElement.contains(e.target) || parentMenuElm) {
                isMenuClicked = true;
            }
            if ((this._menuElm !== e.target && !isMenuClicked && !e.defaultPrevented) || (e.target.className === 'close' && parentMenuElm)) {
                this.hideMenu();
            }
        }
    }
    handleMenuItemCommandClick(event, _type, item, level = 0, columnDef) {
        if (item !== 'divider' && !item.disabled && !item.divider) {
            const command = item.command || '';
            if (command && !item.commandItems) {
                const callbackArgs = {
                    grid: this.grid,
                    command: item.command,
                    column: columnDef,
                    item,
                };
                // execute Grid Menu callback with command,
                // we'll also execute optional user defined onCommand callback when provided
                this.pubSubService.publish('onHeaderMenuCommand', callbackArgs);
                if (typeof this.addonOptions?.onCommand === 'function') {
                    this.addonOptions.onCommand(event, callbackArgs);
                }
                // execute action callback when defined
                if (typeof item.action === 'function') {
                    item.action.call(this, event, callbackArgs);
                }
                // does the user want to leave open the Grid Menu after executing a command?
                if (!event.defaultPrevented) {
                    this.hideMenu();
                }
                // Stop propagation so that it doesn't register as a header click event.
                event.preventDefault();
                event.stopPropagation();
            }
            else if (item.commandItems) {
                this.repositionSubMenu(event, item, level, columnDef);
            }
        }
    }
    handleMenuItemMouseOver(e, _type, item, level = 0, columnDef) {
        if (item !== 'divider' && !item.disabled && !item.divider) {
            if (item.commandItems) {
                this.repositionSubMenu(e, item, level, columnDef);
            }
            else if (level === 0) {
                this.disposeSubMenus();
            }
        }
    }
    // --
    // protected functions
    // ------------------
    /**
     * Create Header Menu with Custom Commands if user has enabled Header Menu
     * @param gridOptions
     * @param columns
     * @return header menu
     */
    addHeaderMenuCustomCommands(columns) {
        const gridOptions = this.sharedService.gridOptions;
        const headerMenuOptions = gridOptions.headerMenu || {};
        const translationPrefix = getTranslationPrefix(gridOptions);
        const commandLabels = this._addonOptions?.commandLabels;
        if (Array.isArray(columns) && gridOptions.enableHeaderMenu) {
            columns.forEach((columnDef) => {
                if (columnDef && !columnDef.excludeFromHeaderMenu) {
                    if (!columnDef.header) {
                        columnDef.header = {
                            menu: {
                                commandItems: [],
                            },
                        };
                    }
                    else if (!columnDef.header.menu) {
                        // we might have header buttons without header menu,
                        // so only initialize the header menu without overwrite header buttons
                        columnDef.header.menu = { commandItems: [] };
                    }
                    let columnHeaderMenuItems = columnDef?.header?.menu?.commandItems ?? [];
                    // Freeze Column (pinning)
                    let hasFrozenOrResizeCommand = false;
                    if (headerMenuOptions && !headerMenuOptions.hideFreezeColumnsCommand) {
                        hasFrozenOrResizeCommand = true;
                        if (gridOptions.frozenColumn === columns.findIndex((col) => col.id === columnDef.id)) {
                            // make sure the "freeze-columns" doesn't exist before adding the "unfreeze-columns"
                            this.removeCommandWhenFound(columnHeaderMenuItems, 'freeze-columns');
                            // add unfreeze command
                            const cmdUnfreeze = 'unfreeze-columns';
                            this.addMissingCommandOrAction({
                                _orgTitle: commandLabels?.unfreezeColumnsCommand || '',
                                iconCssClass: headerMenuOptions.iconUnfreezeColumns || 'mdi mdi-pin-off-outline',
                                titleKey: `${translationPrefix}UNFREEZE_COLUMNS`,
                                command: cmdUnfreeze,
                                positionOrder: 45,
                                action: (_e, args) => this.freezeOrUnfreezeColumns(args.column, cmdUnfreeze),
                            }, headerMenuOptions.hideCommands, columnHeaderMenuItems);
                        }
                        else {
                            // make sure the "unfreeze-columns" doesn't exist before adding the "freeze-columns"
                            this.removeCommandWhenFound(columnHeaderMenuItems, 'unfreeze-columns');
                            // add freeze command
                            const cmdFreeze = 'freeze-columns';
                            this.addMissingCommandOrAction({
                                _orgTitle: commandLabels?.freezeColumnsCommand || '',
                                iconCssClass: headerMenuOptions.iconFreezeColumns || 'mdi mdi-pin-outline',
                                titleKey: `${translationPrefix}FREEZE_COLUMNS`,
                                command: 'freeze-columns',
                                positionOrder: 45,
                                action: (_e, args) => this.freezeOrUnfreezeColumns(args.column, cmdFreeze),
                            }, headerMenuOptions.hideCommands, columnHeaderMenuItems);
                        }
                    }
                    // Column Resize by Content (column autofit)
                    if (headerMenuOptions &&
                        !headerMenuOptions.hideColumnResizeByContentCommand &&
                        !headerMenuOptions.hideCommands?.includes('column-resize-by-content') &&
                        this.sharedService.gridOptions.enableColumnResizeOnDoubleClick) {
                        hasFrozenOrResizeCommand = true;
                        this.addMissingCommandOrAction({
                            _orgTitle: commandLabels?.columnResizeByContentCommand || '',
                            iconCssClass: headerMenuOptions.iconColumnResizeByContentCommand || 'mdi mdi-arrow-expand-horizontal',
                            titleKey: `${translationPrefix}COLUMN_RESIZE_BY_CONTENT`,
                            command: 'column-resize-by-content',
                            positionOrder: 47,
                            action: (_e, args) => this.pubSubService.publish('onHeaderMenuColumnResizeByContent', { columnId: args.column.id }),
                        }, headerMenuOptions.hideCommands, columnHeaderMenuItems);
                    }
                    // add a divider (separator) between the top freeze columns commands and the rest of the commands
                    if (hasFrozenOrResizeCommand && !columnHeaderMenuItems.some((item) => item !== 'divider' && item.positionOrder === 48)) {
                        columnHeaderMenuItems.push({ divider: true, command: 'divider-1', positionOrder: 48 });
                    }
                    // Sorting Commands
                    if (gridOptions.enableSorting &&
                        columnDef.sortable &&
                        headerMenuOptions &&
                        !headerMenuOptions.hideSortCommands &&
                        // @deprecated use boolean value of addMissingCommandOrAction() in next major instead
                        !(headerMenuOptions.hideCommands?.includes('sort-asc') && headerMenuOptions.hideCommands?.includes('sort-desc'))) {
                        // sort ascending command
                        this.addMissingCommandOrAction({
                            _orgTitle: commandLabels?.sortAscCommand || '',
                            iconCssClass: headerMenuOptions.iconSortAscCommand || 'mdi mdi-sort-ascending',
                            titleKey: `${translationPrefix}SORT_ASCENDING`,
                            command: 'sort-asc',
                            positionOrder: 50,
                            action: (e, args) => this.sortColumn(e, args, true),
                        }, headerMenuOptions.hideCommands, columnHeaderMenuItems);
                        // sort descending command
                        this.addMissingCommandOrAction({
                            _orgTitle: commandLabels?.sortDescCommand || '',
                            iconCssClass: headerMenuOptions.iconSortDescCommand || 'mdi mdi-sort-descending',
                            titleKey: `${translationPrefix}SORT_DESCENDING`,
                            command: 'sort-desc',
                            positionOrder: 51,
                            action: (e, args) => this.sortColumn(e, args, false),
                        }, headerMenuOptions.hideCommands, columnHeaderMenuItems);
                        // add a divider (separator) between the top sort commands and the other clear commands
                        if (!columnHeaderMenuItems.some((item) => item !== 'divider' && item.positionOrder === 52)) {
                            columnHeaderMenuItems.push({ divider: true, command: 'divider-2', positionOrder: 52 });
                        }
                        if (!headerMenuOptions.hideClearSortCommand) {
                            this.addMissingCommandOrAction({
                                _orgTitle: commandLabels?.clearSortCommand || '',
                                iconCssClass: headerMenuOptions.iconClearSortCommand || 'mdi mdi-sort-variant-off',
                                titleKey: `${translationPrefix}REMOVE_SORT`,
                                command: 'clear-sort',
                                positionOrder: 58,
                                action: (e, args) => this.clearColumnSort(e, args),
                            }, headerMenuOptions.hideCommands, columnHeaderMenuItems);
                        }
                    }
                    // Filter Shortcuts via sub-menus
                    const cmdShortcutName = 'filter-shortcuts-root-menu';
                    if (columnDef.filter?.filterShortcuts &&
                        !columnHeaderMenuItems.some((item) => item !== 'divider' && 'command' in item && item.command === cmdShortcutName)) {
                        const shortcutSubItems = [];
                        columnDef.filter.filterShortcuts.forEach((fs) => {
                            // use the Title name as the command key in kebab cas
                            const command = fs.title ? toKebabCase(fs.title) : (fs.titleKey || '').toLowerCase().replaceAll('_', '-');
                            shortcutSubItems.push({
                                ...fs,
                                command,
                                action: (_e, args) => {
                                    // get associated Column Filter instance and use its `setValues()` method to update the filter with provided `searchTerms`
                                    const filterRef = this.filterService.getFiltersMetadata().find((f) => f.columnDef.id === args.column.id);
                                    filterRef?.setValues(fs.searchTerms, fs.operator, true);
                                },
                            });
                        });
                        const filterShortcutsPositionOrder = headerMenuOptions.filterShortcutsPositionOrder ?? 55;
                        columnHeaderMenuItems.push({
                            _orgTitle: commandLabels?.filterShortcutsCommand || '',
                            iconCssClass: headerMenuOptions.iconFilterShortcutSubMenu || 'mdi mdi-filter-outline',
                            titleKey: `${translationPrefix}FILTER_SHORTCUTS`,
                            command: cmdShortcutName,
                            positionOrder: filterShortcutsPositionOrder,
                            commandItems: shortcutSubItems,
                        });
                        // add a divider (separator) between the top freeze columns commands and the rest of the commands
                        if (hasFrozenOrResizeCommand &&
                            !columnHeaderMenuItems.some((item) => item !== 'divider' && item.positionOrder === filterShortcutsPositionOrder + 1)) {
                            columnHeaderMenuItems.push({ divider: true, command: 'divider-3', positionOrder: filterShortcutsPositionOrder + 1 });
                        }
                    }
                    // Filtering Commands
                    if (gridOptions.enableFiltering &&
                        columnDef.filterable &&
                        headerMenuOptions &&
                        !headerMenuOptions.hideFilterCommand &&
                        !headerMenuOptions.hideCommands?.includes('clear-filter')) {
                        if (!headerMenuOptions.hideClearFilterCommand) {
                            this.addMissingCommandOrAction({
                                _orgTitle: commandLabels?.clearFilterCommand || '',
                                iconCssClass: headerMenuOptions.iconClearFilterCommand || 'mdi mdi-filter-remove-outline',
                                titleKey: `${translationPrefix}REMOVE_FILTER`,
                                command: 'clear-filter',
                                positionOrder: 57,
                                action: (e, args) => {
                                    this.clearColumnFilter(e, args);
                                },
                            }, headerMenuOptions.hideCommands, columnHeaderMenuItems);
                        }
                    }
                    // Hide Column Command
                    if (headerMenuOptions && !headerMenuOptions.hideColumnHideCommand && !headerMenuOptions.hideCommands?.includes('hide-column')) {
                        this.addMissingCommandOrAction({
                            _orgTitle: commandLabels?.hideColumnCommand || '',
                            iconCssClass: headerMenuOptions.iconColumnHideCommand || 'mdi mdi-close',
                            titleKey: `${translationPrefix}HIDE_COLUMN`,
                            command: 'hide-column',
                            positionOrder: 59,
                            action: (_e, args) => {
                                this.hideColumn(args.column);
                                if (this.sharedService.gridOptions?.enableAutoSizeColumns) {
                                    this.grid.autosizeColumns();
                                }
                            },
                        }, headerMenuOptions.hideCommands, columnHeaderMenuItems);
                    }
                    this.extensionUtility.translateMenuItemsFromTitleKey(columnHeaderMenuItems);
                    this.extensionUtility.sortItems(columnHeaderMenuItems, 'positionOrder');
                }
            });
        }
        return headerMenuOptions;
    }
    /** Clear the Filter on the current column (if it's actually filtered) */
    clearColumnFilter(event, args) {
        if (args?.column) {
            this.filterService.clearFilterByColumnId(event, args.column.id);
        }
    }
    /** Clear the Sort on the current column (if it's actually sorted) */
    clearColumnSort(event, args) {
        if (args?.column && this.sharedService) {
            this.sortService.clearSortByColumnId(event, args.column.id);
        }
    }
    removeCommandWhenFound(columnHeaderMenuItems, command) {
        const commandIdx = columnHeaderMenuItems.findIndex((item) => item !== 'divider' && item?.command === command);
        if (commandIdx >= 0) {
            columnHeaderMenuItems.splice(commandIdx, 1);
        }
    }
    /** freeze or unfreeze columns command */
    freezeOrUnfreezeColumns(column, command) {
        const columnPosition = this.grid.getVisibleColumns().findIndex((col) => col.id === column.id);
        const newGridOptions = {
            frozenColumn: command === 'unfreeze-columns' ? -1 : columnPosition,
            enableMouseWheelScrollHandler: true,
        };
        // make sure column freeze is allowed before applying the change
        if (this.grid.validateColumnFreezeWidth(newGridOptions.frozenColumn)) {
            this.grid.setOptions(newGridOptions, false, true); // suppress the setColumns (3rd argument) since we'll do that ourselves
            // remove the last freeze/unfreeze command called from Header Menu since it will be replaced by the other one when reopening the menu
            const columnHeaderMenuItems = column?.header?.menu?.commandItems ?? [];
            this.removeCommandWhenFound(columnHeaderMenuItems, command);
            this.sharedService.gridOptions.frozenColumn = newGridOptions.frozenColumn;
            this.sharedService.gridOptions.enableMouseWheelScrollHandler = newGridOptions.enableMouseWheelScrollHandler;
            this.sharedService.frozenVisibleColumnId = this.grid.getFrozenColumnId();
            this.grid.updateColumns();
            this.recreateHeaderMenu(this.grid.getColumns());
            // we also need to autosize columns if the option is enabled
            const gridOptions = this.grid.getOptions();
            if (gridOptions.enableAutoSizeColumns) {
                this.grid.autosizeColumns();
            }
        }
    }
    createParentMenu(e, columnDef, menu) {
        // let the user modify the menu or cancel altogether,
        // or provide alternative menu implementation.
        const callbackArgs = {
            grid: this.grid,
            column: columnDef,
            menu,
        };
        // execute optional callback method defined by the user, if it returns false then we won't go further and not open the grid menu
        if (typeof e.stopPropagation === 'function') {
            this.pubSubService.publish('onHeaderMenuBeforeMenuShow', callbackArgs);
            if (typeof this.addonOptions?.onBeforeMenuShow === 'function' && this.addonOptions?.onBeforeMenuShow(e, callbackArgs) === false) {
                return;
            }
        }
        // Track the element that triggered the menu (for focus restoration)
        const triggerElement = e.target;
        this.setMenuTriggerElement(triggerElement);
        // create 1st parent menu container & reposition it
        this._menuElm = this.createCommandMenu(triggerElement, menu.commandItems, columnDef);
        this.grid.getContainerNode()?.appendChild(this._menuElm);
        this.repositionMenu(e, this._menuElm, undefined, this.addonOptions);
        // Focus the first menu item for keyboard accessibility (do this BEFORE binding keyboard handler)
        this.focusFirstMenuItem(this._menuElm);
        // Use base class method to wire up keyboard navigation
        this.wireMenuKeyboardNavigation(this._menuElm);
        // execute optional callback method defined by the user
        this.pubSubService.publish('onHeaderMenuAfterMenuShow', callbackArgs);
        if (typeof this.addonOptions?.onAfterMenuShow === 'function' && this.addonOptions?.onAfterMenuShow(e, callbackArgs) === false) {
            return;
        }
        // Stop propagation so that it doesn't register as a header click event.
        e.preventDefault();
        e.stopPropagation();
    }
    /** Create the menu or sub-menu(s) but without the column picker which is a separate single process */
    createCommandMenu(triggeredByElm, commandItems, columnDef, level = 0, item) {
        // Always use the triggering item's command (whitespace removed) as the sub-menu parent id for every level
        const subMenuCommand = item?.command;
        const subMenuId = subMenuCommand ? subMenuCommand.replace(/\s/g, '') : '';
        const menuClasses = `${this.menuCssClass} slick-menu-level-${level} ${this.gridUid}`;
        const bodyMenuElm = document.body.querySelector(`.${this.menuCssClass}.slick-menu-level-${level}${this.gridUidSelector}`);
        // return menu/sub-menu if it's already opened unless we are on different sub-menu tree if so close them all
        if (bodyMenuElm) {
            if (bodyMenuElm.dataset.subMenuParent === subMenuId) {
                return bodyMenuElm;
            }
            this.disposeSubMenus();
        }
        const menuElm = createDomElement('div', {
            ariaExpanded: 'true',
            ariaLabel: level > 1 ? 'SubMenu' : 'Header Menu',
            role: 'menu',
            className: menuClasses,
            style: { minWidth: `${this.addonOptions.minWidth}px` },
        });
        if (level > 0) {
            menuElm.classList.add('slick-submenu');
            if (subMenuId) {
                menuElm.dataset.subMenuParent = subMenuId;
            }
            // add dark mode CSS class when enabled
            if (this.gridOptions?.darkMode) {
                menuElm.classList.add('slick-dark-mode');
            }
        }
        const commandMenuElm = createDomElement('div', { className: `${this._menuCssPrefix}-command-list`, role: 'menu' }, menuElm);
        const callbackArgs = {
            grid: this.grid,
            column: columnDef,
            level,
            menu: { commandItems },
        };
        // when creating sub-menu also add its sub-menu title when exists
        if (item && level > 0) {
            this.addSubMenuTitleWhenExists(item, commandMenuElm); // add sub-menu title when exists
        }
        this.populateCommandOrOptionItems('command', this.addonOptions, commandMenuElm, commandItems, callbackArgs, triggeredByElm, this.handleMenuItemCommandClick, this.handleMenuItemMouseOver);
        // increment level for possible next sub-menus if exists
        level++;
        return menuElm;
    }
    /**
     * Reset all the internal Menu options which have text to translate
     * @param header menu object
     */
    resetHeaderMenuTranslations(columns) {
        columns.forEach((columnDef) => {
            if (columnDef?.header?.menu?.commandItems && !columnDef.excludeFromHeaderMenu) {
                const columnHeaderMenuItems = columnDef.header.menu.commandItems || [];
                this.extensionUtility.translateMenuItemsFromTitleKey(columnHeaderMenuItems);
            }
        });
    }
    /** Sort the current column */
    sortColumn(event, args, isSortingAsc = true) {
        if (args?.column) {
            // get previously sorted columns
            const columnDef = args.column;
            // 1- get the sort columns without the current column, in the case of a single sort that would equal to an empty array
            // prettier-ignore
            const tmpSortedColumns = !this.sharedService.gridOptions.multiColumnSort ? [] : this.sortService.getCurrentColumnSorts(columnDef.id + '');
            let emitterType = 'local';
            // 2- add to the column array, the new sorted column by the header menu
            tmpSortedColumns.push({ columnId: columnDef.id, sortCol: columnDef, sortAsc: isSortingAsc });
            if (this.sharedService.gridOptions.backendServiceApi) {
                this.sortService.onBackendSortChanged(event, {
                    multiColumnSort: true,
                    sortCols: tmpSortedColumns,
                    grid: this.grid,
                });
                emitterType = 'remote';
            }
            else if (this.sharedService.dataView) {
                this.sortService.onLocalSortChanged(this.grid, tmpSortedColumns);
                emitterType = 'local';
            }
            else {
                // when using customDataView, we will simply send it as a onSort event with notify
                args.grid.onSort.notify(tmpSortedColumns);
            }
            // update the sharedService.slickGrid sortColumns array which will at the same add the visual sort icon(s) on the UI
            const newSortColumns = tmpSortedColumns.map((col) => {
                return {
                    columnId: col?.sortCol?.id ?? '',
                    sortAsc: col?.sortAsc ?? true,
                };
            });
            // add sort icon in UI
            this.grid.setSortColumns(newSortColumns);
            // if we have an emitter type set, we will emit a sort changed
            // for the Grid State Service to see the change.
            // We also need to pass current sorters changed to the emitSortChanged method
            if (emitterType) {
                const currentLocalSorters = [];
                newSortColumns.forEach((sortCol) => {
                    currentLocalSorters.push({
                        columnId: `${sortCol.columnId}`,
                        direction: sortCol.sortAsc ? 'ASC' : 'DESC',
                    });
                });
                this.sortService.emitSortChanged(emitterType, currentLocalSorters);
            }
        }
    }
    recreateHeaderMenu(newColumns) {
        this.sharedService.gridOptions.headerMenu = this.addHeaderMenuCustomCommands(newColumns);
    }
}
//# sourceMappingURL=slickHeaderMenu.js.map