"use strict";

exports.__esModule = true;
require("core-js/modules/es.array.push.js");
require("core-js/modules/es.error.cause.js");
var _element = require("../../../helpers/dom/element");
var _object = require("../../../helpers/object");
var _array = require("../../../helpers/array");
var _unicode = require("../../../helpers/unicode");
var _function = require("../../../helpers/function");
var _data = require("../../../helpers/data");
var C = _interopRequireWildcard(require("../../../i18n/constants"));
var _event = require("../../../helpers/dom/event");
var _base = require("./_base");
var _input = require("./input");
var _link = require("./link");
var _utils = require("../utils");
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
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; } }
const SHORTCUTS_GROUP = 'multipleSelect.itemBox';

/**
 * @private
 * @class MultipleSelectUI
 */
var _items = /*#__PURE__*/new WeakMap();
var _itemsBox = /*#__PURE__*/new WeakMap();
var _locale = /*#__PURE__*/new WeakMap();
var _searchInput = /*#__PURE__*/new WeakMap();
var _selectAllUI = /*#__PURE__*/new WeakMap();
var _clearAllUI = /*#__PURE__*/new WeakMap();
var _onInput = /*#__PURE__*/new WeakSet();
var _onInputKeyDown = /*#__PURE__*/new WeakSet();
var _onSelectAllClick = /*#__PURE__*/new WeakSet();
var _onClearAllClick = /*#__PURE__*/new WeakSet();
class MultipleSelectUI extends _base.BaseUI {
  static get DEFAULTS() {
    return (0, _object.clone)({
      className: 'htUIMultipleSelect',
      value: []
    });
  }

  /**
   * List of available select options.
   *
   * @type {Array}
   */

  constructor(hotInstance, options) {
    super(hotInstance, (0, _object.extend)(MultipleSelectUI.DEFAULTS, options));
    /**
     * On click listener for "Clear" link.
     *
     * @param {DOMEvent} event The mouse event object.
     */
    _classPrivateMethodInitSpec(this, _onClearAllClick);
    /**
     * On click listener for "Select all" link.
     *
     * @param {DOMEvent} event The mouse event object.
     */
    _classPrivateMethodInitSpec(this, _onSelectAllClick);
    /**
     * 'keydown' event listener for input element.
     *
     * @param {Event} event DOM event.
     */
    _classPrivateMethodInitSpec(this, _onInputKeyDown);
    /**
     * 'input' event listener for input element.
     *
     * @param {Event} event DOM event.
     */
    _classPrivateMethodInitSpec(this, _onInput);
    _classPrivateFieldInitSpec(this, _items, {
      writable: true,
      value: []
    });
    /**
     * Handsontable instance used as items list element.
     *
     * @type {Handsontable}
     */
    _classPrivateFieldInitSpec(this, _itemsBox, {
      writable: true,
      value: void 0
    });
    /**
     * A locale for the component used to compare filtered values.
     *
     * @type {string}
     */
    _classPrivateFieldInitSpec(this, _locale, {
      writable: true,
      value: void 0
    });
    /**
     * Input element.
     *
     * @type {InputUI}
     */
    _classPrivateFieldInitSpec(this, _searchInput, {
      writable: true,
      value: void 0
    });
    /**
     * "Select all" UI element.
     *
     * @type {LinkUI}
     */
    _classPrivateFieldInitSpec(this, _selectAllUI, {
      writable: true,
      value: void 0
    });
    /**
     * "Clear" UI element.
     *
     * @type {LinkUI}
     */
    _classPrivateFieldInitSpec(this, _clearAllUI, {
      writable: true,
      value: void 0
    });
    _classPrivateFieldSet(this, _searchInput, new _input.InputUI(this.hot, {
      placeholder: C.FILTERS_BUTTONS_PLACEHOLDER_SEARCH,
      className: 'htUIMultipleSelectSearch'
    }));
    _classPrivateFieldSet(this, _selectAllUI, new _link.LinkUI(this.hot, {
      textContent: C.FILTERS_BUTTONS_SELECT_ALL,
      className: 'htUISelectAll'
    }));
    _classPrivateFieldSet(this, _clearAllUI, new _link.LinkUI(this.hot, {
      textContent: C.FILTERS_BUTTONS_CLEAR,
      className: 'htUIClearAll'
    }));
    this.registerHooks();
  }

  /**
   * Gets the instance of the internal Handsontable that acts here as a listbox component.
   *
   * @returns {Handsontable}
   */
  getItemsBox() {
    return _classPrivateFieldGet(this, _itemsBox);
  }

