"use strict";

require("core-js/modules/es.symbol.to-primitive.js");
require("core-js/modules/es.date.to-primitive.js");
require("core-js/modules/es.symbol.js");
require("core-js/modules/es.symbol.description.js");
require("core-js/modules/es.number.constructor.js");
require("core-js/modules/es.symbol.iterator.js");
function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
exports.__esModule = true;
exports.default = void 0;
require("core-js/modules/es.array.map.js");
require("core-js/modules/es.array.index-of.js");
require("core-js/modules/es.object.to-string.js");
require("core-js/modules/web.dom-collections.for-each.js");
require("core-js/modules/es.array.filter.js");
require("core-js/modules/es.array.from.js");
require("core-js/modules/es.string.iterator.js");
require("core-js/modules/es.array.iterator.js");
require("core-js/modules/web.dom-collections.iterator.js");
require("core-js/modules/es.array.includes.js");
require("core-js/modules/es.string.includes.js");
require("core-js/modules/es.array.slice.js");
require("core-js/modules/es.weak-map.js");
var _string = require("../../../helpers/string");
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
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; } }
var _axis = /*#__PURE__*/new WeakMap();
var _indexMapper = /*#__PURE__*/new WeakMap();
var _indexSyncer = /*#__PURE__*/new WeakMap();
var _indexesSequence = /*#__PURE__*/new WeakMap();
var _movedIndexes = /*#__PURE__*/new WeakMap();
var _finalIndex = /*#__PURE__*/new WeakMap();
var _removedIndexes = /*#__PURE__*/new WeakMap();
/**
 * @private
 * @class IndexSyncer
 * @description
 *
 * Indexes synchronizer responsible for providing logic for particular axis. It respects an idea to represent trimmed
 * elements in HF's engine to perform formulas calculations on them. It also provides method for translation from visual
 * row/column indexes to HF's row/column indexes.
 */
