"use strict";

exports.__esModule = true;
require("core-js/modules/es.array.unscopables.flat.js");
require("core-js/modules/es.error.cause.js");
var _element = require("../../../../helpers/dom/element");
var _scanner2 = require("./scanner");
var _border = _interopRequireDefault(require("./border/border"));
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 _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; }
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; } }
/**
 * Module responsible for rendering selections (CSS classes) and borders based on the
 * collection of the Selection instances provided throughout the `selections` Walkontable
 * setting.
 *
 * @private
 */
var _activeOverlaysWot = /*#__PURE__*/new WeakMap();
var _selections = /*#__PURE__*/new WeakMap();
var _scanner = /*#__PURE__*/new WeakMap();
var _appliedClasses = /*#__PURE__*/new WeakMap();
var _destroyListeners = /*#__PURE__*/new WeakMap();
var _selectionBorders = /*#__PURE__*/new WeakMap();
var _resetCells = /*#__PURE__*/new WeakSet();
class SelectionManager {
  constructor(selections) {
    /**
     * Resets the elements to their initial state (remove the CSS classes that are added in the
     * previous render cycle).
     */
    _classPrivateMethodInitSpec(this, _resetCells);
    /**
     * The overlay's Walkontable instance that are currently processed.
     *
     * @type {Walkontable}
     */
    _classPrivateFieldInitSpec(this, _activeOverlaysWot, {
      writable: true,
      value: void 0
    });
    /**
     * The Highlight instance that holds Selections instances within it.
     *
     * @type {Highlight|null}
     */
    _classPrivateFieldInitSpec(this, _selections, {
      writable: true,
      value: void 0
    });
    /**
     * The SelectionScanner allows to scan and collect the cell and header elements that matches
     * to the coords defined in the selections.
     *
     * @type {SelectionScanner}
     */
    _classPrivateFieldInitSpec(this, _scanner, {
      writable: true,
      value: new _scanner2.SelectionScanner()
    });
    /**
     * The Map tracks applied CSS classes. It's used to reset the elements state to their initial state.
     *
     * @type {WeakMap}
     */
    _classPrivateFieldInitSpec(this, _appliedClasses, {
      writable: true,
      value: new WeakMap()
    });
    /**
     * The Map tracks applied "destroy" listeners for Selection instances.
     *
     * @type {WeakMap}
     */
    _classPrivateFieldInitSpec(this, _destroyListeners, {
      writable: true,
      value: new WeakSet()
    });
    /**
     * The Map holds references to Border classes for Selection instances which requires that when
     * the "border" setting is defined.
     *
     * @type {Map}
     */
    _classPrivateFieldInitSpec(this, _selectionBorders, {
      writable: true,
      value: new Map()
    });
    _classPrivateFieldSet(this, _selections, selections);
  }

  /**
   * Sets the active Walkontable instance.
   *
   * @param {Walkontable} activeWot The overlays or master Walkontable instance.
   * @returns {SelectionManager}
   */
  setActiveOverlay(activeWot) {
    _classPrivateFieldSet(this, _activeOverlaysWot, activeWot);
    _classPrivateFieldGet(this, _scanner).setActiveOverlay(_classPrivateFieldGet(this, _activeOverlaysWot));
    if (!_classPrivateFieldGet(this, _appliedClasses).has(_classPrivateFieldGet(this, _activeOverlaysWot))) {
      _classPrivateFieldGet(this, _appliedClasses).set(_classPrivateFieldGet(this, _activeOverlaysWot), new Set());
    }
    return this;
  }

  /**
   * Gets the Selection instance of the "focus" type.
   *
   * @returns {Selection|null}
   */
  getFocusSelection() {
    return _classPrivateFieldGet(this, _selections) !== null ? _classPrivateFieldGet(this, _selections).getFocus() : null;
  }

  /**
   * Gets the Selection instance of the "area" type.
   *
   * @returns {Selection|null}
   */
  getAreaSelection() {
    return _classPrivateFieldGet(this, _selections) !== null ? _classPrivateFieldGet(this, _selections).createLayeredArea() : null;
  }

  /**
   * Gets the Border instance associated with Selection instance.
   *
   * @param {Selection} selection The selection instance.
   * @returns {Border|null} Returns the Border instance (new for each overlay Walkontable instance).
   */
  getBorderInstance(selection) {
    if (!selection.settings.border) {
      return null;
    }
    if (_classPrivateFieldGet(this, _selectionBorders).has(selection)) {
      const borders = _classPrivateFieldGet(this, _selectionBorders).get(selection);
      if (borders.has(_classPrivateFieldGet(this, _activeOverlaysWot))) {
        return borders.get(_classPrivateFieldGet(this, _activeOverlaysWot));
      }
      const border = new _border.default(_classPrivateFieldGet(this, _activeOverlaysWot), selection.settings);
      borders.set(_classPrivateFieldGet(this, _activeOverlaysWot), border);
      return border;
    }
    const border = new _border.default(_classPrivateFieldGet(this, _activeOverlaysWot), selection.settings);
    _classPrivateFieldGet(this, _selectionBorders).set(selection, new Map([[_classPrivateFieldGet(this, _activeOverlaysWot), border]]));
    return border;
  }

  /**
   * Gets all Border instances associated with Selection instance for all overlays.
   *
   * @param {Selection} selection The selection instance.
   * @returns {Border[]}
   */
  getBorderInstances(selection) {
    var _classPrivateFieldGet2, _classPrivateFieldGet3;
    return Array.from((_classPrivateFieldGet2 = (_classPrivateFieldGet3 = _classPrivateFieldGet(this, _selectionBorders).get(selection)) === null || _classPrivateFieldGet3 === void 0 ? void 0 : _classPrivateFieldGet3.values()) !== null && _classPrivateFieldGet2 !== void 0 ? _classPrivateFieldGet2 : []);
  }

