"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
function _export(target, all) {
    for(var name in all)Object.defineProperty(target, name, {
        enumerable: true,
        get: Object.getOwnPropertyDescriptor(all, name).get
    });
}
_export(exports, {
    get HiddenRows () {
        return HiddenRows;
    },
    get PLUGIN_KEY () {
        return PLUGIN_KEY;
    },
    get PLUGIN_PRIORITY () {
        return PLUGIN_PRIORITY;
    }
});
const _base = require("../base");
const _element = require("../../helpers/dom/element");
const _number = require("../../helpers/number");
const _array = require("../../helpers/array");
const _predefinedItems = require("../contextMenu/predefinedItems");
const _hooks = require("../../core/hooks");
const _hideRow = /*#__PURE__*/ _interop_require_default(require("./contextMenuItem/hideRow"));
const _showRow = /*#__PURE__*/ _interop_require_default(require("./contextMenuItem/showRow"));
const _translations = require("../../translations");
function _check_private_redeclaration(obj, privateCollection) {
    if (privateCollection.has(obj)) {
        throw new TypeError("Cannot initialize the same private elements twice on an object");
    }
}
function _class_apply_descriptor_get(receiver, descriptor) {
    if (descriptor.get) {
        return descriptor.get.call(receiver);
    }
    return descriptor.value;
}
function _class_apply_descriptor_set(receiver, descriptor, value) {
    if (descriptor.set) {
        descriptor.set.call(receiver, value);
    } else {
        if (!descriptor.writable) {
            throw new TypeError("attempted to set read only private field");
        }
        descriptor.value = value;
    }
}
function _class_extract_field_descriptor(receiver, privateMap, action) {
    if (!privateMap.has(receiver)) {
        throw new TypeError("attempted to " + action + " private field on non-instance");
    }
    return privateMap.get(receiver);
}
function _class_private_field_get(receiver, privateMap) {
    var descriptor = _class_extract_field_descriptor(receiver, privateMap, "get");
    return _class_apply_descriptor_get(receiver, descriptor);
}
function _class_private_field_init(obj, privateMap, value) {
    _check_private_redeclaration(obj, privateMap);
    privateMap.set(obj, value);
}
function _class_private_field_set(receiver, privateMap, value) {
    var descriptor = _class_extract_field_descriptor(receiver, privateMap, "set");
    _class_apply_descriptor_set(receiver, descriptor, value);
    return value;
}
function _class_private_method_get(receiver, privateSet, fn) {
    if (!privateSet.has(receiver)) {
        throw new TypeError("attempted to get private field on non-instance");
    }
    return fn;
}
function _class_private_method_init(obj, privateSet) {
    _check_private_redeclaration(obj, privateSet);
    privateSet.add(obj);
}
function _interop_require_default(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    };
}
_hooks.Hooks.getSingleton().register('beforeHideRows');
_hooks.Hooks.getSingleton().register('afterHideRows');
_hooks.Hooks.getSingleton().register('beforeUnhideRows');
_hooks.Hooks.getSingleton().register('afterUnhideRows');
const PLUGIN_KEY = 'hiddenRows';
const PLUGIN_PRIORITY = 320;
var /**
   * Map of hidden rows by the plugin.
   *
   * @private
   * @type {HidingMap|null}
   */ _hiddenRowsMap = /*#__PURE__*/ new WeakMap(), /**
   * Adds the additional row height for the hidden row indicators.
   *
   * @param {number|undefined} height Row height.
   * @param {number} row Visual row index.
   * @returns {number}
   */ _onModifyRowHeight = /*#__PURE__*/ new WeakSet(), /**
   * Sets the copy-related cell meta.
   *
   * @param {number} row Visual row index.
   * @param {number} column Visual column index.
   * @param {object} cellProperties Object containing the cell properties.
   */ _onAfterGetCellMeta = /*#__PURE__*/ new WeakSet(), /**
   * Modifies the copyable range, accordingly to the provided config.
   *
   * @param {Array} ranges An array of objects defining copyable cells.
   * @returns {Array}
   */ _onModifyCopyableRange = /*#__PURE__*/ new WeakSet(), /**
   * Adds the needed classes to the headers.
   *
   * @param {number} row Visual row index.
   * @param {HTMLElement} TH Header's TH element.
   */ _onAfterGetRowHeader = /*#__PURE__*/ new WeakSet(), /**
   * Add Show-hide rows to context menu.
   *
   * @param {object} options An array of objects containing information about the pre-defined Context Menu items.
   */ _onAfterContextMenuDefaultOptions = /*#__PURE__*/ new WeakSet(), /**
   * On map initialized hook callback.
   */ _onMapInit = /*#__PURE__*/ new WeakSet();