  /**
   * Register all necessary hooks.
   */
  registerHooks() {
    _classPrivateFieldGet(this, _searchInput).addLocalHook('keydown', event => _classPrivateMethodGet(this, _onInputKeyDown, _onInputKeyDown2).call(this, event));
    _classPrivateFieldGet(this, _searchInput).addLocalHook('input', event => _classPrivateMethodGet(this, _onInput, _onInput2).call(this, event));
    _classPrivateFieldGet(this, _selectAllUI).addLocalHook('click', event => _classPrivateMethodGet(this, _onSelectAllClick, _onSelectAllClick2).call(this, event));
    _classPrivateFieldGet(this, _clearAllUI).addLocalHook('click', event => _classPrivateMethodGet(this, _onClearAllClick, _onClearAllClick2).call(this, event));
  }

  /**
   * Set available options.
   *
   * @param {Array} items Array of objects with `checked` and `label` property.
   */
  setItems(items) {
    _classPrivateFieldSet(this, _items, items);
    if (_classPrivateFieldGet(this, _itemsBox)) {
      _classPrivateFieldGet(this, _itemsBox).loadData(_classPrivateFieldGet(this, _items));
    }
  }

  /**
   * Set a locale for the component.
   *
   * @param {string} locale Locale used for filter actions performed on data, ie. `en-US`.
   */
  setLocale(locale) {
    _classPrivateFieldSet(this, _locale, locale);
  }

  /**
   * Get a locale for the component.
   *
   * @returns {string}
   */
  getLocale() {
    return _classPrivateFieldGet(this, _locale);
  }

  /**
   * Get all available options.
   *
   * @returns {Array}
   */
  getItems() {
    return [..._classPrivateFieldGet(this, _items)];
  }

  /**
   * Get element value.
   *
   * @returns {Array} Array of selected values.
   */
  getValue() {
    return itemsToValue(_classPrivateFieldGet(this, _items));
  }

  /**
   * Gets the instance of the search input element.
   *
   * @returns {InputUI}
   */
  getSearchInputElement() {
    return _classPrivateFieldGet(this, _searchInput);
  }

  /**
   * Gets the instance of the "select all" link element.
   *
   * @returns {LinkUI}
   */
  getSelectAllElement() {
    return _classPrivateFieldGet(this, _selectAllUI);
  }

  /**
   * Gets the instance of the "clear" link element.
   *
   * @returns {LinkUI}
   */
  getClearAllElement() {
    return _classPrivateFieldGet(this, _clearAllUI);
  }

  /**
   * Check if all values listed in element are selected.
   *
   * @returns {boolean}
   */
  isSelectedAllValues() {
    return _classPrivateFieldGet(this, _items).length === this.getValue().length;
  }

  /**
   * Build DOM structure.
   */
  build() {
    super.build();
    const {
      rootDocument
    } = this.hot;
    const itemsBoxWrapper = rootDocument.createElement('div');
    const selectionControl = new _base.BaseUI(this.hot, {
      className: 'htUISelectionControls',
      children: [_classPrivateFieldGet(this, _selectAllUI), _classPrivateFieldGet(this, _clearAllUI)]
    });
    this._element.appendChild(_classPrivateFieldGet(this, _searchInput).element);
    this._element.appendChild(selectionControl.element);
    this._element.appendChild(itemsBoxWrapper);
    const hotInitializer = wrapper => {
      if (!this._element) {
        return;
      }
      if (_classPrivateFieldGet(this, _itemsBox)) {
        _classPrivateFieldGet(this, _itemsBox).destroy();
      }
      (0, _element.addClass)(wrapper, 'htUIMultipleSelectHot');
      // Constructs and initializes a new Handsontable instance
      _classPrivateFieldSet(this, _itemsBox, new this.hot.constructor(wrapper, {
        data: _classPrivateFieldGet(this, _items),
        columns: [{
          data: 'checked',
          type: 'checkbox',
          label: {
            property: 'visualValue',
            position: 'after'
          }
        }],
        beforeRenderer: (TD, row, col, prop, value, cellProperties) => {
          TD.title = cellProperties.instance.getDataAtRowProp(row, cellProperties.label.property);
        },
        afterListen: () => {
          this.runLocalHooks('focus', this);
        },
        beforeOnCellMouseUp: () => {
          _classPrivateFieldGet(this, _itemsBox).listen();
        },
        maxCols: 1,
        autoWrapCol: true,
        height: 110,
        // Workaround for #151.
        colWidths: () => _classPrivateFieldGet(this, _itemsBox).container.scrollWidth - (0, _element.getScrollbarWidth)(rootDocument),
        copyPaste: false,
        disableVisualSelection: 'area',
        fillHandle: false,
        fragmentSelection: 'cell',
        tabMoves: {
          row: 1,
          col: 0
        },
        layoutDirection: this.hot.isRtl() ? 'rtl' : 'ltr'
      }));
      _classPrivateFieldGet(this, _itemsBox).init();
      const shortcutManager = _classPrivateFieldGet(this, _itemsBox).getShortcutManager();
      const gridContext = shortcutManager.getContext('grid');
      gridContext.removeShortcutsByKeys(['Tab']);
      gridContext.removeShortcutsByKeys(['Shift', 'Tab']);
      gridContext.addShortcut({
        keys: [['Escape']],
        callback: event => {
          this.runLocalHooks('keydown', event, this);
        },
        group: SHORTCUTS_GROUP
      });
      gridContext.addShortcut({
        keys: [['Tab'], ['Shift', 'Tab']],
        callback: event => {
          _classPrivateFieldGet(this, _itemsBox).deselectCell();
          this.runLocalHooks('keydown', event, this);
          this.runLocalHooks('listTabKeydown', event, this);
        },
        group: SHORTCUTS_GROUP
      });
    };
    hotInitializer(itemsBoxWrapper);
    this.hot._registerTimeout(() => hotInitializer(itemsBoxWrapper), 100);
  }

