"use strict";

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

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.getBoundsForComponent = getBoundsForComponent;
exports.posObjFromNonQuizEntry = posObjFromNonQuizEntry;
exports.onQuizEntryHover = onQuizEntryHover;
exports.onQuizEntryDrop = onQuizEntryDrop;
exports.collectDrop = collectDrop;
exports.usingIE = usingIE;
exports.chooseDragConnection = chooseDragConnection;
exports.beginQuizEntryDrag = beginQuizEntryDrag;
exports.endQuizEntryDrag = endQuizEntryDrag;
exports.collectDrag = collectDrag;
exports.dragSource = exports.DropTargetCreator = exports.dropTarget = exports.ItemTypes = exports.posObjFromQuizEntry = void 0;

var _reactDom = _interopRequireDefault(require("react-dom"));

var _lodash = require("lodash");

var _immutable = require("immutable");

var _reactDnd = require("react-dnd");

var _cachePreviousArgs = _interopRequireDefault(require("../../../util/cachePreviousArgs"));

var _constants = require("@instructure/quiz-common/lib/constants");

function getBoundsForComponent(component) {
  var dndComponent = component.dndComponent ? component.dndComponent : component;

  var DOMNode = _reactDom.default.findDOMNode(dndComponent);

  return DOMNode && DOMNode.getBoundingClientRect() || {};
}

var posObjFromQuizEntry = (0, _cachePreviousArgs.default)(function (quizEntryDragging, quizEntryHovered, mousePos, component, inSidebar) {
  var _getBoundsForComponen = getBoundsForComponent(component),
      top = _getBoundsForComponen.top,
      bottom = _getBoundsForComponen.bottom,
      left = _getBoundsForComponen.left,
      right = _getBoundsForComponen.right;

  var midY = top + (bottom - top) / 2;
  var midX = left + (right - left) / 2;
  var onRightHalf = mousePos.x > midX;
  var aboveHalf = mousePos.y < midY;
  var deepInsideEntry = mousePos.y > top + 40 && mousePos.y < bottom - 40;
  var newPositionObj = {
    position: quizEntryHovered.position,
    intoEmptyStimulus: false,
    aboveHalf: aboveHalf,
    fromAbove: quizEntryHovered.position > quizEntryDragging.position // handle dragging items over stimulus

  };

  if (!quizEntryDragging.hasStimulus && quizEntryHovered.hasStimulus && (onRightHalf || inSidebar)) {
    if (deepInsideEntry && quizEntryHovered.getNestedEntries().size === 0) {
      newPositionObj.intoEmptyStimulus = true;
      return newPositionObj;
    } else if (deepInsideEntry) {
      // Can return null here, because onHover is called for the stimulus and the nested item
      // (since both are being hovered at the same time). We only care about the nested item
      // in this case, so we're basically just ignoring the stimulus.
      return null;
    }
  }

  var draggingStimulusInStimulus = quizEntryDragging.hasStimulus && quizEntryHovered.isInStimulus;
  var ignoreItemHover = quizEntryHovered.isInStimulus && !deepInsideEntry && !inSidebar;

  if (draggingStimulusInStimulus || ignoreItemHover) {
    return null;
  }

  return newPositionObj;
});
exports.posObjFromQuizEntry = posObjFromQuizEntry;

function posObjFromNonQuizEntry(quizEntryDragging, startComp, endComp, mousePos, quizEntries) {
  // check if dropping above all quizEntries
  var _getBoundsForComponen2 = getBoundsForComponent(startComp),
      bottom = _getBoundsForComponen2.bottom;

  if (mousePos.y < bottom) {
    return {
      position: 1,
      intoEmptyStimulus: false,
      aboveHalf: true,
      fromAbove: false
    };
  } // check if dropping below all quizEntries


  var _getBoundsForComponen3 = getBoundsForComponent(endComp),
      top = _getBoundsForComponen3.top;

  if (mousePos.y > top) {
    var lastQuizEntry = quizEntries.maxBy(function (quizEntry) {
      return quizEntry.position;
    });
    var position = lastQuizEntry.position;

    if (lastQuizEntry.isInStimulus) {
      var stimulusQuizEntry = quizEntries.find(function (qe) {
        return qe.id === lastQuizEntry.stimulusQuizEntryId;
      });

      if (stimulusQuizEntry) {
        position = stimulusQuizEntry.position;
      }
    }

    return {
      position: position,
      intoEmptyStimulus: false,
      aboveHalf: false,
      fromAbove: position > quizEntryDragging.position
    };
  }

  return null;
}

function createPositionObj(props, monitor, component, inSidebar) {
  var itemData = monitor.getItem();
  var mousePos = monitor.getClientOffset() || {};
  var newPositionObj = null;

  if (props.quizEntry) {
    newPositionObj = posObjFromQuizEntry(itemData.quizEntry, props.quizEntry, mousePos, component, inSidebar);
  } else {
    var startQuizEntries = component.startQuizEntries,
        endQuizEntries = component.endQuizEntries;
    newPositionObj = posObjFromNonQuizEntry(itemData.quizEntry, startQuizEntries, endQuizEntries, mousePos, props.quizEntries);
  }

  return newPositionObj;
} // createPosition arg is so that tests can stub it