class HiddenRows extends _base.BasePlugin {
    static get PLUGIN_KEY() {
        return PLUGIN_KEY;
    }
    static get PLUGIN_PRIORITY() {
        return PLUGIN_PRIORITY;
    }
    static get DEFAULT_SETTINGS() {
        return {
            copyPasteEnabled: true,
            indicators: false,
            rows: []
        };
    }
    /**
   * Checks if the plugin is enabled in the handsontable settings. This method is executed in {@link Hooks#beforeInit}
   * hook and if it returns `true` then the {@link HiddenRows#enablePlugin} method is called.
   *
   * @returns {boolean}
   */ isEnabled() {
        return !!this.hot.getSettings()[PLUGIN_KEY];
    }
    /**
   * Enables the plugin functionality for this Handsontable instance.
   */ enablePlugin() {
        if (this.enabled) {
            return;
        }
        _class_private_field_set(this, _hiddenRowsMap, new _translations.HidingMap());
        _class_private_field_get(this, _hiddenRowsMap).addLocalHook('init', ()=>_class_private_method_get(this, _onMapInit, onMapInit).call(this));
        this.hot.rowIndexMapper.registerMap(this.pluginName, _class_private_field_get(this, _hiddenRowsMap));
        this.addHook('afterContextMenuDefaultOptions', (...args)=>_class_private_method_get(this, _onAfterContextMenuDefaultOptions, onAfterContextMenuDefaultOptions).call(this, ...args));
        this.addHook('afterGetCellMeta', (row, col, cellProperties)=>_class_private_method_get(this, _onAfterGetCellMeta, onAfterGetCellMeta).call(this, row, col, cellProperties));
        this.addHook('modifyRowHeight', (height, row)=>_class_private_method_get(this, _onModifyRowHeight, onModifyRowHeight).call(this, height, row));
        this.addHook('afterGetRowHeader', (...args)=>_class_private_method_get(this, _onAfterGetRowHeader, onAfterGetRowHeader).call(this, ...args));
        this.addHook('modifyCopyableRange', (ranges)=>_class_private_method_get(this, _onModifyCopyableRange, onModifyCopyableRange).call(this, ranges));
        super.enablePlugin();
    }
    /**
   * Updates the plugin's state.
   *
   * This method is executed when [`updateSettings()`](@/api/core.md#updatesettings) is invoked with any of the following configuration options:
   *  - [`hiddenRows`](@/api/options.md#hiddenrows)
   */ updatePlugin() {
        this.disablePlugin();
        this.enablePlugin();
        super.updatePlugin();
    }
    /**
   * Disables the plugin functionality for this Handsontable instance.
   */ disablePlugin() {
        super.disablePlugin();
        this.hot.rowIndexMapper.unregisterMap(this.pluginName);
        this.resetCellsMeta();
    }
    /**
   * Shows the rows provided in the array.
   *
   * @param {number[]} rows Array of visual row indexes.
   */ showRows(rows) {
        const currentHideConfig = this.getHiddenRows();
        const isValidConfig = this.isValidConfig(rows);
        let destinationHideConfig = currentHideConfig;
        const hidingMapValues = _class_private_field_get(this, _hiddenRowsMap).getValues().slice();
        const isAnyRowShowed = rows.length > 0;
        if (isValidConfig && isAnyRowShowed) {
            const physicalRows = rows.map((visualRow)=>this.hot.toPhysicalRow(visualRow));
            // Preparing new values for hiding map.
            (0, _array.arrayEach)(physicalRows, (physicalRow)=>{
                hidingMapValues[physicalRow] = false;
            });
            // Preparing new hiding config.
            destinationHideConfig = (0, _array.arrayReduce)(hidingMapValues, (hiddenIndexes, isHidden, physicalIndex)=>{
                if (isHidden) {
                    hiddenIndexes.push(this.hot.toVisualRow(physicalIndex));
                }
                return hiddenIndexes;
            }, []);
        }
        const continueHiding = this.hot.runHooks('beforeUnhideRows', currentHideConfig, destinationHideConfig, isValidConfig && isAnyRowShowed);
        if (continueHiding === false) {
            return;
        }
        if (isValidConfig && isAnyRowShowed) {
            _class_private_field_get(this, _hiddenRowsMap).setValues(hidingMapValues);
        }
        this.hot.runHooks('afterUnhideRows', currentHideConfig, destinationHideConfig, isValidConfig && isAnyRowShowed, isValidConfig && destinationHideConfig.length < currentHideConfig.length);
    }
    /**
   * Shows the row provided as row index (counting from 0).
   *
   * @param {...number} row Visual row index.
   */ showRow(...row) {
        this.showRows(row);
    }
    /**
   * Hides the rows provided in the array.
   *
   * @param {number[]} rows Array of visual row indexes.
   */ hideRows(rows) {
        const currentHideConfig = this.getHiddenRows();
        const isConfigValid = this.isValidConfig(rows);
        let destinationHideConfig = currentHideConfig;
        if (isConfigValid) {
            destinationHideConfig = Array.from(new Set(currentHideConfig.concat(rows)));
        }
        const continueHiding = this.hot.runHooks('beforeHideRows', currentHideConfig, destinationHideConfig, isConfigValid);
        if (continueHiding === false) {
            return;
        }
        if (isConfigValid) {
            this.hot.batchExecution(()=>{
                (0, _array.arrayEach)(rows, (visualRow)=>{
                    _class_private_field_get(this, _hiddenRowsMap).setValueAtIndex(this.hot.toPhysicalRow(visualRow), true);
                });
            }, true);
        }
        this.hot.runHooks('afterHideRows', currentHideConfig, destinationHideConfig, isConfigValid, isConfigValid && destinationHideConfig.length > currentHideConfig.length);
    }
    /**
   * Hides the row provided as row index (counting from 0).
   *
   * @param {...number} row Visual row index.
   */ hideRow(...row) {
        this.hideRows(row);
    }
    /**
   * Returns an array of visual indexes of hidden rows.
   *
   * @returns {number[]}
   */ getHiddenRows() {
        return (0, _array.arrayMap)(_class_private_field_get(this, _hiddenRowsMap).getHiddenIndexes(), (physicalRowIndex)=>{
            return this.hot.toVisualRow(physicalRowIndex);
        });
    }
    /**
   * Checks if the provided row is hidden.
   *
   * @param {number} row Visual row index.
   * @returns {boolean}
   */ isHidden(row) {
        return _class_private_field_get(this, _hiddenRowsMap).getValueAtIndex(this.hot.toPhysicalRow(row)) || false;
    }
    /**
   * Checks whether all of the provided row indexes are within the bounds of the table.
   *
   * @param {Array} hiddenRows List of hidden visual row indexes.
   * @returns {boolean}
   */ isValidConfig(hiddenRows) {
        const nrOfRows = this.hot.countRows();
        if (Array.isArray(hiddenRows) && hiddenRows.length > 0) {
            return hiddenRows.every((visualRow)=>Number.isInteger(visualRow) && visualRow >= 0 && visualRow < nrOfRows);
        }
        return false;
    }
    /**
   * Resets all rendered cells meta.
   *
   * @private
   */ resetCellsMeta() {
        (0, _array.arrayEach)(this.hot.getCellsMeta(), (meta)=>{
            meta.skipRowOnPaste = false;
        });
    }
    /**
   * Destroys the plugin instance.
   */ destroy() {
        _class_private_field_set(this, _hiddenRowsMap, null);
        super.destroy();
    }
    constructor(...args){
        super(...args), _class_private_method_init(this, _onModifyRowHeight), _class_private_method_init(this, _onAfterGetCellMeta), _class_private_method_init(this, _onModifyCopyableRange), _class_private_method_init(this, _onAfterGetRowHeader), _class_private_method_init(this, _onAfterContextMenuDefaultOptions), _class_private_method_init(this, _onMapInit), _class_private_field_init(this, _hiddenRowsMap, {
            writable: true,
            value: void 0
        }), _class_private_field_set(this, _hiddenRowsMap, null);
    }
}
function onModifyRowHeight(height, row) {
    // Hook is triggered internally only for the visible rows. Conditional will be handled for the API
    // calls of the `getRowHeight` function on not visible indexes.
    if (this.isHidden(row)) {
        return 0;
    }
    return height;
}
function onAfterGetCellMeta(row, column, cellProperties) {
    if (this.getSetting('copyPasteEnabled') === false && this.isHidden(row)) {
        // Cell property handled by the `Autofill` and the `CopyPaste` plugins.
        cellProperties.skipRowOnPaste = true;
    }
    if (this.isHidden(row - 1)) {
        cellProperties.className = cellProperties.className || '';
        if (cellProperties.className.indexOf('afterHiddenRow') === -1) {
            cellProperties.className += ' afterHiddenRow';
        }
    } else if (cellProperties.className) {
        const classArr = cellProperties.className.split(' ');
        if (classArr.length > 0) {
            const containAfterHiddenRow = classArr.indexOf('afterHiddenRow');
            if (containAfterHiddenRow > -1) {
                classArr.splice(containAfterHiddenRow, 1);
            }
            cellProperties.className = classArr.join(' ');
        }
    }
}
function onModifyCopyableRange(ranges) {
    // Ranges shouldn't be modified when `copyPasteEnabled` option is set to `true` (by default).
    if (this.getSetting('copyPasteEnabled')) {
        return ranges;
    }
    const newRanges = [];
    const pushRange = (startRow, endRow, startCol, endCol)=>{
        newRanges.push({
            startRow,
            endRow,
            startCol,
            endCol
        });
    };
    (0, _array.arrayEach)(ranges, (range)=>{
        let isHidden = true;
        let rangeStart = 0;
        (0, _number.rangeEach)(range.startRow, range.endRow, (visualRow)=>{
            if (this.isHidden(visualRow)) {
                if (!isHidden) {
                    pushRange(rangeStart, visualRow - 1, range.startCol, range.endCol);
                }
                isHidden = true;
            } else {
                if (isHidden) {
                    rangeStart = visualRow;
                }
                if (visualRow === range.endRow) {
                    pushRange(rangeStart, visualRow, range.startCol, range.endCol);
                }
                isHidden = false;
            }
        });
    });
    return newRanges;
}
function onAfterGetRowHeader(row, TH) {
    if (!this.getSetting('indicators') || row < 0) {
        return;
    }
    const classList = [];
    if (row >= 1 && this.isHidden(row - 1)) {
        classList.push('afterHiddenRow');
    }
    if (row < this.hot.countRows() - 1 && this.isHidden(row + 1)) {
        classList.push('beforeHiddenRow');
    }
    (0, _element.addClass)(TH, classList);
}
function onAfterContextMenuDefaultOptions(options) {
    options.items.push({
        name: _predefinedItems.SEPARATOR
    }, (0, _hideRow.default)(this), (0, _showRow.default)(this));
}
function onMapInit() {
    const rows = this.getSetting('rows');
    if (Array.isArray(rows)) {
        this.hideRows(rows);
    }
}