  /**
   * Destroys the Border instance associated with Selection instance.
   *
   * @param {Selection} selection The selection instance.
   */
  destroyBorders(selection) {
    _classPrivateFieldGet(this, _selectionBorders).get(selection).forEach(border => border.destroy());
    _classPrivateFieldGet(this, _selectionBorders).delete(selection);
  }

  /**
   * Renders all the selections (add CSS classes to cells and draw borders).
   *
   * @param {boolean} fastDraw Indicates the render cycle type (fast/slow).
   */
  render(fastDraw) {
    if (_classPrivateFieldGet(this, _selections) === null) {
      return;
    }
    if (fastDraw) {
      // there was no rerender, so we need to remove classNames by ourselves
      _classPrivateMethodGet(this, _resetCells, _resetCells2).call(this);
    }
    const selections = Array.from(_classPrivateFieldGet(this, _selections));
    const classNamesMap = new Map();
    for (let i = 0; i < selections.length; i++) {
      const selection = selections[i];
      const {
        className,
        createLayers,
        selectionType
      } = selection.settings;
      if (!_classPrivateFieldGet(this, _destroyListeners).has(selection)) {
        _classPrivateFieldGet(this, _destroyListeners).add(selection);
        selection.addLocalHook('destroy', () => this.destroyBorders(selection));
      }
      const borderInstance = this.getBorderInstance(selection);
      if (selection.isEmpty()) {
        borderInstance === null || borderInstance === void 0 || borderInstance.disappear();
        continue; // eslint-disable-line no-continue
      }

      if (className) {
        const elements = _classPrivateFieldGet(this, _scanner).setActiveSelection(selection).scan();
        elements.forEach(element => {
          if (classNamesMap.has(element)) {
            const classNamesLayers = classNamesMap.get(element);
            if (classNamesLayers.has(className) && createLayers === true) {
              classNamesLayers.set(className, classNamesLayers.get(className) + 1);
            } else {
              classNamesLayers.set(className, 1);
            }
          } else {
            classNamesMap.set(element, new Map([[className, 1]]));
          }
        });
      }
      const corners = selection.getCorners();
      _classPrivateFieldGet(this, _activeOverlaysWot).getSetting('onBeforeDrawBorders', corners, selectionType);
      borderInstance === null || borderInstance === void 0 || borderInstance.appear(corners);
    }
    classNamesMap.forEach((classNamesLayers, element) => {
      var _classPrivateFieldGet4, _classPrivateFieldGet5;
      const classNames = Array.from(classNamesLayers).map(_ref => {
        let [className, occurrenceCount] = _ref;
        if (occurrenceCount === 1) {
          return className;
        }
        return [className, ...Array.from({
          length: occurrenceCount - 1
        }, (_, i) => `${className}-${i + 1}`)];
      }).flat();
      classNames.forEach(className => _classPrivateFieldGet(this, _appliedClasses).get(_classPrivateFieldGet(this, _activeOverlaysWot)).add(className));
      (0, _element.addClass)(element, classNames);
      if (element.nodeName === 'TD' && Array.isArray((_classPrivateFieldGet4 = _classPrivateFieldGet(this, _selections).options) === null || _classPrivateFieldGet4 === void 0 ? void 0 : _classPrivateFieldGet4.cellAttributes)) {
        (0, _element.setAttribute)(element, _classPrivateFieldGet(this, _selections).options.cellAttributes);
      } else if (element.nodeName === 'TH' && Array.isArray((_classPrivateFieldGet5 = _classPrivateFieldGet(this, _selections).options) === null || _classPrivateFieldGet5 === void 0 ? void 0 : _classPrivateFieldGet5.headerAttributes)) {
        (0, _element.setAttribute)(element, _classPrivateFieldGet(this, _selections).options.headerAttributes);
      }
    });
  }
}
exports.SelectionManager = SelectionManager;
function _resetCells2() {
  const appliedOverlaysClasses = _classPrivateFieldGet(this, _appliedClasses).get(_classPrivateFieldGet(this, _activeOverlaysWot));
  const classesToRemove = _classPrivateFieldGet(this, _activeOverlaysWot).wtSettings.getSetting('onBeforeRemoveCellClassNames');
  if (Array.isArray(classesToRemove)) {
    for (let i = 0; i < classesToRemove.length; i++) {
      appliedOverlaysClasses.add(classesToRemove[i]);
    }
  }
  appliedOverlaysClasses.forEach(className => {
    var _classPrivateFieldGet6, _classPrivateFieldGet7;
    const nodes = _classPrivateFieldGet(this, _activeOverlaysWot).wtTable.TABLE.querySelectorAll(`.${className}`);
    let cellAttributes = [];
    if (Array.isArray((_classPrivateFieldGet6 = _classPrivateFieldGet(this, _selections).options) === null || _classPrivateFieldGet6 === void 0 ? void 0 : _classPrivateFieldGet6.cellAttributes)) {
      cellAttributes = _classPrivateFieldGet(this, _selections).options.cellAttributes.map(el => el[0]);
    }
    if (Array.isArray((_classPrivateFieldGet7 = _classPrivateFieldGet(this, _selections).options) === null || _classPrivateFieldGet7 === void 0 ? void 0 : _classPrivateFieldGet7.headerAttributes)) {
      cellAttributes = [...cellAttributes, ..._classPrivateFieldGet(this, _selections).options.headerAttributes.map(el => el[0])];
    }
    for (let i = 0, len = nodes.length; i < len; i++) {
      (0, _element.removeClass)(nodes[i], className);
      (0, _element.removeAttribute)(nodes[i], cellAttributes);
    }
  });
  appliedOverlaysClasses.clear();
}