"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

exports.__esModule = true;
exports.default = void 0;

var _domLib = require("dom-lib");

var _react = require("react");

var _AutoScroller = _interopRequireDefault(require("./AutoScroller"));

var _utils = require("./utils");

var _useManager2 = _interopRequireDefault(require("./useManager"));

function _createForOfIteratorHelperLoose(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; return function () { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } it = o[Symbol.iterator](); return it.next.bind(it); }

function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }

function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }

var useSortHelper = function useSortHelper(config) {
  var autoScroll = config.autoScroll,
      pressDelay = config.pressDelay,
      transitionDuration = config.transitionDuration,
      onSort = config.onSort,
      onSortEnd = config.onSortEnd,
      onSortMove = config.onSortMove,
      onSortStart = config.onSortStart;

  var _useState = (0, _react.useState)(false),
      sorting = _useState[0],
      setSorting = _useState[1];

  var containerRef = (0, _react.useRef)(null);
  var pressTimer = (0, _react.useRef)();

  var _useManager = (0, _useManager2.default)(),
      listItemRegister = _useManager.listItemRegister,
      getManagedItem = _useManager.getManagedItem,
      getOrderedItems = _useManager.getOrderedItems;
  /**
   * start dragging
   * */


  var handlePress = (0, _react.useCallback)(function (mouseDownEvent, targetNode, curManagedItem) {
    var _activeNodeHelper;

    var listItemBaseClassName = targetNode.classList[0]; // get list item base className

    var helperElementClass = listItemBaseClassName + "-helper";
    var holderElementClass = listItemBaseClassName + "-holder"; // data

    var containerElement = containerRef.current;
    var activeNode = curManagedItem.node;
    var activeNodeOldIndex = curManagedItem.info.index;
    var activeNodeNextIndex = curManagedItem.info.index;
    var activeNodeHolderTranslate = {
      x: 0,
      y: 0
    };
    var animatedNodesOffset = []; // all list item offset
    // init scroller

    var scrollContainer = (0, _utils.getScrollingParent)(containerElement) || containerElement;
    var autoScroller = new _AutoScroller.default(scrollContainer, function (offset) {
      activeNodeHolderTranslate.x += offset.left;
      activeNodeHolderTranslate.y += offset.top;
    });
    var activeNodeBoundingClientRect = activeNode.getBoundingClientRect();
    var activeNodeOffsetEdge = (0, _utils.getEdgeOffset)(activeNode, containerElement);
    var activeNodeStyle = getComputedStyle(activeNode);
    var activeNodeHelper = activeNode.cloneNode(true);
    (_activeNodeHelper = activeNodeHelper) === null || _activeNodeHelper === void 0 ? void 0 : _activeNodeHelper.classList.add(helperElementClass);
    (0, _utils.setInlineStyles)(activeNodeHelper, {
      position: 'fixed',
      width: activeNodeBoundingClientRect.width + "px",
      height: activeNodeBoundingClientRect.height + "px",
      left: activeNodeBoundingClientRect.left - parseFloat(activeNodeStyle.marginLeft) + "px",
      top: activeNodeBoundingClientRect.top - parseFloat(activeNodeStyle.marginTop) + "px"
    });
    activeNode.classList.add(holderElementClass);
    document.body.appendChild(activeNodeHelper);

    var getContainerScrollDelta = function getContainerScrollDelta() {
      return {
        left: scrollContainer.scrollLeft - scrollContainer.scrollLeft,
        top: scrollContainer.scrollTop - scrollContainer.scrollTop
      };
    };

    var getHolderTranslate = function getHolderTranslate() {
      return animatedNodesOffset.reduce(function (acc, item) {
        return {
          x: acc.x + item.x,
          y: acc.y + item.y
        };
      }, {
        x: 0,
        y: 0
      });
    };

    var sortMouseMoveListener = (0, _domLib.on)(window, 'mousemove', function (mouseOverEvent) {
      // Update helper position
      var offset = {
        x: (mouseOverEvent === null || mouseOverEvent === void 0 ? void 0 : mouseOverEvent.pageX) || 0,
        y: (mouseOverEvent === null || mouseOverEvent === void 0 ? void 0 : mouseOverEvent.pageY) || 0
      };
      var containerScrollDelta = getContainerScrollDelta();
      var containerBoundingRect = scrollContainer.getBoundingClientRect();
      activeNodeHolderTranslate = {
        x: offset.x - mouseDownEvent.pageX,
        y: offset.y - mouseDownEvent.pageY
      };
      (0, _utils.setTranslate3d)(activeNodeHelper, activeNodeHolderTranslate); // animate

      activeNodeNextIndex = -1;
      var listItemManagerRefs = getOrderedItems(curManagedItem.info.collection);
      var sortingOffsetY = activeNodeOffsetEdge.top + activeNodeHolderTranslate.y + containerScrollDelta.top;
      var activeNodeHeight = parseFloat(activeNodeStyle.height) || 0;

      for (var i = 0, len = listItemManagerRefs.length; i < len; i++) {
        var currentNode = listItemManagerRefs[i].node;
        var currentNodeIndex = listItemManagerRefs[i].info.index;
        var offsetY = activeNodeBoundingClientRect.height > currentNode.offsetHeight ? currentNode.offsetHeight / 2 : activeNodeBoundingClientRect.height / 2;
        var translate = {
          x: 0,
          y: 0
        }; // If we haven't cached the node's offsetTop / offsetLeft value

        var curEdgeOffset = listItemManagerRefs[i].edgeOffset || (0, _utils.getEdgeOffset)(currentNode, containerElement);
        listItemManagerRefs[i].edgeOffset = curEdgeOffset; // Get a reference to the next node

        var prvNode = i > 0 && listItemManagerRefs[i - 1];
        var nextNode = i < len - 1 && listItemManagerRefs[i + 1]; // Also cache the node's edge offset if needed.

        if (prvNode && !prvNode.edgeOffset) {
          prvNode.edgeOffset = (0, _utils.getEdgeOffset)(prvNode.node, containerElement);
        }

        if (nextNode && !nextNode.edgeOffset) {
          nextNode.edgeOffset = (0, _utils.getEdgeOffset)(nextNode.node, containerElement);
        } // If the node is the one we're currently animating, skip it


        if (currentNodeIndex === activeNodeOldIndex) {
          continue;
        }

        if (prvNode && currentNodeIndex > activeNodeOldIndex && sortingOffsetY + offsetY >= curEdgeOffset.top) {
          translate.y = -activeNodeHeight;
          animatedNodesOffset[currentNodeIndex] = {
            x: 0,
            y: currentNode.offsetHeight
          };
          activeNodeNextIndex = currentNodeIndex;
        } else if (nextNode && currentNodeIndex < activeNodeOldIndex && sortingOffsetY <= curEdgeOffset.top + offsetY) {
          translate.y = activeNodeHeight;
          animatedNodesOffset[currentNodeIndex] = {
            x: 0,
            y: -currentNode.offsetHeight
          };

          if (activeNodeNextIndex === -1) {
            activeNodeNextIndex = currentNodeIndex;
          }
        } else {
          animatedNodesOffset[currentNodeIndex] = {
            x: 0,
            y: 0
          };
        }

        (0, _utils.setTransitionDuration)(currentNode, transitionDuration);
        (0, _utils.setTranslate3d)(currentNode, translate); // translate holder

        (0, _utils.setTranslate3d)(activeNode, getHolderTranslate());
      }

      if (activeNodeNextIndex === -1) {
        activeNodeNextIndex = activeNodeOldIndex;
      } // auto scroll


      if (autoScroll) {
        autoScroller.update({
          width: activeNodeBoundingClientRect.width,
          height: activeNodeBoundingClientRect.height,
          translate: activeNodeHolderTranslate,
          maxTranslate: {
            y: containerBoundingRect.top + containerBoundingRect.height - activeNodeBoundingClientRect.top - activeNodeBoundingClientRect.height / 2
          },
          minTranslate: {
            y: containerBoundingRect.top - activeNodeBoundingClientRect.top - activeNodeBoundingClientRect.height / 2
          }
        });
      }

      onSortMove === null || onSortMove === void 0 ? void 0 : onSortMove({
        collection: curManagedItem.info.collection,
        node: activeNode,
        oldIndex: activeNodeOldIndex,
        newIndex: activeNodeNextIndex
      }, mouseOverEvent);
    }, {
      passive: false
    });
    var sortMouseEndListener = (0, _domLib.on)(window, 'mouseup', function (event) {
      // Remove the event listeners
      sortMouseMoveListener.off();
      sortMouseEndListener.off();
      var holderTranslate = getHolderTranslate();
      var containerScrollDelta = getContainerScrollDelta();
      (0, _utils.setTranslate3d)(activeNodeHelper, {
        x: holderTranslate.x - containerScrollDelta.left,
        y: holderTranslate.y - containerScrollDelta.top
      });
      (0, _utils.setTransitionDuration)(activeNodeHelper, transitionDuration); // wait for animation

      setTimeout(function () {
        var _activeNodeHelper2, _activeNodeHelper2$pa;

        // Remove the helper from the DOM
        (_activeNodeHelper2 = activeNodeHelper) === null || _activeNodeHelper2 === void 0 ? void 0 : (_activeNodeHelper2$pa = _activeNodeHelper2.parentNode) === null || _activeNodeHelper2$pa === void 0 ? void 0 : _activeNodeHelper2$pa.removeChild(activeNodeHelper);
        activeNodeHelper = null; // Remove redundant styles

        activeNode.classList.remove(holderElementClass);
        (0, _utils.setTranslate3d)(activeNode, null);
        animatedNodesOffset = [];

        for (var _iterator = _createForOfIteratorHelperLoose(getOrderedItems(curManagedItem.info.collection)), _step; !(_step = _iterator()).done;) {
          var item = _step.value;
          // Clear the cached offsetTop / offsetLeft value
          item.edgeOffset = null; // Remove the transforms / transitions

          var el = item.node;
          (0, _utils.setTranslate3d)(el, null);
          (0, _utils.setTransitionDuration)(el, null);
        } // Stop autoScroll


        autoScroller.clear(); // Update manager state

        setSorting(false); // callbacks

        var callbackPayload = {
          collection: curManagedItem.info.collection,
          node: curManagedItem.node,
          newIndex: activeNodeNextIndex,
          oldIndex: activeNodeOldIndex
        };
        onSortEnd === null || onSortEnd === void 0 ? void 0 : onSortEnd(callbackPayload, event);
        onSort === null || onSort === void 0 ? void 0 : onSort(callbackPayload, event);
      }, transitionDuration);
    }, {
      passive: false
    });
    setSorting(true); // start callback

    onSortStart === null || onSortStart === void 0 ? void 0 : onSortStart({
      collection: curManagedItem.info.collection,
      node: activeNode,
      oldIndex: activeNodeOldIndex,
      newIndex: activeNodeNextIndex
    }, mouseDownEvent.nativeEvent);
  }, [autoScroll, getOrderedItems, onSort, onSortEnd, onSortMove, onSortStart, transitionDuration]);
  /**
   * Determine whether to start dragging
   * */

  var handleStart = (0, _react.useCallback)(function (mouseDownEvent) {
    var triggeredNode = mouseDownEvent.target;
    var targetNode = (0, _utils.closestNode)(triggeredNode, function (el) {
      return Boolean(getManagedItem(el));
    });
    var curManagedItem = getManagedItem(targetNode);

    if ( // is not secondary button pressed
    mouseDownEvent.button !== 2 && // is list item
    Boolean(curManagedItem) && !curManagedItem.info.disabled && // is not sorting
    !sorting && // is valid node
    targetNode instanceof HTMLElement && // excludes interactive elements
    !targetNode.contains((0, _utils.closestNode)(triggeredNode, _utils.isContainInteractiveElement))) {
      mouseDownEvent.preventDefault();
      pressTimer.current = setTimeout(handlePress, pressDelay, mouseDownEvent, targetNode, curManagedItem);
    }
  }, [getManagedItem, handlePress, pressDelay, sorting]);
  /**
   * Clear timer after drag
   * */

  var handleEnd = (0, _react.useCallback)(function () {
    return clearTimeout(pressTimer.current);
  }, []);
  return {
    handleStart: handleStart,
    handleEnd: handleEnd,
    containerRef: containerRef,
    sorting: sorting,
    register: listItemRegister
  };
};

var _default = useSortHelper;
exports.default = _default;