import "core-js/modules/es.symbol";
import "core-js/modules/es.symbol.description";
import "core-js/modules/es.symbol.iterator";
import "core-js/modules/es.array.concat";
import "core-js/modules/es.array.includes";
import "core-js/modules/es.array.iterator";
import "core-js/modules/es.object.to-string";
import "core-js/modules/es.regexp.to-string";
import "core-js/modules/es.string.includes";
import "core-js/modules/es.string.iterator";
import "core-js/modules/web.dom-collections.iterator";

function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }

function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }

function _iterableToArrayLimit(arr, i) { if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) { return; } var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }

function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }

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, descriptor.key, descriptor); } }

function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

import { CellCoords, CellRange } from './../../../3rdparty/walkontable/src';
/**
 * Class responsible for all of the Selection-related operations on merged cells.
 *
 * @class SelectionCalculations
 * @plugin MergeCells
 * @util
 */

var SelectionCalculations =
/*#__PURE__*/
function () {
  function SelectionCalculations(plugin) {
    _classCallCheck(this, SelectionCalculations);

    /**
     * Reference to the Merge Cells plugin.
     *
     * @type {MergeCells}
     */
    this.plugin = plugin;
    /**
     * Class name used for fully selected merged cells.
     *
     * @type {String}
     */

    this.fullySelectedMergedCellClassName = 'fullySelectedMergedCell';
  }
  /**
   * "Snap" the delta value according to defined merged cells. (In other words, compensate the rowspan -
   * e.g. going up with `delta.row = -1` over a merged cell with `rowspan = 3`, `delta.row` should change to `-3`.)
   *
   * @param {Object} delta The delta object containing `row` and `col` properties.
   * @param {CellRange} selectionRange The selection range.
   * @param {Object} mergedCell A merged cell object.
   */


  _createClass(SelectionCalculations, [{
    key: "snapDelta",
    value: function snapDelta(delta, selectionRange, mergedCell) {
      var cellCoords = selectionRange.to;
      var newRow = cellCoords.row + delta.row;
      var newColumn = cellCoords.col + delta.col;

      if (delta.row) {
        this.jumpOverMergedCell(delta, mergedCell, newRow);
      } else if (delta.col) {
        this.jumpOverMergedCell(delta, mergedCell, newColumn);
      }
    }
    /**
     * "Jump" over the merged cell (compensate for the indexes within the merged cell to get past it)
     *
     * @private
     * @param {Object} delta The delta object.
     * @param {MergedCellCoords} mergedCell The merge cell object.
     * @param {Number} newIndex New row/column index, created with the delta.
     */

  }, {
    key: "jumpOverMergedCell",
    value: function jumpOverMergedCell(delta, mergedCell, newIndex) {
      var flatDelta = delta.row || delta.col;
      var includesIndex = null;
      var firstIndex = null;
      var lastIndex = null;

      if (delta.row) {
        includesIndex = mergedCell.includesVertically(newIndex);
        firstIndex = mergedCell.row;
        lastIndex = mergedCell.getLastRow();
      } else if (delta.col) {
        includesIndex = mergedCell.includesHorizontally(newIndex);
        firstIndex = mergedCell.col;
        lastIndex = mergedCell.getLastColumn();
      }

      if (flatDelta === 0) {
        return;
      } else if (flatDelta > 0) {
        if (includesIndex && newIndex !== firstIndex) {
          flatDelta += lastIndex - newIndex + 1;
        }
      } else if (includesIndex && newIndex !== lastIndex) {
        flatDelta -= newIndex - firstIndex + 1;
      }

      if (delta.row) {
        delta.row = flatDelta;
      } else if (delta.col) {
        delta.col = flatDelta;
      }
    }
    /**
     * Get a selection range with `to` property incremented by the provided delta.
     *
     * @param {CellRange} oldSelectionRange The base selection range.
     * @param {Object} delta The delta object with `row` and `col` properties.
     * @returns {CellRange} A new `CellRange` object.
     */

  }, {
    key: "getUpdatedSelectionRange",
    value: function getUpdatedSelectionRange(oldSelectionRange, delta) {
      return new CellRange(oldSelectionRange.highlight, oldSelectionRange.from, new CellCoords(oldSelectionRange.to.row + delta.row, oldSelectionRange.to.col + delta.col));
    }
    /**
     * Generate an additional class name for the entirely-selected merged cells.
     *
     * @param {Number} currentRow Row index of the currently processed cell.
     * @param {Number} currentColumn Column index of the currently cell.
     * @param {Array} cornersOfSelection Array of the current selection in a form of `[startRow, startColumn, endRow, endColumn]`.
     * @param {Number|undefined} layerLevel Number indicating which layer of selection is currently processed.
     * @returns {String|undefined} A `String`, which will act as an additional `className` to be added to the currently processed cell.
     */

  }, {
    key: "getSelectedMergedCellClassName",
    value: function getSelectedMergedCellClassName(currentRow, currentColumn, cornersOfSelection, layerLevel) {
      var _cornersOfSelection = _slicedToArray(cornersOfSelection, 4),
          startRow = _cornersOfSelection[0],
          startColumn = _cornersOfSelection[1],
          endRow = _cornersOfSelection[2],
          endColumn = _cornersOfSelection[3];

      if (layerLevel === void 0) {
        return;
      }

      if (currentRow >= startRow && currentRow <= endRow && currentColumn >= startColumn && currentColumn <= endColumn) {
        var isMergedCellParent = this.plugin.mergedCellsCollection.isMergedParent(currentRow, currentColumn);

        if (!isMergedCellParent) {
          return;
        }

        var mergedCell = this.plugin.mergedCellsCollection.get(currentRow, currentColumn);

        if (!mergedCell) {
          return;
        }

        if (mergedCell.row + mergedCell.rowspan - 1 <= endRow && mergedCell.col + mergedCell.colspan - 1 <= endColumn) {
          return "".concat(this.fullySelectedMergedCellClassName, "-").concat(layerLevel);
        } else if (this.plugin.selectionCalculations.isMergeCellFullySelected(mergedCell, this.plugin.hot.getSelectedRange())) {
          return "".concat(this.fullySelectedMergedCellClassName, "-multiple");
        }
      }
    }
    /**
     * Check if the provided merged cell is fully selected (by one or many layers of selection)
     *
     * @param {MergedCellCoords} mergedCell The merged cell to be processed.
     * @param {CellRange[]} selectionRangesArray Array of selection ranges.
     * @returns {Boolean}
     */

  }, {
    key: "isMergeCellFullySelected",
    value: function isMergeCellFullySelected(mergedCell, selectionRangesArray) {
      var mergedCellIndividualCoords = [];

      if (!selectionRangesArray || !mergedCell) {
        return false;
      }

      for (var r = 0; r < mergedCell.rowspan; r += 1) {
        for (var c = 0; c < mergedCell.colspan; c += 1) {
          mergedCellIndividualCoords.push(new CellCoords(mergedCell.row + r, mergedCell.col + c));
        }
      }

      for (var i = 0; i < mergedCellIndividualCoords.length; i += 1) {
        var insideSelections = [];

        for (var s = 0; s < selectionRangesArray.length; s += 1) {
          insideSelections[s] = selectionRangesArray[s].includes(mergedCellIndividualCoords[i]);
        }

        if (!insideSelections.includes(true)) {
          return false;
        }
      }

      return true;
    }
    /**
     * Generate an array of the entirely-selected merged cells' class names.
     *
     * @returns {String[]} An `Array` of `String`s. Each of these strings will act like class names to be removed from all the cells in the table.
     */

  }, {
    key: "getSelectedMergedCellClassNameToRemove",
    value: function getSelectedMergedCellClassNameToRemove() {
      var classNames = [];

      for (var i = 0; i <= 7; i += 1) {
        classNames.push("".concat(this.fullySelectedMergedCellClassName, "-").concat(i));
      }

      classNames.push("".concat(this.fullySelectedMergedCellClassName, "-multiple"));
      return classNames;
    }
  }]);

  return SelectionCalculations;
}();

export default SelectionCalculations;