  /**
   * Focus element.
   */
  focus() {
    if (this.isBuilt()) {
      _classPrivateFieldGet(this, _itemsBox).listen();
    }
  }

  /**
   * Reset DOM structure.
   */
  reset() {
    _classPrivateFieldGet(this, _searchInput).reset();
    _classPrivateFieldGet(this, _selectAllUI).reset();
    _classPrivateFieldGet(this, _clearAllUI).reset();
  }

  /**
   * Update DOM structure.
   */
  update() {
    if (!this.isBuilt()) {
      return;
    }
    _classPrivateFieldGet(this, _itemsBox).loadData(valueToItems(_classPrivateFieldGet(this, _items), this.options.value));
    super.update();
  }

  /**
   * Destroy instance.
   */
  destroy() {
    if (_classPrivateFieldGet(this, _itemsBox)) {
      _classPrivateFieldGet(this, _itemsBox).destroy();
    }
    _classPrivateFieldGet(this, _searchInput).destroy();
    _classPrivateFieldGet(this, _clearAllUI).destroy();
    _classPrivateFieldGet(this, _selectAllUI).destroy();
    _classPrivateFieldSet(this, _searchInput, null);
    _classPrivateFieldSet(this, _clearAllUI, null);
    _classPrivateFieldSet(this, _selectAllUI, null);
    _classPrivateFieldSet(this, _itemsBox, null);
    _classPrivateFieldSet(this, _items, null);
    super.destroy();
  }
}
exports.MultipleSelectUI = MultipleSelectUI;
function _onInput2(event) {
  const value = event.target.value.toLocaleLowerCase(this.getLocale());
  let filteredItems;
  if (value === '') {
    filteredItems = [..._classPrivateFieldGet(this, _items)];
  } else {
    filteredItems = (0, _array.arrayFilter)(_classPrivateFieldGet(this, _items), item => `${item.value}`.toLocaleLowerCase(this.getLocale()).indexOf(value) >= 0);
  }
  _classPrivateFieldGet(this, _itemsBox).loadData(filteredItems);
}
function _onInputKeyDown2(event) {
  this.runLocalHooks('keydown', event, this);
  const isKeyCode = (0, _function.partial)(_unicode.isKey, event.keyCode);
  if (isKeyCode('ARROW_DOWN')) {
    event.preventDefault();
    (0, _event.stopImmediatePropagation)(event);
    _classPrivateFieldGet(this, _itemsBox).listen();
    _classPrivateFieldGet(this, _itemsBox).selectCell(0, 0);
  }
}
function _onSelectAllClick2(event) {
  const changes = [];
  event.preventDefault();
  (0, _array.arrayEach)(_classPrivateFieldGet(this, _itemsBox).getSourceData(), (row, rowIndex) => {
    row.checked = true;
    changes.push((0, _data.dataRowToChangesArray)(row, rowIndex)[0]);
  });
  _classPrivateFieldGet(this, _itemsBox).setSourceDataAtCell(changes);
}
function _onClearAllClick2(event) {
  const changes = [];
  event.preventDefault();
  (0, _array.arrayEach)(_classPrivateFieldGet(this, _itemsBox).getSourceData(), (row, rowIndex) => {
    row.checked = false;
    changes.push((0, _data.dataRowToChangesArray)(row, rowIndex)[0]);
  });
  _classPrivateFieldGet(this, _itemsBox).setSourceDataAtCell(changes);
}
var _default = MultipleSelectUI;
/**
 * Pick up object items based on selected values.
 *
 * @param {Array} availableItems Base collection to compare values.
 * @param {Array} selectedValue Flat array with selected values.
 * @returns {Array}
 */
exports.default = _default;
function valueToItems(availableItems, selectedValue) {
  const arrayAssertion = (0, _utils.createArrayAssertion)(selectedValue);
  return (0, _array.arrayMap)(availableItems, item => {
    item.checked = arrayAssertion(item.value);
    return item;
  });
}

/**
 * Convert all checked items into flat array.
 *
 * @param {Array} availableItems Base collection.
 * @returns {Array}
 */
function itemsToValue(availableItems) {
  const items = [];
  (0, _array.arrayEach)(availableItems, item => {
    if (item.checked) {
      items.push(item.value);
    }
  });
  return items;
}