function onQuizEntryHover(props, monitor, component, refname) {
  var createPosition = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : createPositionObj;
  var inSidebar = refname === _constants.SIDEBAR_ITEM_REF;

  if (inSidebar && !props.sidebarOpen) {
    return;
  }

  var newPositionObj = createPosition(props, monitor, component, inSidebar);
  if (newPositionObj === null) return;
  var itemData = monitor.getItem();
  var samePosition = newPositionObj.position === itemData.position;
  var sameAboveHalf = newPositionObj.aboveHalf === itemData.aboveHalf;
  var sameIntoEmptyStimulus = newPositionObj.intoEmptyStimulus === itemData.intoEmptyStimulus;

  if (samePosition && sameAboveHalf && sameIntoEmptyStimulus) {
    return;
  } // mutation used here to avoid rerendering on every mouse pixel move
  // author of React DnD acknoledges shortcomings of mutations but
  // recommends it here for performance purposes


  Object.assign(monitor.getItem(), {
    position: newPositionObj.position,
    aboveHalf: newPositionObj.aboveHalf,
    intoEmptyStimulus: newPositionObj.intoEmptyStimulus
  });
  props.newHoverPosition(newPositionObj);
}

function positionOfTempItem(quizEntries) {
  // TODO: replace the use of chain with lodash/fp functions and flow
  return (0, _lodash.chain)(quizEntries.toJS()).sortBy(function (qe) {
    return qe.position;
  }).map(function (qe) {
    return qe.id;
  }).indexOf(_constants.TEMPORARY_QUIZ_ENTRY_ID).value() + 1;
}

function newPositionFromPositionObj(newPositionObj, originalItemPosition) {
  if (newPositionObj.intoEmptyStimulus) {
    var offset = newPositionObj.fromAbove ? 0 : 1;
    return newPositionObj.position + offset;
  }

  if (newPositionObj.position === originalItemPosition) {
    return newPositionObj.position;
  }

  if (newPositionObj.fromAbove && newPositionObj.aboveHalf) {
    return newPositionObj.position - 1;
  }

  if (!newPositionObj.fromAbove && !newPositionObj.aboveHalf) {
    return newPositionObj.position + 1;
  }

  return newPositionObj.position;
}

function handleDrop(props, newPosition, newStimulusQuizEntryId, oldStimulusQuizEntryId, itemData, moveTempItem, inSidebar) {
  var quizEntry = itemData.quizEntry;
  var stimulusQuizEntryIdChanged = newStimulusQuizEntryId !== oldStimulusQuizEntryId;
  var isImmutable = quizEntry.isItem ? quizEntry.getEntry().isImmutable() : false;

  if (isImmutable && stimulusQuizEntryIdChanged) {
    var uiData = (0, _immutable.Map)({
      movedInSidebar: inSidebar,
      quizId: props.quizId,
      position: newPosition,
      stimulusQuizEntryId: newStimulusQuizEntryId,
      quizEntryId: quizEntry.id
    });
    props.setUi(_constants.MOVE_IMMUTABLE_DATA, uiData);
    props.openMoveImmutableModal();
  } else {
    props.setUi(_constants.MOVED_IN_SIDEBAR, inSidebar);
    props.moveQuizEntry(props.quizId, newPosition, newStimulusQuizEntryId, quizEntry.id, moveTempItem);
  }
}

