"use strict";

exports.__esModule = true;
require("core-js/modules/es.array.push.js");
require("core-js/modules/es.error.cause.js");
var _base = require("../base");
var _pluginHooks = _interopRequireDefault(require("../../pluginHooks"));
var _array = require("../../helpers/array");
var _element = require("../../helpers/dom/element");
var _event = require("../../helpers/dom/event");
var _number = require("../../helpers/number");
var _backlight2 = _interopRequireDefault(require("./ui/backlight"));
var _guideline2 = _interopRequireDefault(require("./ui/guideline"));
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 _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; }
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 _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); }
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 _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.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('beforeColumnMove');
_pluginHooks.default.getSingleton().register('afterColumnMove');
const PLUGIN_KEY = 'manualColumnMove';
exports.PLUGIN_KEY = PLUGIN_KEY;
const PLUGIN_PRIORITY = 120;
exports.PLUGIN_PRIORITY = PLUGIN_PRIORITY;
const CSS_PLUGIN = 'ht__manualColumnMove';
const CSS_SHOW_UI = 'show-ui';
const CSS_ON_MOVING = 'on-moving--columns';
const CSS_AFTER_SELECTION = 'after-selection--columns';

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

/**
 * @plugin ManualColumnMove
 * @class ManualColumnMove
 *
 * @description
 * This plugin allows to change columns order. To make columns order persistent the {@link Options#persistentState}
 * plugin should be enabled.
 *
 * API:
 * - `moveColumn` - move single column to the new position.
 * - `moveColumns` - move many columns (as an array of indexes) to the new position.
 * - `dragColumn` - drag single column to the new position.
 * - `dragColumns` - drag many columns (as an array of indexes) to the new position.
 *
 * [Documentation](@/guides/columns/column-moving.md) explain differences between drag and move actions.
 * Please keep in mind that if you want apply visual changes,
 * you have to call manually the `render` method on the instance of Handsontable.
 *
 * The plugin creates additional components to make moving possibly using user interface:
 * - backlight - highlight of selected columns.
 * - guideline - line which shows where columns has been moved.
 *
 * @class ManualColumnMove
 * @plugin ManualColumnMove
 */