var AxisSyncer = /*#__PURE__*/function () {
  /**
   * The axis for which the actions are performed.
   *
   * @private
   * @type {'row'|'column'}
   */

  /**
   * Reference to index mapper.
   *
   * @private
   * @type {IndexMapper}
   */

  /**
   * The index synchronizer for both axis (is storing some more general information).
   *
   * @private
   * @type {IndexSyncer}
   */

  /**
   * Sequence of physical indexes stored for watching changes and calculating some transformations.
   *
   * @private
   * @type {Array<number>}
   */

  /**
   * List of moved HF indexes, stored before performing move on HOT to calculate transformation needed on HF's engine.
   *
   * @private
   * @type {Array<number>}
   */

  /**
   * Final HF's place where to move indexes, stored before performing move on HOT to calculate transformation needed on HF's engine.
   *
   * @private
   * @type {number|undefined}
   */

  /**
   * List of removed HF indexes, stored before performing removal on HOT to calculate transformation needed on HF's engine.
   *
   * @private
   * @type {Array<number>}
   */

  function AxisSyncer(axis, indexMapper, indexSyncer) {
    _classCallCheck(this, AxisSyncer);
    _classPrivateFieldInitSpec(this, _axis, {
      writable: true,
      value: void 0
    });
    _classPrivateFieldInitSpec(this, _indexMapper, {
      writable: true,
      value: void 0
    });
    _classPrivateFieldInitSpec(this, _indexSyncer, {
      writable: true,
      value: void 0
    });
    _classPrivateFieldInitSpec(this, _indexesSequence, {
      writable: true,
      value: []
    });
    _classPrivateFieldInitSpec(this, _movedIndexes, {
      writable: true,
      value: []
    });
    _classPrivateFieldInitSpec(this, _finalIndex, {
      writable: true,
      value: void 0
    });
    _classPrivateFieldInitSpec(this, _removedIndexes, {
      writable: true,
      value: []
    });
    _classPrivateFieldSet(this, _axis, axis);
    _classPrivateFieldSet(this, _indexMapper, indexMapper);
    _classPrivateFieldSet(this, _indexSyncer, indexSyncer);
  }

  /**
   * Sets removed HF indexes (it should be done right before performing move on HOT).
   *
   * @param {Array<number>} removedIndexes List of removed physical indexes.
   * @returns {Array<number>} List of removed visual indexes.
   */
  _createClass(AxisSyncer, [{
    key: "setRemovedHfIndexes",
    value: function setRemovedHfIndexes(removedIndexes) {
      var _this = this;
      _classPrivateFieldSet(this, _removedIndexes, removedIndexes.map(function (physicalIndex) {
        var visualIndex = _classPrivateFieldGet(_this, _indexMapper).getVisualFromPhysicalIndex(physicalIndex);
        return _this.getHfIndexFromVisualIndex(visualIndex);
      }));
      return _classPrivateFieldGet(this, _removedIndexes);
    }

    /**
     * Gets removed HF indexes (right before performing removal on HOT).
     *
     * @returns {Array<number>} List of removed HF indexes.
     */
  }, {
    key: "getRemovedHfIndexes",
    value: function getRemovedHfIndexes() {
      return _classPrivateFieldGet(this, _removedIndexes);
    }

    /**
     * Gets corresponding HyperFormula index for particular visual index. It's respecting the idea that HF's engine
     * is fed also with trimmed indexes (business requirements for formula result calculation also for trimmed elements).
     *
     * @param {number} visualIndex Visual index.
     * @returns {number}
     */
  }, {
    key: "getHfIndexFromVisualIndex",
    value: function getHfIndexFromVisualIndex(visualIndex) {
      var indexesSequence = _classPrivateFieldGet(this, _indexMapper).getIndexesSequence();
      var notTrimmedIndexes = _classPrivateFieldGet(this, _indexMapper).getNotTrimmedIndexes();
      return indexesSequence.indexOf(notTrimmedIndexes[visualIndex]);
    }

    /**
     * Synchronizes moves done on HOT to HF engine (based on previously calculated positions).
     *
     * @private
     * @param {Array<{from: number, to: number}>} moves Calculated HF's move positions.
     */
  }, {
    key: "syncMoves",
    value: function syncMoves(moves) {
      var _this2 = this;
      var NUMBER_OF_MOVED_INDEXES = 1;
      var SYNC_MOVE_METHOD_NAME = "move".concat((0, _string.toUpperCaseFirst)(_classPrivateFieldGet(this, _axis)), "s");
      _classPrivateFieldGet(this, _indexSyncer).getEngine().batch(function () {
        moves.forEach(function (move) {
          var moveToTheSamePosition = move.from !== move.to;
          // Moving from left to right (or top to bottom) to a line (drop index) right after already moved element.
          var anotherMoveWithoutEffect = move.from + 1 !== move.to;
          if (moveToTheSamePosition && anotherMoveWithoutEffect) {
            _classPrivateFieldGet(_this2, _indexSyncer).getEngine()[SYNC_MOVE_METHOD_NAME](_classPrivateFieldGet(_this2, _indexSyncer).getSheetId(), move.from, NUMBER_OF_MOVED_INDEXES, move.to);
          }
        });
      });
    }

    /**
     * Stores information about performed HOT moves for purpose of calculating where to move HF elements.
     *
     * @param {Array<number>} movedVisualIndexes Sequence of moved visual indexes for certain axis.
     * @param {number} visualFinalIndex Final visual place where to move HOT indexes.
     * @param {boolean} movePossible Indicates if it's possible to move HOT indexes to the desired position.
     */
  }, {
    key: "storeMovesInformation",
    value: function storeMovesInformation(movedVisualIndexes, visualFinalIndex, movePossible) {
      var _this3 = this;
      if (movePossible === false) {
        return;
      }
      _classPrivateFieldSet(this, _movedIndexes, movedVisualIndexes.map(function (index) {
        return _this3.getHfIndexFromVisualIndex(index);
      }));
      _classPrivateFieldSet(this, _finalIndex, this.getHfIndexFromVisualIndex(visualFinalIndex));
    }

    /**
     * Gets first position where to move element (respecting the fact that some element will be sooner or later
     * taken out of the dataset in order to move them).
     *
     * @param {Array<number>} movedHfIndexes Sequence of moved HF indexes for certain axis.
     * @param {number} finalHfIndex Final HF place where to move rows.
     * @returns {number} HF's index informing where to move the first element.
     * @private
     */
  }, {
    key: "getMoveLine",
    value: function getMoveLine(movedHfIndexes, finalHfIndex) {
      var numberOfElements = _classPrivateFieldGet(this, _indexMapper).getNumberOfIndexes();
      var notMovedElements = Array.from(Array(numberOfElements).keys()).filter(function (index) {
        return movedHfIndexes.includes(index) === false;
      });
      if (finalHfIndex === 0) {
        var _notMovedElements$fin;
        return (_notMovedElements$fin = notMovedElements[finalHfIndex]) !== null && _notMovedElements$fin !== void 0 ? _notMovedElements$fin : 0; // Moving before the first dataset's element.
      }

      return notMovedElements[finalHfIndex - 1] + 1; // Moving before another element.
    }

    /**
     * Gets initially calculated HF's move positions.
     *
     * @private
     * @param {Array<number>} movedHfIndexes Sequence of moved HF indexes for certain axis.
     * @param {number} finalHfIndex Final HF place where to move rows.
     * @returns {Array<{from: number, to: number}>} Initially calculated HF's move positions.
     */
  }, {
    key: "getInitiallyCalculatedMoves",
    value: function getInitiallyCalculatedMoves(movedHfIndexes, finalHfIndex) {
      var moveLine = this.getMoveLine(movedHfIndexes, finalHfIndex);
      var moves = [];
      movedHfIndexes.forEach(function (movedHfIndex) {
        var move = {
          from: movedHfIndex,
          to: moveLine
        };
        moves.forEach(function (previouslyMovedIndex) {
          var isMovingFromEndToStart = previouslyMovedIndex.from > previouslyMovedIndex.to;
          var isMovingElementBefore = previouslyMovedIndex.to <= move.from;
          var isMovingAfterElement = previouslyMovedIndex.from > move.from;
          if (isMovingAfterElement && isMovingElementBefore && isMovingFromEndToStart) {
            move.from += 1;
          }
        });

        // Moved element from right to left (or bottom to top).
        if (move.from >= moveLine) {
          moveLine += 1;
        }
        moves.push(move);
      });
      return moves;
    }

    /**
     * Gets finally calculated HF's move positions (after adjusting).
     *
     * @private
     * @param {Array<{from: number, to: number}>} moves Initially calculated HF's move positions.
     * @returns {Array<{from: number, to: number}>} Finally calculated HF's move positions (after adjusting).
     */
  }, {
    key: "adjustedCalculatedMoves",
    value: function adjustedCalculatedMoves(moves) {
      moves.forEach(function (move, index) {
        var nextMoved = moves.slice(index + 1);
        nextMoved.forEach(function (nextMovedIndex) {
          var isMovingFromStartToEnd = nextMovedIndex.from < nextMovedIndex.to;
          if (nextMovedIndex.from > move.from && isMovingFromStartToEnd) {
            nextMovedIndex.from -= 1;
          }
        });
      });
      return moves;
    }

    /**
     * Calculating where to move HF elements and performing already calculated moves.
     *
     * @param {boolean} movePossible Indicates if it was possible to move HOT indexes to the desired position.
     * @param {boolean} orderChanged Indicates if order of HOT indexes was changed by move.
     */
  }, {
    key: "calculateAndSyncMoves",
    value: function calculateAndSyncMoves(movePossible, orderChanged) {
      var _this4 = this;
      if (_classPrivateFieldGet(this, _indexSyncer).isPerformingUndoRedo()) {
        return;
      }
      if (movePossible === false || orderChanged === false) {
        return;
      }
      var calculatedMoves = this.adjustedCalculatedMoves(this.getInitiallyCalculatedMoves(_classPrivateFieldGet(this, _movedIndexes), _classPrivateFieldGet(this, _finalIndex)));
      if (_classPrivateFieldGet(this, _indexSyncer).getSheetId() === null) {
        _classPrivateFieldGet(this, _indexSyncer).getPostponeAction(function () {
          return _this4.syncMoves(calculatedMoves);
        });
      } else {
        this.syncMoves(calculatedMoves);
      }
    }

    /**
     * Gets callback for hook triggered after performing change of indexes order.
     *
     * @returns {Function}
     */
  }, {
    key: "getIndexesChangeSyncMethod",
    value: function getIndexesChangeSyncMethod() {
      var _this5 = this;
      var SYNC_ORDER_CHANGE_METHOD_NAME = "set".concat((0, _string.toUpperCaseFirst)(_classPrivateFieldGet(this, _axis)), "Order");
      return function (source) {
        if (_classPrivateFieldGet(_this5, _indexSyncer).isPerformingUndoRedo()) {
          return;
        }
        var newSequence = _classPrivateFieldGet(_this5, _indexMapper).getIndexesSequence();
        if (source === 'update') {
          var relativeTransformation = _classPrivateFieldGet(_this5, _indexesSequence).map(function (index) {
            return newSequence.indexOf(index);
          });
          var sheetDimensions = _classPrivateFieldGet(_this5, _indexSyncer).getEngine().getSheetDimensions(_classPrivateFieldGet(_this5, _indexSyncer).getSheetId());
          var sizeForAxis;
          if (_classPrivateFieldGet(_this5, _axis) === 'row') {
            sizeForAxis = sheetDimensions.height;
          } else {
            sizeForAxis = sheetDimensions.width;
          }
          var numberOfReorganisedIndexes = relativeTransformation.length;

          // Sheet dimension can be changed by HF's engine for purpose of calculating values. It extends dependency
          // graph to calculate values outside of a defined dataset. This part of code could be removed after resolving
          // feature request from HF issue board (handsontable/hyperformula#1179).
          for (var i = numberOfReorganisedIndexes; i < sizeForAxis; i += 1) {
            relativeTransformation.push(i);
          }
          _classPrivateFieldGet(_this5, _indexSyncer).getEngine()[SYNC_ORDER_CHANGE_METHOD_NAME](_classPrivateFieldGet(_this5, _indexSyncer).getSheetId(), relativeTransformation);
        }
        _classPrivateFieldSet(_this5, _indexesSequence, newSequence);
      };
    }

    /**
     * Initialize the AxisSyncer.
     */
  }, {
    key: "init",
    value: function init() {
      _classPrivateFieldSet(this, _indexesSequence, _classPrivateFieldGet(this, _indexMapper).getIndexesSequence());
    }
  }]);
  return AxisSyncer;
}();
var _default = AxisSyncer;
exports.default = _default;