"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
exports.__esModule = true;
exports.NestedTableDragAndDropState = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _createOptimisticActionsOrderByModeReaction = require("../../state/DragAndDrop/createOptimisticActionsOrderByModeReaction");
var _DragAndDrop = require("../DragAndDrop");
var _mobx = require("mobx");
var _events = require("events");
class NestedTableDragAndDropState {
  constructor(params) {
    (0, _defineProperty2.default)(this, "tableState", void 0);
    (0, _defineProperty2.default)(this, "dnd", void 0);
    (0, _defineProperty2.default)(this, "nestedState", void 0);
    (0, _defineProperty2.default)(this, "_isExpandedBeforeDrag", void 0);
    (0, _defineProperty2.default)(this, "_onCancel", async () => {
      const {
        dragEventParentAndAfter,
        dragAndDropDisabled
      } = this;
      const {
        node,
        activeItem,
        overItem
      } = dragEventParentAndAfter;
      if (dragAndDropDisabled) {
        return true;
      }
      if (!node || !activeItem || !overItem || !activeItem.item.originalKeyedItem) {
        return null;
      }
      const dragEndEvent = this._createDragEndEvent();
      if (!dragEndEvent) {
        return null;
      }
      const {
        levelDescriptor
      } = activeItem.item.state;
      const shouldCancel = await (levelDescriptor.dragAndDropCancel == null ? void 0 : levelDescriptor.dragAndDropCancel(this._createSimpleDragEndEvent(dragEndEvent, node)));
      if (!shouldCancel) {
        return false;
      }
      this.dnd._maybeShowErrorToast(shouldCancel, dragEndEvent);
      return true;
    });
    const {
      nestedState
    } = params;
    const {
      container
    } = nestedState;
    this.tableState = nestedState.tableState;
    this.nestedState = nestedState;
    this.dnd = new _DragAndDrop.DragAndDropState({
      container,
      state: nestedState.wrapper.toolbar,
      collection: nestedState,
      move: () => this._move(),
      announcements: {
        dragHandleLabel: id => {
          var _nestedState$getKeyed, _item$originalKeyedIt;
          const {
            translate: t
          } = container;
          const item = (_nestedState$getKeyed = nestedState.getKeyedItem(id)) == null ? void 0 : _nestedState$getKeyed.item;
          const itemName = item == null ? void 0 : item.state.collection.itemName;
          return t('cairo.dragAndDrop.button-role-label.sr', {
            itemName: item && itemName ? itemName((_item$originalKeyedIt = item.originalKeyedItem) == null ? void 0 : _item$originalKeyedIt.item) : ''
          });
        },
        itemDescription: id => {
          var _nestedState$getKeyed2, _item$originalKeyedIt2;
          const item = (_nestedState$getKeyed2 = nestedState.getKeyedItem(id)) == null ? void 0 : _nestedState$getKeyed2.item;
          const itemName = item == null ? void 0 : item.state.collection.itemName;
          return item && itemName ? itemName((_item$originalKeyedIt2 = item.originalKeyedItem) == null ? void 0 : _item$originalKeyedIt2.item) : '';
        }
      }
    });
    this.dnd.events.on('dragStart', () => {
      const {
        activeNode
      } = this;
      this._isExpandedBeforeDrag = activeNode == null ? void 0 : activeNode.node._expanded;
      if (activeNode != null && activeNode.node._expanded) {
        activeNode.node._toggleExpand();
      }
    });
    this.dnd.onCancel = this._onCancel;
    (0, _mobx.makeObservable)(this, {
      dragEventItems: _mobx.computed,
      dragEventDirectionItems: _mobx.computed,
      dragEventDepth: _mobx.computed,
      activeNode: _mobx.computed,
      dragEventParentAndAfter: _mobx.computed,
      reachedMaxDepth: _mobx.computed,
      dragAndDropDisabled: _mobx.computed,
      _createDragEndEvent: _mobx.action,
      _move: _mobx.action
    });
  }
  _createNewParentData(node) {
    if (!node.parent || !node.parentNode) {
      return {};
    }
    return {
      parentItem: node.parent.item
    };
  }
  _createDragEndEvent({
    setNewParent = true
  } = {}) {
    var _node$parent;
    const {
      dragEventParentAndAfter,
      dnd,
      nestedState
    } = this;
    const {
      node,
      activeItem,
      after,
      overItem
    } = dragEventParentAndAfter;
    if (!node || !activeItem || !overItem || !activeItem.item.originalKeyedItem || !overItem.item.originalKeyedItem) {
      return null;
    }
    const {
      levelDescriptor
    } = activeItem.item.state;
    if (!levelDescriptor.setParent) {
      if (process.env.NODE_ENV !== 'production') {
        console.warn('setParent is not defined in levelDescriptor, skipping drag end event creation');
      }
      return null;
    }
    return {
      moveId: dnd._moveId,
      from: setNewParent ? {
        ...activeItem.item.originalKeyedItem,
        item: levelDescriptor.setParent(activeItem.item.originalKeyedItem.item, (_node$parent = node.parent) == null ? void 0 : _node$parent.id, this._createNewParentData(node))
      } : activeItem.item.originalKeyedItem,
      over: overItem.item.originalKeyedItem,
      after: after == null ? void 0 : after.item.originalKeyedItem,
      query: nestedState.query.asComputed,
      filtersKeyHash: nestedState.query.filtersKeyHash,
      isFromHandle: Boolean(dnd._isHandleActive)
    };
  }
  _createSimpleDragEndEvent(dragEndEvent, node) {
    var _node$parent2;
    const {
      dnd
    } = this;
    return {
      ...dnd._createSimpleDragEndEvent(dragEndEvent),
      parentId: (_node$parent2 = node.parent) == null ? void 0 : _node$parent2.id,
      node
    };
  }
  _move() {
    var _node$parentNode;
    const {
      dragEventParentAndAfter,
      nestedState,
      reachedMaxDepth,
      activeNode
    } = this;
    if (reachedMaxDepth) {
      if (activeNode && this._isExpandedBeforeDrag != null && this._isExpandedBeforeDrag !== activeNode.node._expanded) {
        activeNode._toggleExpand();
      }
      return;
    }
    const {
      node,
      activeItem,
      overItem
    } = dragEventParentAndAfter;
    if (!node || !activeItem || !overItem || !activeItem.item.originalKeyedItem) {
      return;
    }
    const dragEndEvent = this._createDragEndEvent();
    if (!dragEndEvent) {
      return;
    }

    /**
     * A submit function that will be shared between 3 optimistic actions.
     * How it works: The `dragAndDropSubmit` function provided by the consumer will be called only inside the `move` action submit function.
     * Using EventEmitter to resolve the promise only after the `move` action submit function completes.
     */

    const submitEvents = new _events.EventEmitter();
    const submit = () => new Promise((resolve, reject) => submitEvents.once('submit', err => err ? reject(err) : resolve()));
    activeItem.item.state.collection.optimisticActions.updateOne(dragEndEvent.from.item, {
      submit,
      keepPosition: true
    });
    if (activeItem.item.state === node || node.unprocessedMap.has(dragEndEvent.from.key)) {
      node.collection.optimisticActions.updateOne(dragEndEvent.from.item, {
        submit,
        keepPosition: true
      });
    } else {
      node.collection.optimisticActions.createOne(dragEndEvent.from.item, {
        submit
      });
    }
    node.collection.optimisticActions.move(dragEndEvent, {
      submit: async () => {
        const {
          levelDescriptor
        } = activeItem.item.state;
        try {
          await (levelDescriptor.dragAndDropSubmit == null ? void 0 : levelDescriptor.dragAndDropSubmit(this._createSimpleDragEndEvent(dragEndEvent, node)));
          submitEvents.emit('submit');
        } catch (e) {
          submitEvents.emit('submit', e);
          throw e;
        }
      },
      collectionSnapshot: nestedState.getCollectionSnapshot()
    });
    const nodeAfterMove = node.createNode({
      parent: activeItem.item.originalKeyedItem,
      notifyAll: true
    });
    if (nodeAfterMove && this._isExpandedBeforeDrag != null) {
      nodeAfterMove.node._expanded = this._isExpandedBeforeDrag;
    }
    node._notify();
    (_node$parentNode = node.parentNode) == null || _node$parentNode._notify();
    node._preRegisterAll();
  }
  getStickyColumnsCount({
    stickyColumns,
    horizontalScroll
  }) {
    const {
      dnd
    } = this;
    return horizontalScroll && !dnd.isDisabled ? stickyColumns + 1 : stickyColumns;
  }
  get dragEventItems() {
    const {
      dnd
    } = this;
    const {
      collection,
      activeId,
      overId
    } = dnd;
    if (!overId || !activeId) {
      return null;
    }
    const overItem = collection.getKeyedItem(overId);
    const activeItem = collection.getKeyedItem(activeId);
    if (activeItem == null || overItem == null) {
      return null;
    }
    return {
      overItem,
      activeItem
    };
  }
  get dragEventDirectionItems() {
    const {
      nestedState: {
        keyedItems: items
      },
      dragEventItems
    } = this;
    if (!dragEventItems) {
      return null;
    }
    const {
      overItem,
      activeItem
    } = dragEventItems;
    const activeItemIndex = activeItem.index;
    const overItemIndex = overItem.index;
    const previousItem = activeItemIndex >= overItemIndex ? items[overItemIndex - 1] : items[overItemIndex];
    const nextItem = activeItemIndex <= overItemIndex ? items[overItemIndex + 1] : items[overItemIndex];
    return {
      nextItem,
      previousItem,
      overItem,
      activeItem
    };
  }
  get dragEventDepth() {
    const {
      nestedState: {
        _indentationWidth
      },
      dragEventDirectionItems,
      dnd: {
        _moveDelta
      }
    } = this;
    if (!dragEventDirectionItems) {
      return null;
    }
    const {
      nextItem,
      previousItem,
      activeItem,
      overItem
    } = dragEventDirectionItems;
    const dragDepth = Math.round(_moveDelta.x / _indentationWidth); // getDragDepth
    const projectedDepth = activeItem.item.state.childrenDepth + dragDepth;
    const maxDepth = previousItem ? previousItem.item.state.childrenDepth + 1 : 0;
    const minDepth = nextItem ? nextItem.item.state.childrenDepth : 0;
    let depth = projectedDepth;
    if (!this.isSameEntityAsOtherLevels) {
      depth = activeItem.item.state.childrenDepth;
    } else if (projectedDepth >= maxDepth) {
      depth = maxDepth;
    } else if (projectedDepth < minDepth) {
      depth = minDepth;
    }
    return {
      depth,
      nextItem,
      previousItem,
      activeItem,
      overItem
    };
  }
  get activeNode() {
    const {
      dnd: {
        activeId
      },
      nestedState
    } = this;
    if (!activeId) {
      return null;
    }
    return nestedState.root._getNode(activeId);
  }
  get dragEventParentAndAfter() {
    const {
      nestedState,
      dragEventDepth
    } = this;
    if (!dragEventDepth) {
      return {};
    }
    const {
      keyedItems: items
    } = nestedState;
    const {
      previousItem,
      depth,
      overItem,
      activeItem
    } = dragEventDepth;
    if (previousItem == null) {
      return {
        node: nestedState.root,
        after: null,
        // before: nestedState.root.keyedItems[0],
        activeItem,
        overItem
      };
    }
    if (depth === previousItem.item.state.childrenDepth) {
      return {
        node: previousItem.item.state,
        after: previousItem,
        // before: nextItem && nextItem.item.state.depth === depth ? nextItem : null,
        activeItem,
        overItem
      };
    }
    if (depth > previousItem.item.state.childrenDepth) {
      const node = previousItem.item.state.parentKeyToChildrenMap.get(previousItem.id);
      return {
        node,
        after: null,
        // before: node?.keyedItems[0],
        activeItem,
        overItem
      };
    }
    for (let i = previousItem.index; i >= 0; i--) {
      const item = items[i];
      if (item.item.state.childrenDepth === depth) {
        return {
          node: item.item.state,
          after: item,
          activeItem,
          overItem
        };
      }
    }
    return {
      activeItem,
      overItem
    };
  }
  get reachedMaxDepth() {
    const {
      dragEventParentAndAfter,
      dragEventDirectionItems,
      nestedState,
      activeNode
    } = this;
    if (!dragEventParentAndAfter || !dragEventDirectionItems) {
      return false;
    }
    const {
      node
    } = dragEventParentAndAfter;
    if (!node) {
      return true;
    }
    const activeNodeDeepestBranchDepth = (activeNode == null ? void 0 : activeNode.deepestBranchDepth) ?? 0;
    return node.levelDescriptor.depth + activeNodeDeepestBranchDepth >= nestedState.levels.length;
  }
  get dragAndDropDisabled() {
    const {
      dragEventParentAndAfter
    } = this;
    const {
      node
    } = dragEventParentAndAfter;
    if (!node) {
      return null;
    }
    const dragEndEvent = this._createDragEndEvent({
      setNewParent: false
    });
    if (!dragEndEvent) {
      return null;
    }
    return node.levelDescriptor.dragAndDropDisabled == null ? void 0 : node.levelDescriptor.dragAndDropDisabled(this._createSimpleDragEndEvent(dragEndEvent, node));
  }
  get isSameEntityAsOtherLevels() {
    var _this$nestedState$lev;
    return (_this$nestedState$lev = this.nestedState.levels[0]) == null ? void 0 : _this$nestedState$lev.isSameEntityAsOtherLevels;
  }
  initCollection(collection) {
    return (0, _createOptimisticActionsOrderByModeReaction.createOptimisticActionsOrderByModeReaction)(this.dnd, collection);
  }
  init() {
    return this.dnd.init();
  }
}
exports.NestedTableDragAndDropState = NestedTableDragAndDropState;
//# sourceMappingURL=NestedTableDragAndDropState.js.map