var _backlight = /*#__PURE__*/new WeakMap();
var _guideline = /*#__PURE__*/new WeakMap();
var _columnsToMove = /*#__PURE__*/new WeakMap();
var _countCols = /*#__PURE__*/new WeakMap();
var _pressed = /*#__PURE__*/new WeakMap();
var _target = /*#__PURE__*/new WeakMap();
var _cachedDropIndex = /*#__PURE__*/new WeakMap();
var _hoveredColumn = /*#__PURE__*/new WeakMap();
var _rootElementOffset = /*#__PURE__*/new WeakMap();
var _hasRowHeaders = /*#__PURE__*/new WeakMap();
var _fixedColumnsStart = /*#__PURE__*/new WeakMap();
var _onBeforeOnCellMouseDown = /*#__PURE__*/new WeakSet();
var _onMouseMove = /*#__PURE__*/new WeakSet();
var _onBeforeOnCellMouseOver = /*#__PURE__*/new WeakSet();
var _onMouseUp = /*#__PURE__*/new WeakSet();
var _onAfterScrollVertically = /*#__PURE__*/new WeakSet();
var _onAfterLoadData = /*#__PURE__*/new WeakSet();
class ManualColumnMove extends _base.BasePlugin {
  constructor() {
    super(...arguments);
    /**
     * Callback for the `afterLoadData` hook.
     *
     * @private
     */
    _classPrivateMethodInitSpec(this, _onAfterLoadData);
    /**
     * `afterScrollHorizontally` hook callback. Fired the table was scrolled horizontally.
     */
    _classPrivateMethodInitSpec(this, _onAfterScrollVertically);
    /**
     * `onMouseUp` hook callback.
     */
    _classPrivateMethodInitSpec(this, _onMouseUp);
    /**
     * 'beforeOnCellMouseOver' hook callback. Fired when pointer was over cell.
     *
     * @param {MouseEvent} event `mouseover` event properties.
     * @param {CellCoords} coords Visual cell coordinates where was fired event.
     * @param {HTMLElement} TD Cell represented as HTMLElement.
     * @param {object} controller An object with properties `row`, `column` and `cell`. Each property contains
     *                            a boolean value that allows or disallows changing the selection for that particular area.
     */
    _classPrivateMethodInitSpec(this, _onBeforeOnCellMouseOver);
    /**
     * 'mouseMove' event callback. Fired when pointer move on document.documentElement.
     *
     * @param {MouseEvent} event `mousemove` event properties.
     */
    _classPrivateMethodInitSpec(this, _onMouseMove);
    /**
     * Change the behavior of selection / dragging.
     *
     * @param {MouseEvent} event `mousedown` event properties.
     * @param {CellCoords} coords Visual cell coordinates where was fired event.
     * @param {HTMLElement} TD Cell represented as HTMLElement.
     * @param {object} controller An object with properties `row`, `column` and `cell`. Each property contains
     *                            a boolean value that allows or disallows changing the selection for that particular area.
     */
    _classPrivateMethodInitSpec(this, _onBeforeOnCellMouseDown);
    /**
     * Backlight UI object.
     *
     * @type {object}
     */
    _classPrivateFieldInitSpec(this, _backlight, {
      writable: true,
      value: new _backlight2.default(this.hot)
    });
    /**
     * Guideline UI object.
     *
     * @type {object}
     */
    _classPrivateFieldInitSpec(this, _guideline, {
      writable: true,
      value: new _guideline2.default(this.hot)
    });
    /**
     * @type {number[]}
     */
    _classPrivateFieldInitSpec(this, _columnsToMove, {
      writable: true,
      value: []
    });
    /**
     * @type {number}
     */
    _classPrivateFieldInitSpec(this, _countCols, {
      writable: true,
      value: 0
    });
    /**
     * @type {boolean}
     */
    _classPrivateFieldInitSpec(this, _pressed, {
      writable: true,
      value: false
    });
    /**
     * @type {object}
     */
    _classPrivateFieldInitSpec(this, _target, {
      writable: true,
      value: {}
    });
    /**
     * @type {number}
     */
    _classPrivateFieldInitSpec(this, _cachedDropIndex, {
      writable: true,
      value: void 0
    });
    /**
     * @type {number}
     */
    _classPrivateFieldInitSpec(this, _hoveredColumn, {
      writable: true,
      value: void 0
    });
    /**
     * @type {number}
     */
    _classPrivateFieldInitSpec(this, _rootElementOffset, {
      writable: true,
      value: void 0
    });
    /**
     * @type {boolean}
     */
    _classPrivateFieldInitSpec(this, _hasRowHeaders, {
      writable: true,
      value: void 0
    });
    /**
     * @type {number}
     */
    _classPrivateFieldInitSpec(this, _fixedColumnsStart, {
      writable: true,
      value: void 0
    });
  }
  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 ManualColumnMove#enablePlugin} method is called.
   *
   * @returns {boolean}
   */
  isEnabled() {
    return !!this.hot.getSettings()[PLUGIN_KEY];
  }

