'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var _rollupPluginBabelHelpers = require('../../../_virtual/_rollupPluginBabelHelpers.js');
var treePathReducer = require('../reducers/treePathReducer.js');
var getItemByFocused = require('../utils/getItemByFocused.js');

var JUMP_SIZE = 10;
var keys = {
  Enter: 'Enter',
  Space: 'Space',
  Tab: 'Tab',
  Escape: 'Escape',
  Backspace: 'Backspace',
  ArrowLeft: 'ArrowLeft',
  ArrowRight: 'ArrowRight',
  ArrowUp: 'ArrowUp',
  ArrowDown: 'ArrowDown',
  Home: 'Home',
  End: 'End',
  PageUp: 'PageUp',
  PageDown: 'PageDown'
};
var openListWithInitialFocus = function openListWithInitialFocus(dispatchPath, dispatchFocusedPath, handleListToggle) {
  dispatchPath({
    type: 'opened_first_level'
  });
  dispatchFocusedPath({
    type: 'set_initial_focus'
  });
  handleListToggle(true);
};
var collapseNestedPath = function collapseNestedPath(path, focusedPath, dispatchPath) {
  if (path.length > focusedPath.length) {
    dispatchPath({
      type: 'removed_last_level'
    });
  }
};

// #TODO: подумать над идеей выноса логики фокуса непосредственно в focusedPathReducer.
var useKeyNavigation = function useKeyNavigation(_ref) {
  var focusedPath = _ref.focusedPath,
    dispatchFocusedPath = _ref.dispatchFocusedPath,
    path = _ref.path,
    dispatchPath = _ref.dispatchPath,
    pathMap = _ref.pathMap,
    focusedToValueMap = _ref.focusedToValueMap,
    handleListToggle = _ref.handleListToggle,
    handlePressDown = _ref.handlePressDown,
    treePath = _ref.treePath,
    dispatchTreePath = _ref.dispatchTreePath,
    treeView = _ref.treeView,
    valueToPathMap = _ref.valueToPathMap,
    items = _ref.items,
    disabled = _ref.disabled,
    readOnly = _ref.readOnly;
  if (treeView) {
    return keyboardNavigationTree({
      focusedPath: focusedPath,
      dispatchFocusedPath: dispatchFocusedPath,
      path: path,
      dispatchPath: dispatchPath,
      pathMap: pathMap,
      focusedToValueMap: focusedToValueMap,
      handleListToggle: handleListToggle,
      handlePressDown: handlePressDown,
      treePath: treePath,
      dispatchTreePath: dispatchTreePath,
      treeView: treeView,
      valueToPathMap: valueToPathMap,
      items: items,
      disabled: disabled,
      readOnly: readOnly
    });
  }
  return keyboardNavigationDefault({
    focusedPath: focusedPath,
    dispatchFocusedPath: dispatchFocusedPath,
    path: path,
    dispatchPath: dispatchPath,
    pathMap: pathMap,
    focusedToValueMap: focusedToValueMap,
    handleListToggle: handleListToggle,
    handlePressDown: handlePressDown,
    treePath: treePath,
    dispatchTreePath: dispatchTreePath,
    treeView: treeView,
    valueToPathMap: valueToPathMap,
    items: items,
    disabled: disabled,
    readOnly: readOnly
  });
};
var keyboardNavigationDefault = function keyboardNavigationDefault(_ref2) {
  var focusedPath = _ref2.focusedPath,
    dispatchFocusedPath = _ref2.dispatchFocusedPath,
    path = _ref2.path,
    dispatchPath = _ref2.dispatchPath,
    pathMap = _ref2.pathMap,
    focusedToValueMap = _ref2.focusedToValueMap,
    handleListToggle = _ref2.handleListToggle,
    handlePressDown = _ref2.handlePressDown,
    disabled = _ref2.disabled,
    readOnly = _ref2.readOnly;
  var currentIndex = (focusedPath === null || focusedPath === void 0 ? void 0 : focusedPath[focusedPath.length - 1]) || 0;
  var currentLength = pathMap.get(path === null || path === void 0 ? void 0 : path[focusedPath.length - 1]) || 0;
  var onKeyDown = function onKeyDown(event) {
    if (disabled || readOnly) {
      return;
    }
    switch (event.code) {
      case keys.ArrowUp:
        {
          if (focusedPath.length) {
            if (currentIndex > 0) {
              collapseNestedPath(path, focusedPath, dispatchPath);
              dispatchFocusedPath({
                type: 'change_last_focus',
                value: currentIndex - 1
              });
            }
          } else {
            openListWithInitialFocus(dispatchPath, dispatchFocusedPath, handleListToggle);
          }
          break;
        }
      case keys.ArrowDown:
        {
          if (focusedPath.length) {
            if (currentIndex + 1 < currentLength) {
              collapseNestedPath(path, focusedPath, dispatchPath);
              dispatchFocusedPath({
                type: 'change_last_focus',
                value: currentIndex + 1
              });
            }
          } else {
            openListWithInitialFocus(dispatchPath, dispatchFocusedPath, handleListToggle);
          }
          break;
        }
      case keys.ArrowLeft:
        {
          if (path[0]) {
            if (focusedPath.length) {
              if (path.length > focusedPath.length) {
                dispatchPath({
                  type: 'removed_last_level'
                });
              } else {
                dispatchFocusedPath({
                  type: 'return_prev_focus'
                });
              }
            }
            if (path.length === 1) {
              handleListToggle(false);
            }
          }
          break;
        }
      case keys.ArrowRight:
        {
          if (path[0]) {
            if (!focusedPath.length) {
              break;
            }
            var currentItem = getItemByFocused.getItemByFocused(focusedPath, focusedToValueMap);
            if (currentItem !== null && currentItem !== void 0 && currentItem.disabled) {
              break;
            }
            if (currentItem !== null && currentItem !== void 0 && currentItem.items) {
              if (path.length > focusedPath.length) {
                dispatchFocusedPath({
                  type: 'add_focus',
                  value: 0
                });
              } else {
                dispatchPath({
                  type: 'added_next_level',
                  value: currentItem.value.toString()
                });
              }
            }
          }
          break;
        }
      case keys.Space:
        {
          event.preventDefault();
          var _currentItem = getItemByFocused.getItemByFocused(focusedPath, focusedToValueMap);
          if (!path[0]) {
            dispatchPath({
              type: 'opened_first_level'
            });
            dispatchFocusedPath({
              type: 'set_initial_focus'
            });
            break;
          }
          if (!_currentItem || _currentItem !== null && _currentItem !== void 0 && _currentItem.disabled) {
            break;
          }
          handlePressDown(_currentItem);
          break;
        }
      case keys.Enter:
        {
          event.preventDefault();
          var _currentItem2 = getItemByFocused.getItemByFocused(focusedPath, focusedToValueMap);
          if (!path[0]) {
            dispatchPath({
              type: 'opened_first_level'
            });
            dispatchFocusedPath({
              type: 'set_initial_focus'
            });
            break;
          }
          if (!_currentItem2 || _currentItem2.disabled) {
            break;
          }
          if (_currentItem2 !== null && _currentItem2 !== void 0 && _currentItem2.items) {
            if (path.length > focusedPath.length) {
              dispatchFocusedPath({
                type: 'add_focus',
                value: 0
              });
            } else {
              dispatchPath({
                type: 'added_next_level',
                value: _currentItem2.value.toString()
              });
            }
            break;
          }
          handlePressDown(_currentItem2);
          break;
        }
      case keys.Tab:
      case keys.Escape:
        {
          if (path[0]) {
            handleListToggle(false);
          }
          break;
        }
      case keys.Home:
        {
          if (path[0]) {
            collapseNestedPath(path, focusedPath, dispatchPath);
            dispatchFocusedPath({
              type: 'change_last_focus',
              value: 0
            });
          } else {
            openListWithInitialFocus(dispatchPath, dispatchFocusedPath, handleListToggle);
          }
          break;
        }
      case keys.End:
        {
          if (path[0]) {
            collapseNestedPath(path, focusedPath, dispatchPath);
            dispatchFocusedPath({
              type: 'change_last_focus',
              value: currentLength - 1
            });
          } else {
            dispatchPath({
              type: 'opened_first_level'
            });
            dispatchFocusedPath({
              type: 'change_last_focus',
              value: (pathMap.get('root') || 0) - 1
            });
            handleListToggle(true);
          }
          break;
        }
      case keys.PageUp:
        {
          if (!path[0]) {
            break;
          }
          collapseNestedPath(path, focusedPath, dispatchPath);
          if (currentIndex <= JUMP_SIZE) {
            dispatchFocusedPath({
              type: 'change_last_focus',
              value: 0
            });
          } else {
            dispatchFocusedPath({
              type: 'change_last_focus',
              value: currentIndex - JUMP_SIZE
            });
          }
          break;
        }
      case keys.PageDown:
        {
          if (!path[0]) {
            break;
          }
          collapseNestedPath(path, focusedPath, dispatchPath);
          if (currentLength - currentIndex <= JUMP_SIZE) {
            dispatchFocusedPath({
              type: 'change_last_focus',
              value: currentLength - 1
            });
          } else {
            dispatchFocusedPath({
              type: 'change_last_focus',
              value: currentIndex + JUMP_SIZE
            });
          }
          break;
        }
    }
  };
  return {
    onKeyDown: onKeyDown
  };
};
var keyboardNavigationTree = function keyboardNavigationTree(_ref3) {
  var _currentItem$parent;
  var focusedPath = _ref3.focusedPath,
    dispatchFocusedPath = _ref3.dispatchFocusedPath,
    path = _ref3.path,
    dispatchPath = _ref3.dispatchPath,
    pathMap = _ref3.pathMap,
    focusedToValueMap = _ref3.focusedToValueMap,
    handleListToggle = _ref3.handleListToggle,
    handlePressDown = _ref3.handlePressDown,
    treePath = _ref3.treePath,
    dispatchTreePath = _ref3.dispatchTreePath,
    valueToPathMap = _ref3.valueToPathMap,
    items = _ref3.items,
    disabled = _ref3.disabled,
    readOnly = _ref3.readOnly;
  var currentItem = getItemByFocused.getItemByFocused(focusedPath, focusedToValueMap);
  var currentIndex = (focusedPath === null || focusedPath === void 0 ? void 0 : focusedPath[focusedPath.length - 1]) || 0;
  var currentLength = (currentItem === null || currentItem === void 0 || (_currentItem$parent = currentItem.parent) === null || _currentItem$parent === void 0 || (_currentItem$parent = _currentItem$parent.items) === null || _currentItem$parent === void 0 ? void 0 : _currentItem$parent.length) || pathMap.get('root') || 0;
  var isValidFocus = function isValidFocus(focusCandidate) {
    if (!Array.isArray(items) || !Array.isArray(focusCandidate)) return false;
    var currentLevel = items;
    var _iterator = _rollupPluginBabelHelpers.createForOfIteratorHelper(focusCandidate),
      _step;
    try {
      for (_iterator.s(); !(_step = _iterator.n()).done;) {
        var index = _step.value;
        if (!Array.isArray(currentLevel) || index >= currentLevel.length) {
          return false;
        }
        var node = currentLevel[index];
        currentLevel = node.items || [];
      }
    } catch (err) {
      _iterator.e(err);
    } finally {
      _iterator.f();
    }
    return true;
  };
  var onKeyDown = function onKeyDown(event) {
    if (disabled || readOnly) {
      return;
    }
    switch (event.code) {
      case keys.ArrowUp:
        {
          /**
           * Если список открыт и фокус уже установлен на каком-либо элементе.
           * */
          if (focusedPath.length) {
            /**
             * Если это не первый элемент, то нужно вначале найти элемент для фокуса.
             * Т.к. если верхний элемент раскрыт, то и перемещаться нужно не на него,
             * а на его самый нижний дочерний элемент.
             * */
            if (currentIndex > 0) {
              var nextFocus = [].concat(_rollupPluginBabelHelpers.toConsumableArray(focusedPath.slice(0, -1)), [currentIndex - 1]);
              while (nextFocus) {
                var focusedPathAsString = nextFocus.reduce(function (acc, n) {
                  return "".concat(acc, "/").concat(n);
                }, '').replace(/^(\/)/, '');
                var item = focusedToValueMap.get(focusedPathAsString);
                if (!item) {
                  break;
                }
                var isLevelOpened = treePathReducer.keyExists(treePath, valueToPathMap.get(item.value.toString()) || []);
                if (isLevelOpened) {
                  var _item$items;
                  nextFocus = [].concat(_rollupPluginBabelHelpers.toConsumableArray(nextFocus), [((item === null || item === void 0 || (_item$items = item.items) === null || _item$items === void 0 ? void 0 : _item$items.length) || 0) - 1]);
                } else {
                  break;
                }
              }
              dispatchFocusedPath({
                type: 'set_focus',
                value: nextFocus
              });
            } else {
              /**
               * Если элемент первый, то нужно лишь подняться к его родителю.
               * */
              dispatchFocusedPath({
                type: 'return_prev_focus'
              });
            }
          } else {
            /**
             * Если список закрыт, то нужно его открыть и установить фокус на первый элемент.
             * */
            openListWithInitialFocus(dispatchPath, dispatchFocusedPath, handleListToggle);
          }
          break;
        }
      case keys.ArrowDown:
        {
          /**
           * Если список открыт и фокус уже установлен на каком-либо элементе.
           * */
          if (focusedPath.length) {
            /**
             * Заходим сюда если у элемента есть другие вложенные элементы.
             * */
            if (currentItem !== null && currentItem !== void 0 && currentItem.items && currentItem !== null && currentItem !== void 0 && currentItem.items.length) {
              var isCurrentLevelOpened = treePathReducer.keyExists(treePath, valueToPathMap.get(currentItem.value.toString()) || []);

              /**
               * Если у этого элемента открыт его дочерний список,
               * то устанавливаем фокус на первый элемент из этого списка
               * и сразу же выходим из обработчика события.
               * */
              if (isCurrentLevelOpened) {
                dispatchFocusedPath({
                  type: 'add_focus',
                  value: 0
                });
                break;
              }
            }

            /**
             * Если мы еще не достигли конца списка, то движемся к следующему элементу.
             * */
            if (currentIndex + 1 < currentLength) {
              dispatchFocusedPath({
                type: 'change_last_focus',
                value: currentIndex + 1
              });
            } else {
              /**
               * Если же достигли последнего элемента на текущем уровне, то нужно определить,
               * на какой из элементов ниже мы перейдем.
               * Переход фокуса отсюда может быть только на уровни выше, при чем сразу на несколько.
               * */
              var focusCandidate = _rollupPluginBabelHelpers.toConsumableArray(focusedPath);
              var _nextFocus = null;
              while (focusCandidate.length > 1) {
                focusCandidate = [].concat(_rollupPluginBabelHelpers.toConsumableArray(focusCandidate.slice(0, -2)), [(focusCandidate.at(-2) || 0) + 1]);
                if (isValidFocus(focusCandidate)) {
                  _nextFocus = focusCandidate;
                  break;
                }
              }
              if (_nextFocus) {
                dispatchFocusedPath({
                  type: 'set_focus',
                  value: _nextFocus
                });
              } else {
                break;
              }
            }
          } else {
            /**
             * Если список закрыт, то нужно его открыть и установить фокус на первый элемент.
             * */
            openListWithInitialFocus(dispatchPath, dispatchFocusedPath, handleListToggle);
          }
          break;
        }
      case keys.ArrowLeft:
        {
          if (path[0]) {
            if (focusedPath.length) {
              dispatchTreePath({
                type: 'close_level',
                value: valueToPathMap.get((currentItem === null || currentItem === void 0 ? void 0 : currentItem.value.toString()) || '') || []
              });
            }
          }
          break;
        }
      case keys.ArrowRight:
        {
          if (path[0]) {
            if (!focusedPath.length || currentItem !== null && currentItem !== void 0 && currentItem.disabled || !(currentItem !== null && currentItem !== void 0 && currentItem.items)) {
              break;
            }
            dispatchTreePath({
              type: 'open_level',
              value: valueToPathMap.get(currentItem.value.toString()) || []
            });
          }
          break;
        }
      case keys.Space:
      case keys.Enter:
        {
          event.preventDefault();
          if (!path[0]) {
            dispatchPath({
              type: 'opened_first_level'
            });
            dispatchFocusedPath({
              type: 'set_initial_focus'
            });
            break;
          }
          if (!currentItem || currentItem !== null && currentItem !== void 0 && currentItem.disabled) {
            break;
          }
          handlePressDown(currentItem);
          break;
        }
      case keys.Tab:
      case keys.Escape:
        {
          if (path[0]) {
            handleListToggle(false);
          }
          break;
        }
    }
  };
  return {
    onKeyDown: onKeyDown
  };
};

exports.keys = keys;
exports.useKeyNavigation = useKeyNavigation;
