"use strict";

exports.__esModule = true;
require("core-js/modules/es.error.cause.js");
require("core-js/modules/es.array.push.js");
var _base = require("../base");
var _pluginHooks = _interopRequireDefault(require("../../pluginHooks"));
var _freezeColumn = _interopRequireDefault(require("./contextMenuItem/freezeColumn"));
var _unfreezeColumn = _interopRequireDefault(require("./contextMenuItem/unfreezeColumn"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); }
function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); }
function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } }
function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); }
function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; }
function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; }
function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); }
function _classApplyDescriptorSet(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 _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; }
_pluginHooks.default.getSingleton().register('beforeColumnFreeze');
_pluginHooks.default.getSingleton().register('afterColumnFreeze');
_pluginHooks.default.getSingleton().register('beforeColumnUnfreeze');
_pluginHooks.default.getSingleton().register('afterColumnUnfreeze');
const PLUGIN_KEY = 'manualColumnFreeze';
exports.PLUGIN_KEY = PLUGIN_KEY;
const PLUGIN_PRIORITY = 110;

/* eslint-disable jsdoc/require-description-complete-sentence */

/**
 * @plugin ManualColumnFreeze
 * @class ManualColumnFreeze
 *
 * @description
 * This plugin allows to manually "freeze" and "unfreeze" a column using an entry in the Context Menu or using API.
 * You can turn it on by setting a {@link Options#manualColumnFreeze} property to `true`.
 *
 * @example
 * ```js
 * // Enables the plugin
 * manualColumnFreeze: true,
 * ```
 */
exports.PLUGIN_PRIORITY = PLUGIN_PRIORITY;
var _afterFirstUse = /*#__PURE__*/new WeakMap();
var _addContextMenuEntry = /*#__PURE__*/new WeakSet();
var _onBeforeColumnMove = /*#__PURE__*/new WeakSet();
class ManualColumnFreeze extends _base.BasePlugin {
  constructor() {
    super(...arguments);
    /**
     * Prevents moving the columns from/to fixed area.
     *
     * @private
     * @param {Array} columns Array of visual column indexes to be moved.
     * @param {number} finalIndex Visual column index, being a start index for the moved columns. Points to where the elements will be placed after the moving action.
     * @returns {boolean|undefined}
     */
    _classPrivateMethodInitSpec(this, _onBeforeColumnMove);
    /**
     * Adds the manualColumnFreeze context menu entries.
     *
     * @private
     * @param {object} options Context menu options.
     */
    _classPrivateMethodInitSpec(this, _addContextMenuEntry);
    /**
     * Determines when the moving operation is allowed.
     *
     * @type {boolean}
     */
    _classPrivateFieldInitSpec(this, _afterFirstUse, {
      writable: true,
      value: false
    });
  }
  static get PLUGIN_KEY() {
    return PLUGIN_KEY;
  }
  static get PLUGIN_PRIORITY() {
    return PLUGIN_PRIORITY;
  }
  /**
   * 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 ManualColumnFreeze#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;
    }
    this.addHook('afterContextMenuDefaultOptions', options => _classPrivateMethodGet(this, _addContextMenuEntry, _addContextMenuEntry2).call(this, options));
    this.addHook('beforeColumnMove', (columns, finalIndex) => _classPrivateMethodGet(this, _onBeforeColumnMove, _onBeforeColumnMove2).call(this, columns, finalIndex));
    super.enablePlugin();
  }

  /**
   * Disables the plugin functionality for this Handsontable instance.
   */
  disablePlugin() {
    _classPrivateFieldSet(this, _afterFirstUse, false);
    super.disablePlugin();
  }

  /**
   * Updates the plugin's state.
   *
   * This method is executed when [`updateSettings()`](@/api/core.md#updatesettings) is invoked with any of the following configuration options:
   *  - [`manualColumnFreeze`](@/api/options.md#manualcolumnfreeze)
   */
  updatePlugin() {
    this.disablePlugin();
    this.enablePlugin();
    super.updatePlugin();
  }

  /**
   * Freezes the specified column (adds it to fixed columns).
   *
   * `freezeColumn()` doesn't re-render the table,
   * so you need to call the `render()` method afterward.
   *
   * @param {number} column Visual column index.
   */
  freezeColumn(column) {
    const settings = this.hot.getSettings();
    // columns are already fixed (frozen)
    const freezePerformed = settings.fixedColumnsStart < this.hot.countCols() && column > settings.fixedColumnsStart - 1;
    if (!_classPrivateFieldGet(this, _afterFirstUse)) {
      _classPrivateFieldSet(this, _afterFirstUse, true);
    }
    const beforeColumnFreezeHook = this.hot.runHooks('beforeColumnFreeze', column, freezePerformed);
    if (beforeColumnFreezeHook === false) {
      return;
    }
    if (freezePerformed) {
      this.hot.columnIndexMapper.moveIndexes(column, settings.fixedColumnsStart);

      // Since 12.0.0, the "fixedColumnsLeft" is replaced with the "fixedColumnsStart" option.
      // However, keeping the old name still in effect. When both option names are used together,
      // the error is thrown. To prevent that, the plugin needs to modify the original option key
      // to bypass the validation.
      settings._fixedColumnsStart += 1;
    }
    this.hot.runHooks('afterColumnFreeze', column, freezePerformed);
  }

  /**
   * Unfreezes the given column (remove it from fixed columns and bring to it's previous position).
   *
   * @param {number} column Visual column index.
   */
  unfreezeColumn(column) {
    const settings = this.hot.getSettings();
    // columns are not fixed (not frozen)
    const unfreezePerformed = settings.fixedColumnsStart > 0 && column <= settings.fixedColumnsStart - 1;
    if (!_classPrivateFieldGet(this, _afterFirstUse)) {
      _classPrivateFieldSet(this, _afterFirstUse, true);
    }
    const beforeColumnUnfreezeHook = this.hot.runHooks('beforeColumnUnfreeze', column, unfreezePerformed);
    if (beforeColumnUnfreezeHook === false) {
      return;
    }
    if (unfreezePerformed) {
      // Since 12.0.0, the "fixedColumnsLeft" is replaced with the "fixedColumnsStart" option.
      // However, keeping the old name still in effect. When both option names are used together,
      // the error is thrown. To prevent that, the plugin needs to modify the original option key
      // to bypass the validation.
      settings._fixedColumnsStart -= 1;
      this.hot.columnIndexMapper.moveIndexes(column, settings.fixedColumnsStart);
    }
    this.hot.runHooks('afterColumnUnfreeze', column, unfreezePerformed);
  }
}
exports.ManualColumnFreeze = ManualColumnFreeze;
function _addContextMenuEntry2(options) {
  options.items.push({
    name: '---------'
  }, (0, _freezeColumn.default)(this), (0, _unfreezeColumn.default)(this));
}
function _onBeforeColumnMove2(columns, finalIndex) {
  if (_classPrivateFieldGet(this, _afterFirstUse)) {
    const freezeLine = this.hot.getSettings().fixedColumnsStart;

    // Moving any column before the "freeze line" isn't possible.
    if (finalIndex < freezeLine) {
      return false;
    }

    // Moving frozen column isn't possible.
    if (columns.some(column => column < freezeLine)) {
      return false;
    }
  }
}