  /**
   * Enables the plugin functionality for this Handsontable instance.
   */
  enablePlugin() {
    var _this = this;
    if (this.enabled) {
      return;
    }
    this.addHook('beforeOnCellMouseDown', function () {
      for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
        args[_key] = arguments[_key];
      }
      return _classPrivateMethodGet(_this, _onBeforeOnCellMouseDown, _onBeforeOnCellMouseDown2).call(_this, ...args);
    });
    this.addHook('beforeOnCellMouseOver', function () {
      for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
        args[_key2] = arguments[_key2];
      }
      return _classPrivateMethodGet(_this, _onBeforeOnCellMouseOver, _onBeforeOnCellMouseOver2).call(_this, ...args);
    });
    this.addHook('afterScrollVertically', () => _classPrivateMethodGet(this, _onAfterScrollVertically, _onAfterScrollVertically2).call(this));
    this.addHook('afterLoadData', function () {
      for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
        args[_key3] = arguments[_key3];
      }
      return _classPrivateMethodGet(_this, _onAfterLoadData, _onAfterLoadData2).call(_this, ...args);
    });
    this.buildPluginUI();
    this.registerEvents();

    // TODO: move adding plugin classname to BasePlugin.
    (0, _element.addClass)(this.hot.rootElement, CSS_PLUGIN);
    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:
   *  - [`manualColumnMove`](@/api/options.md#manualcolumnmove)
   */
  updatePlugin() {
    this.disablePlugin();
    this.enablePlugin();
    this.moveBySettingsOrLoad();
    super.updatePlugin();
  }

  /**
   * Disables the plugin functionality for this Handsontable instance.
   */
  disablePlugin() {
    (0, _element.removeClass)(this.hot.rootElement, CSS_PLUGIN);
    this.unregisterEvents();
    _classPrivateFieldGet(this, _backlight).destroy();
    _classPrivateFieldGet(this, _guideline).destroy();
    super.disablePlugin();
  }

  /**
   * Moves a single column.
   *
   * @param {number} column Visual column index 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.
   * To check the visualization of the final index, please take a look at [documentation](@/guides/columns/column-moving.md#drag-and-move-actions-of-manualcolumnmove-plugin).
   * @fires Hooks#beforeColumnMove
   * @fires Hooks#afterColumnMove
   * @returns {boolean}
   */
  moveColumn(column, finalIndex) {
    return this.moveColumns([column], finalIndex);
  }

  /**
   * Moves a multiple columns.
   *
   * @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.
   * To check the visualization of the final index, please take a look at [documentation](@/guides/columns/column-moving.md#drag-and-move-actions-of-manualcolumnmove-plugin).
   * @fires Hooks#beforeColumnMove
   * @fires Hooks#afterColumnMove
   * @returns {boolean}
   */
  moveColumns(columns, finalIndex) {
    const dropIndex = _classPrivateFieldGet(this, _cachedDropIndex);
    const movePossible = this.isMovePossible(columns, finalIndex);
    const beforeMoveHook = this.hot.runHooks('beforeColumnMove', columns, finalIndex, dropIndex, movePossible);
    _classPrivateFieldSet(this, _cachedDropIndex, undefined);
    if (beforeMoveHook === false) {
      return;
    }
    if (movePossible) {
      this.hot.columnIndexMapper.moveIndexes(columns, finalIndex);
    }
    const movePerformed = movePossible && this.isColumnOrderChanged(columns, finalIndex);
    this.hot.runHooks('afterColumnMove', columns, finalIndex, dropIndex, movePossible, movePerformed);
    return movePerformed;
  }

  /**
   * Drag a single column to drop index position.
   *
   * @param {number} column Visual column index to be dragged.
   * @param {number} dropIndex Visual column index, being a drop index for the moved columns. Points to where we are going to drop the moved elements.
   * To check visualization of drop index please take a look at [documentation](@/guides/columns/column-moving.md#drag-and-move-actions-of-manualcolumnmove-plugin).
   * @fires Hooks#beforeColumnMove
   * @fires Hooks#afterColumnMove
   * @returns {boolean}
   */
  dragColumn(column, dropIndex) {
    return this.dragColumns([column], dropIndex);
  }

  /**
   * Drag multiple columns to drop index position.
   *
   * @param {Array} columns Array of visual column indexes to be dragged.
   * @param {number} dropIndex Visual column index, being a drop index for the moved columns. Points to where we are going to drop the moved elements.
   * To check visualization of drop index please take a look at [documentation](@/guides/columns/column-moving.md#drag-and-move-actions-of-manualcolumnmove-plugin).
   * @fires Hooks#beforeColumnMove
   * @fires Hooks#afterColumnMove
   * @returns {boolean}
   */
  dragColumns(columns, dropIndex) {
    const finalIndex = this.countFinalIndex(columns, dropIndex);
    _classPrivateFieldSet(this, _cachedDropIndex, dropIndex);
    return this.moveColumns(columns, finalIndex);
  }

  /**
   * Indicates if it's possible to move columns to the desired position. Some of the actions aren't
   * possible, i.e. You can’t move more than one element to the last position.
   *
   * @param {Array} movedColumns 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.
   * To check the visualization of the final index, please take a look at [documentation](@/guides/columns/column-moving.md#drag-and-move-actions-of-manualcolumnmove-plugin).
   * @returns {boolean}
   */
  isMovePossible(movedColumns, finalIndex) {
    const length = this.hot.columnIndexMapper.getNotTrimmedIndexesLength();

    // An attempt to transfer more columns to start destination than is possible (only when moving from the top to the bottom).
    const tooHighDestinationIndex = movedColumns.length + finalIndex > length;
    const tooLowDestinationIndex = finalIndex < 0;
    const tooLowMovedColumnIndex = movedColumns.some(movedColumn => movedColumn < 0);
    const tooHighMovedColumnIndex = movedColumns.some(movedColumn => movedColumn >= length);
    if (tooHighDestinationIndex || tooLowDestinationIndex || tooLowMovedColumnIndex || tooHighMovedColumnIndex) {
      return false;
    }
    return true;
  }

  /**
   * Indicates if order of columns was changed.
   *
   * @private
   * @param {Array} movedColumns 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.
   * To check the visualization of the final index, please take a look at [documentation](@/guides/columns/column-moving.md#drag-and-move-actions-of-manualcolumnmove-plugin).
   * @returns {boolean}
   */
  isColumnOrderChanged(movedColumns, finalIndex) {
    return movedColumns.some((column, nrOfMovedElement) => column - nrOfMovedElement !== finalIndex);
  }

  /**
   * Count the final column index from the drop index.
   *
   * @private
   * @param {Array} movedColumns Array of visual column indexes to be moved.
   * @param {number} dropIndex Visual column index, being a drop index for the moved columns.
   * @returns {number} Visual column index, being a start index for the moved columns.
   */
  countFinalIndex(movedColumns, dropIndex) {
    const numberOfColumnsLowerThanDropIndex = (0, _array.arrayReduce)(movedColumns, (numberOfColumns, currentColumnIndex) => {
      if (currentColumnIndex < dropIndex) {
        numberOfColumns += 1;
      }
      return numberOfColumns;
    }, 0);
    return dropIndex - numberOfColumnsLowerThanDropIndex;
  }

  /**
   * Gets the sum of the widths of columns in the provided range.
   *
   * @private
   * @param {number} fromColumn Visual column index.
   * @param {number} toColumn Visual column index.
   * @returns {number}
   */
  getColumnsWidth(fromColumn, toColumn) {
    const columnMapper = this.hot.columnIndexMapper;
    let columnsWidth = 0;
    for (let visualColumnIndex = fromColumn; visualColumnIndex <= toColumn; visualColumnIndex += 1) {
      // We can't use just `getColWidth` (even without indexes translation) as it doesn't return proper values
      // when column is stretched.
      const renderableIndex = columnMapper.getRenderableFromVisualIndex(visualColumnIndex);
      if (visualColumnIndex < 0) {
        columnsWidth += this.hot.view._wt.wtViewport.getRowHeaderWidth() || 0;
      } else if (renderableIndex !== null) {
        columnsWidth += this.hot.view._wt.wtTable.getStretchedColumnWidth(renderableIndex) || 0;
      }
    }
    return columnsWidth;
  }

  /**
   * Loads initial settings when persistent state is saved or when plugin was initialized as an array.
   *
   * @private
   */
  moveBySettingsOrLoad() {
    const pluginSettings = this.hot.getSettings()[PLUGIN_KEY];
    if (Array.isArray(pluginSettings)) {
      this.moveColumns(pluginSettings, 0);
    } else if (pluginSettings !== undefined) {
      const persistentState = this.persistentStateLoad();
      if (persistentState.length) {
        this.moveColumns(persistentState, 0);
      }
    }
  }

  /**
   * Checks if the provided column is in the fixedColumnsTop section.
   *
   * @private
   * @param {number} column Visual column index to check.
   * @returns {boolean}
   */
  isFixedColumnsStart(column) {
    return column < this.hot.getSettings().fixedColumnsStart;
  }

  /**
   * Saves the manual column positions to the persistent state (the {@link Options#persistentState} option has to be enabled).
   *
   * @private
   * @fires Hooks#persistentStateSave
   */
  persistentStateSave() {
    this.hot.runHooks('persistentStateSave', 'manualColumnMove', this.hot.columnIndexMapper.getIndexesSequence()); // The `PersistentState` plugin should be refactored.
  }

  /**
   * Loads the manual column positions from the persistent state (the {@link Options#persistentState} option has to be enabled).
   *
   * @private
   * @fires Hooks#persistentStateLoad
   * @returns {Array} Stored state.
   */
  persistentStateLoad() {
    const storedState = {};
    this.hot.runHooks('persistentStateLoad', 'manualColumnMove', storedState);
    return storedState.value ? storedState.value : [];
  }

  /**
   * Prepares an array of indexes based on actual selection.
   *
   * @private
   * @param {number} start The start index.
   * @param {number} end The end index.
   * @returns {Array}
   */
  prepareColumnsToMoving(start, end) {
    const selectedColumns = [];
    (0, _number.rangeEach)(start, end, i => {
      selectedColumns.push(i);
    });
    return selectedColumns;
  }

  /**
   * Update the UI visual position.
   *
   * @private
   */
  refreshPositions() {
    const firstVisible = this.hot.view.getFirstFullyVisibleColumn();
    if (this.isFixedColumnsStart(_classPrivateFieldGet(this, _hoveredColumn)) && firstVisible > 0) {
      this.hot.scrollViewportTo({
        col: this.hot.columnIndexMapper.getNearestNotHiddenIndex(firstVisible - 1, -1)
      });
    }
    const wtTable = this.hot.view._wt.wtTable;
    const scrollableElement = this.hot.view._wt.wtOverlays.scrollableElement;
    const scrollStart = typeof scrollableElement.scrollX === 'number' ? scrollableElement.scrollX : scrollableElement.scrollLeft;
    let tdOffsetStart = this.hot.view.THEAD.offsetLeft + this.getColumnsWidth(0, _classPrivateFieldGet(this, _hoveredColumn) - 1);
    const hiderWidth = wtTable.hider.offsetWidth;
    const tbodyOffsetLeft = wtTable.TBODY.offsetLeft;
    const backlightElemMarginStart = _classPrivateFieldGet(this, _backlight).getOffset().start;
    const backlightElemWidth = _classPrivateFieldGet(this, _backlight).getSize().width;
    let rowHeaderWidth = 0;
    let mouseOffsetStart = 0;
    if (this.hot.isRtl()) {
      const rootWindow = this.hot.rootWindow;
      const containerWidth = (0, _element.outerWidth)(this.hot.rootElement);
      const gridMostRightPos = rootWindow.innerWidth - _classPrivateFieldGet(this, _rootElementOffset) - containerWidth;
      mouseOffsetStart = rootWindow.innerWidth - _classPrivateFieldGet(this, _target).eventPageX - gridMostRightPos - (scrollableElement.scrollX === undefined ? scrollStart : 0);
    } else {
      mouseOffsetStart = _classPrivateFieldGet(this, _target).eventPageX - (_classPrivateFieldGet(this, _rootElementOffset) - (scrollableElement.scrollX === undefined ? scrollStart : 0));
    }
    if (_classPrivateFieldGet(this, _hasRowHeaders)) {
      rowHeaderWidth = this.hot.view._wt.wtOverlays.inlineStartOverlay.clone.wtTable.getColumnHeader(-1).offsetWidth;
    }
    if (this.isFixedColumnsStart(_classPrivateFieldGet(this, _hoveredColumn))) {
      tdOffsetStart += scrollStart;
    }
    tdOffsetStart += rowHeaderWidth;
    if (_classPrivateFieldGet(this, _hoveredColumn) < 0) {
      // if hover on rowHeader
      if (_classPrivateFieldGet(this, _fixedColumnsStart) > 0) {
        _classPrivateFieldGet(this, _target).col = 0;
      } else {
        _classPrivateFieldGet(this, _target).col = firstVisible > 0 ? firstVisible - 1 : firstVisible;
      }
    } else if (_classPrivateFieldGet(this, _target).TD.offsetWidth / 2 + tdOffsetStart <= mouseOffsetStart) {
      const newCoordsCol = _classPrivateFieldGet(this, _hoveredColumn) >= _classPrivateFieldGet(this, _countCols) ? _classPrivateFieldGet(this, _countCols) - 1 : _classPrivateFieldGet(this, _hoveredColumn);

      // if hover on right part of TD
      _classPrivateFieldGet(this, _target).col = newCoordsCol + 1;
      // unfortunately first column is bigger than rest
      tdOffsetStart += _classPrivateFieldGet(this, _target).TD.offsetWidth;
    } else {
      // elsewhere on table
      _classPrivateFieldGet(this, _target).col = _classPrivateFieldGet(this, _hoveredColumn);
    }
    let backlightStart = mouseOffsetStart;
    let guidelineStart = tdOffsetStart;
    if (mouseOffsetStart + backlightElemWidth + backlightElemMarginStart >= hiderWidth) {
      // prevent display backlight on the right side of the table
      backlightStart = hiderWidth - backlightElemWidth - backlightElemMarginStart;
    } else if (mouseOffsetStart + backlightElemMarginStart < tbodyOffsetLeft + rowHeaderWidth) {
      // prevent display backlight on the left side of the table
      backlightStart = tbodyOffsetLeft + rowHeaderWidth + Math.abs(backlightElemMarginStart);
    }
    if (tdOffsetStart >= hiderWidth - 1) {
      // prevent display guideline outside the table
      guidelineStart = hiderWidth - 1;
    } else if (guidelineStart === 0) {
      // guideline has got `margin-left: -1px` as default
      guidelineStart = 1;
    } else if (scrollableElement.scrollX !== undefined && _classPrivateFieldGet(this, _hoveredColumn) < _classPrivateFieldGet(this, _fixedColumnsStart)) {
      guidelineStart -= _classPrivateFieldGet(this, _rootElementOffset) <= scrollableElement.scrollX ? _classPrivateFieldGet(this, _rootElementOffset) : 0;
    }
    _classPrivateFieldGet(this, _backlight).setPosition(null, backlightStart);
    _classPrivateFieldGet(this, _guideline).setPosition(null, guidelineStart);
  }

  /**
   * Binds the events used by the plugin.
   *
   * @private
   */
  registerEvents() {
    const {
      documentElement
    } = this.hot.rootDocument;
    this.eventManager.addEventListener(documentElement, 'mousemove', event => _classPrivateMethodGet(this, _onMouseMove, _onMouseMove2).call(this, event));
    this.eventManager.addEventListener(documentElement, 'mouseup', () => _classPrivateMethodGet(this, _onMouseUp, _onMouseUp2).call(this));
  }

  /**
   * Unbinds the events used by the plugin.
   *
   * @private
   */
  unregisterEvents() {
    this.eventManager.clear();
  }
  /**
   * Builds the plugin's UI.
   *
   * @private
   */
  buildPluginUI() {
    _classPrivateFieldGet(this, _backlight).build();
    _classPrivateFieldGet(this, _guideline).build();
  }
  /**
   * Destroys the plugin instance.
   */
  destroy() {
    _classPrivateFieldGet(this, _backlight).destroy();
    _classPrivateFieldGet(this, _guideline).destroy();
    super.destroy();
  }
}
exports.ManualColumnMove = ManualColumnMove;
function _onBeforeOnCellMouseDown2(event, coords, TD, controller) {
  const wtTable = this.hot.view._wt.wtTable;
  const isHeaderSelection = this.hot.selection.isSelectedByColumnHeader();
  const selection = this.hot.getSelectedRangeLast();
  // This block action shouldn't be handled below.
  const isSortingElement = (0, _element.hasClass)(event.target, 'sortAction');
  if (!selection || !isHeaderSelection || _classPrivateFieldGet(this, _pressed) || event.button !== 0 || isSortingElement) {
    _classPrivateFieldSet(this, _pressed, false);
    _classPrivateFieldGet(this, _columnsToMove).length = 0;
    (0, _element.removeClass)(this.hot.rootElement, [CSS_ON_MOVING, CSS_SHOW_UI]);
    return;
  }
  const guidelineIsNotReady = _classPrivateFieldGet(this, _guideline).isBuilt() && !_classPrivateFieldGet(this, _guideline).isAppended();
  const backlightIsNotReady = _classPrivateFieldGet(this, _backlight).isBuilt() && !_classPrivateFieldGet(this, _backlight).isAppended();
  if (guidelineIsNotReady && backlightIsNotReady) {
    _classPrivateFieldGet(this, _guideline).appendTo(wtTable.hider);
    _classPrivateFieldGet(this, _backlight).appendTo(wtTable.hider);
  }
  const {
    from,
    to
  } = selection;
  const start = Math.min(from.col, to.col);
  const end = Math.max(from.col, to.col);
  if (coords.row < 0 && coords.col >= start && coords.col <= end) {
    controller.column = true;
    _classPrivateFieldSet(this, _pressed, true);
    const eventOffsetX = TD.firstChild ? (0, _event.offsetRelativeTo)(event, TD.firstChild).x : event.offsetX;
    _classPrivateFieldGet(this, _target).eventPageX = event.pageX;
    _classPrivateFieldSet(this, _hoveredColumn, coords.col);
    _classPrivateFieldGet(this, _target).TD = TD;
    _classPrivateFieldGet(this, _target).col = coords.col;
    _classPrivateFieldSet(this, _columnsToMove, this.prepareColumnsToMoving(start, end));
    _classPrivateFieldSet(this, _hasRowHeaders, !!this.hot.getSettings().rowHeaders);
    _classPrivateFieldSet(this, _countCols, this.hot.countCols());
    _classPrivateFieldSet(this, _fixedColumnsStart, this.hot.getSettings().fixedColumnsStart);
    _classPrivateFieldSet(this, _rootElementOffset, (0, _element.offset)(this.hot.rootElement).left);
    const countColumnsFrom = _classPrivateFieldGet(this, _hasRowHeaders) ? -1 : 0;
    const topPos = wtTable.holder.scrollTop + wtTable.getColumnHeaderHeight(0) + 1;
    const fixedColumnsStart = coords.col < _classPrivateFieldGet(this, _fixedColumnsStart);
    const horizontalScrollPosition = this.hot.view._wt.wtOverlays.inlineStartOverlay.getOverlayOffset();
    const offsetX = Math.abs(eventOffsetX - (this.hot.isRtl() ? TD.offsetWidth : 0));
    const inlineOffset = this.getColumnsWidth(start, coords.col - 1) + offsetX;
    const inlinePos = this.getColumnsWidth(countColumnsFrom, start - 1) + (fixedColumnsStart ? horizontalScrollPosition : 0) + inlineOffset;
    _classPrivateFieldGet(this, _backlight).setPosition(topPos, inlinePos);
    _classPrivateFieldGet(this, _backlight).setSize(this.getColumnsWidth(start, end), wtTable.hider.offsetHeight - topPos);
    _classPrivateFieldGet(this, _backlight).setOffset(null, -inlineOffset);
    (0, _element.addClass)(this.hot.rootElement, CSS_ON_MOVING);
  } else {
    (0, _element.removeClass)(this.hot.rootElement, CSS_AFTER_SELECTION);
    _classPrivateFieldSet(this, _pressed, false);
    _classPrivateFieldGet(this, _columnsToMove).length = 0;
  }
}
function _onMouseMove2(event) {
  if (!_classPrivateFieldGet(this, _pressed)) {
    return;
  }
  _classPrivateFieldGet(this, _target).eventPageX = event.pageX;
  this.refreshPositions();
}
function _onBeforeOnCellMouseOver2(event, coords, TD, controller) {
  const selectedRange = this.hot.getSelectedRangeLast();
  if (!selectedRange || !_classPrivateFieldGet(this, _pressed)) {
    return;
  }
  if (_classPrivateFieldGet(this, _columnsToMove).indexOf(coords.col) > -1) {
    (0, _element.removeClass)(this.hot.rootElement, CSS_SHOW_UI);
  } else {
    (0, _element.addClass)(this.hot.rootElement, CSS_SHOW_UI);
  }
  controller.row = true;
  controller.column = true;
  controller.cell = true;
  _classPrivateFieldSet(this, _hoveredColumn, coords.col);
  _classPrivateFieldGet(this, _target).TD = TD;
}
function _onMouseUp2() {
  const target = _classPrivateFieldGet(this, _target).col;
  const columnsLen = _classPrivateFieldGet(this, _columnsToMove).length;
  _classPrivateFieldSet(this, _hoveredColumn, undefined);
  _classPrivateFieldSet(this, _pressed, false);
  (0, _element.removeClass)(this.hot.rootElement, [CSS_ON_MOVING, CSS_SHOW_UI, CSS_AFTER_SELECTION]);
  if (this.hot.selection.isSelectedByColumnHeader()) {
    (0, _element.addClass)(this.hot.rootElement, CSS_AFTER_SELECTION);
  }
  if (columnsLen < 1 || target === undefined) {
    return;
  }
  const firstMovedVisualColumn = _classPrivateFieldGet(this, _columnsToMove)[0];
  const firstMovedPhysicalColumn = this.hot.toPhysicalColumn(firstMovedVisualColumn);
  const movePerformed = this.dragColumns(_classPrivateFieldGet(this, _columnsToMove), target);
  _classPrivateFieldGet(this, _columnsToMove).length = 0;
  if (movePerformed === true) {
    this.persistentStateSave();
    this.hot.render();
    this.hot.view.adjustElementsSize(true);
    const selectionStart = this.hot.toVisualColumn(firstMovedPhysicalColumn);
    const selectionEnd = selectionStart + columnsLen - 1;
    this.hot.selectColumns(selectionStart, selectionEnd);
  }
}
function _onAfterScrollVertically2() {
  const wtTable = this.hot.view._wt.wtTable;
  const headerHeight = wtTable.getColumnHeaderHeight(0) + 1;
  const scrollTop = wtTable.holder.scrollTop;
  const posTop = headerHeight + scrollTop;
  _classPrivateFieldGet(this, _backlight).setPosition(posTop);
  _classPrivateFieldGet(this, _backlight).setSize(null, wtTable.hider.offsetHeight - posTop);
}
function _onAfterLoadData2() {
  this.moveBySettingsOrLoad();
}