function onQuizEntryDrop(props, monitor, component, refname) {
  var inSidebar = refname === _constants.SIDEBAR_ITEM_REF;
  var handledDrop = monitor.getDropResult() && monitor.getDropResult().handledDrop;
  var itemData = monitor.getItem();
  var movingQuizEntry = itemData.quizEntry;
  var hoveredQuizEntry = props.quizEntry;
  var dropStimIntoStim = movingQuizEntry.hasStimulus && hoveredQuizEntry && hoveredQuizEntry.isInStimulus;

  if (inSidebar && !props.sidebarOpen || handledDrop || !props.dndPositionObj || dropStimIntoStim) {
    return {
      handledDrop: handledDrop || false
    };
  }

  var quizEntries = props.quizEntries;
  var originalItemPosition = movingQuizEntry.position;
  var newStimulusQuizEntryId = '';

  var findPositionInList = function findPositionInList(quizEntriesList) {
    var newPositionObj = props.dndPositionObj.toJS() || itemData;
    var targetQuizEntry = quizEntriesList.find(function (qe) {
      return qe.position === newPositionObj.position;
    });

    if (movingQuizEntry.id === targetQuizEntry && targetQuizEntry.id) {
      return newPositionObj.position;
    }

    var targetIsStimulus = targetQuizEntry && targetQuizEntry.hasStimulus;

    if (targetIsStimulus && newPositionObj.intoEmptyStimulus) {
      // into empty
      newStimulusQuizEntryId = targetQuizEntry.id;
    } else if (targetIsStimulus && !newPositionObj.intoEmptyStimulus) {
      // around stimulus
      newPositionObj.position += newPositionObj.aboveHalf ? 0 : targetQuizEntry.getNestedEntries().size;
    } else {
      newStimulusQuizEntryId = targetQuizEntry && targetQuizEntry.stimulusQuizEntryId || '';
    }

    return newPositionFromPositionObj(newPositionObj, originalItemPosition);
  };

  if (movingQuizEntry.id === _constants.TEMPORARY_QUIZ_ENTRY_ID) {
    var newPosition = findPositionInList(quizEntries);

    if (newPosition === originalItemPosition) {
      return {
        handledDrop: true
      };
    }

    var movingDown = newPosition > originalItemPosition;
    props.moveTemporaryQuizEntry(newPosition, newStimulusQuizEntryId, movingDown);
  } else {
    var quizEntriesWithoutTemp = quizEntries.filterNot(function (qe) {
      return qe.id === _constants.TEMPORARY_QUIZ_ENTRY_ID;
    });

    var _newPosition = findPositionInList(quizEntriesWithoutTemp);

    var newPositionIncludingTemp = findPositionInList(quizEntries);
    var tempItemPosition = positionOfTempItem(quizEntries);
    var originBelowTemp = originalItemPosition >= tempItemPosition;
    var originAboveTemp = originalItemPosition < tempItemPosition;
    var droppedPastTemp = originBelowTemp && newPositionIncludingTemp < tempItemPosition || originAboveTemp && newPositionIncludingTemp > tempItemPosition;
    var droppedOnTemp = tempItemPosition === newPositionIncludingTemp;

    var moveTempItem = function moveTempItem() {
      if (droppedPastTemp || droppedOnTemp) {
        var directionToMoveTempItem = originAboveTemp ? 'up' : 'down';

        var _movingDown = !originAboveTemp;

        props.moveTemporaryQuizEntry(directionToMoveTempItem, newStimulusQuizEntryId, _movingDown);
      }
    };

    var oldStimulusQuizEntryId = movingQuizEntry.stimulusQuizEntryId || '';

    if (_newPosition === originalItemPosition && newStimulusQuizEntryId === oldStimulusQuizEntryId) {
      moveTempItem();
      return {
        handledDrop: true
      };
    }

    handleDrop(props, _newPosition, newStimulusQuizEntryId, oldStimulusQuizEntryId, itemData, moveTempItem, inSidebar);
    return {
      handledDrop: true
    };
  }
}

function collectDrop(connect, monitor) {
  return {
    connectDropTarget: connect.dropTarget(),
    isOver: monitor.isOver()
  };
}

var ItemTypes = {
  QUIZ_ENTRY: 'quiz_entry'
};
exports.ItemTypes = ItemTypes;

var dropTarget = function dropTarget(refname) {
  return {
    drop: function drop(props, monitor, component) {
      return onQuizEntryDrop(props, monitor, component, refname);
    },
    hover: function hover(props, monitor, component) {
      onQuizEntryHover(props, monitor, component, refname);
    }
  };
}; // - ItemTypes.QUIZ_ENTRY associates this component drop target with a name
// - dropTarget specifies functions React DnD will call for events with this component
// - collectDrop injects props into component


exports.dropTarget = dropTarget;

var DropTargetCreator = function DropTargetCreator(refname) {
  return (0, _reactDnd.DropTarget)(ItemTypes.QUIZ_ENTRY, dropTarget(refname), collectDrop);
}; // ///////////////// //
// DRAG SOURCE STUFF //
// ///////////////// //


exports.DropTargetCreator = DropTargetCreator;

function usingIE() {
  var windowOverride = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : window;
  var ua = windowOverride.navigator.userAgent;
  var edge = ua.includes('Edge/');
  var ie11 = ua.includes('Trident/');
  var ie10 = ua.includes('MSIE ');
  return edge || ie11 || ie10;
}

function chooseDragConnection(dragSource, dragPreview) {
  var windowOverride = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : window;
  return usingIE(windowOverride) ? dragSource : dragPreview;
}

function beginQuizEntryDrag(props, monitor, component) {
  return {
    quizEntry: props.quizEntry
  };
}

function endQuizEntryDrag(props, monitor, component) {
  // to indicate we're no longer dragging
  props.newHoverPosition({
    position: -1
  });
}

var dragSource = {
  beginDrag: beginQuizEntryDrag,
  endDrag: endQuizEntryDrag
};
exports.dragSource = dragSource;

function collectDrag(connect, monitor) {
  return {
    connectDragSource: connect.dragSource(),
    connectDragPreview: connect.dragPreview(),
    isDragging: monitor.isDragging()
  };
}