"use strict";

exports.__esModule = true;
exports["default"] = void 0;
exports.getTrimmedRangesToDisplay = getTrimmedRangesToDisplay;
var _react = _interopRequireDefault(require("react"));
var _reactDraggable = _interopRequireDefault(require("react-draggable"));
var _reactList = _interopRequireDefault(require("@teselagen/react-list"));
var _Axis = _interopRequireDefault(require("../RowItem/Axis"));
var _getXStartAndWidthFromNonCircularRange = _interopRequireDefault(require("../RowItem/getXStartAndWidthFromNonCircularRange"));
var _reactEasyState = require("@risingstack/react-easy-state");
var _lodash = require("lodash");
var _rangeUtils = require("@teselagen/range-utils");
var _massageTickSpacing = require("../utils/massageTickSpacing");
var _editorUtils = require("../utils/editorUtils");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
var Minimap = /*#__PURE__*/function (_React$Component) {
  _inheritsLoose(Minimap, _React$Component);
  function Minimap() {
    var _this;
    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
      args[_key] = arguments[_key];
    }
    _this = _React$Component.call.apply(_React$Component, [this].concat(args)) || this;
    _defineProperty(_assertThisInitialized(_this), "handleMinimapClick", function (e) {
      if (_this.isDragging || e.target && e.target.classList.contains("minimapCaret")) {
        e.stopPropagation();
        return;
      }
      var _this$props = _this.props,
        onMinimapScrollX = _this$props.onMinimapScrollX,
        _this$props$dimension = _this$props.dimensions.width,
        width = _this$props$dimension === void 0 ? 200 : _this$props$dimension;
      var scrollHandleWidth = _this.getScrollHandleWidth();
      var percent = (_this.getXPositionOfClickInMinimap(e) - scrollHandleWidth / 2) / (width - scrollHandleWidth);
      onMinimapScrollX(percent);
      _this.scrollMinimapVertical({
        e: e,
        force: true
      });
    });
    _defineProperty(_assertThisInitialized(_this), "getSeqLen", function () {
      var _this$props$alignment = _this.props.alignmentTracks,
        alignmentTracks = _this$props$alignment === void 0 ? [] : _this$props$alignment;
      var template = alignmentTracks[0];
      var seqLength = template.alignmentData.sequence.length;
      return seqLength;
    });
    _defineProperty(_assertThisInitialized(_this), "getCharWidth", function () {
      var _this$props$dimension2 = _this.props.dimensions.width,
        width = _this$props$dimension2 === void 0 ? 200 : _this$props$dimension2;
      var seqLength = _this.getSeqLen();
      var charWidth = Math.min(16, width / seqLength);
      return charWidth || 12;
    });
    _defineProperty(_assertThisInitialized(_this), "getScrollHandleWidth", function () {
      var _this$props2 = _this.props,
        numBpsShownInLinearView = _this$props2.numBpsShownInLinearView,
        dimensions = _this$props2.dimensions;
      var charWidth = _this.getCharWidth();
      var _getXStartAndWidthFro = (0, _getXStartAndWidthFromNonCircularRange["default"])({
          start: 0,
          end: Math.max(numBpsShownInLinearView - 1, 0)
        }, charWidth),
        width = _getXStartAndWidthFro.width;
      return Math.min(width, dimensions.width);
    });
    _defineProperty(_assertThisInitialized(_this), "getXPositionOfClickInMinimap", function (e) {
      var leftStart = _this.minimap.getBoundingClientRect().left;
      return Math.max((0, _editorUtils.getClientX)(e) - leftStart, 0);
    });
    _defineProperty(_assertThisInitialized(_this), "getYPositionOfClickInMinimap", function (e) {
      var topStart = _this.minimap.getBoundingClientRect().top;
      return Math.max((0, _editorUtils.getClientY)(e) + _this.minimapTracks.scrollTop - topStart, 0);
    });
    _defineProperty(_assertThisInitialized(_this), "scrollMinimapVertical", function (_ref) {
      var e = _ref.e,
        force = _ref.force,
        initialDragYOffsetFromCenter = _ref.initialDragYOffsetFromCenter;
      var clientY = (0, _editorUtils.getClientY)(e) - (initialDragYOffsetFromCenter || 0);
      try {
        if (!force && (0, _rangeUtils.isPositionWithinRange)(clientY, {
          start: _this.lastYPosition - 5,
          end: _this.lastYPosition + 5
        })) {
          // this.lastYPosition = clientY
          return;
        }
        var lanes = document.querySelectorAll(".minimapLane");
        (0, _lodash.some)(lanes, function (lane) {
          var rect = lane.getBoundingClientRect();
          if (rect.top > clientY && rect.top - rect.height < clientY) {
            var laneI = (0, _lodash.toNumber)(lane.getAttribute("data-lane-index"));
            var scrollToLane = laneI - 3;
            if (laneI === lanes.length - 1) {
              scrollToLane = laneI - 1;
            } else if (laneI === lanes.length - 2) {
              scrollToLane = laneI - 2;
            }
            _this.props.scrollYToTrack(Math.max(scrollToLane, 0));
            return true;
          }
          return false;
        });
        _this.lastYPosition = clientY;
      } catch (error) {
        console.error("error in scrollMinimapVertical:", error);
      }
    });
    _defineProperty(_assertThisInitialized(_this), "handleDragStop", function () {
      // this.hasSetDirection = false;
      setTimeout(function () {
        _this.isDragging = false;
      }, 150);
    });
    _defineProperty(_assertThisInitialized(_this), "handleDragStart", function (e) {
      var eventX = e.pageX;
      var handleEl = window.document.querySelector(".verticalScrollDisplay");
      if (!handleEl) return;
      var _handleEl$getBounding = handleEl.getBoundingClientRect(),
        x = _handleEl$getBounding.x,
        width = _handleEl$getBounding.width;
      var yellowScrollHandleXCenter = x + width / 2;
      _this.initialDragXOffsetFromCenter = eventX - yellowScrollHandleXCenter;
      var eventY = e.pageY;
      if (!handleEl) return;
      var _handleEl$getBounding2 = handleEl.getBoundingClientRect(),
        y = _handleEl$getBounding2.y,
        height = _handleEl$getBounding2.height;
      var yellowScrollHandleYCenter = y + height / 2;
      _this.initialDragYOffsetFromCenter = eventY - yellowScrollHandleYCenter;
    });
    _defineProperty(_assertThisInitialized(_this), "handleDrag", function (e) {
      var _this$props3 = _this.props,
        onMinimapScrollX = _this$props3.onMinimapScrollX,
        _this$props3$dimensio = _this$props3.dimensions.width,
        width = _this$props3$dimensio === void 0 ? 200 : _this$props3$dimensio;
      _this.isDragging = true; //needed to block erroneous click events from being triggered!

      var scrollHandleWidth = _this.getScrollHandleWidth();
      var percent = (_this.getXPositionOfClickInMinimap(e) - (_this.initialDragXOffsetFromCenter || 0) - scrollHandleWidth / 2) / (width - scrollHandleWidth);
      onMinimapScrollX(percent);
      _this.scrollMinimapVertical({
        e: e,
        initialDragYOffsetFromCenter: _this.initialDragYOffsetFromCenter
      });
    });
    _defineProperty(_assertThisInitialized(_this), "itemSizeGetter", function () {
      return _this.props.laneHeight;
    });
    _defineProperty(_assertThisInitialized(_this), "renderItem", function (i) {
      var _this$props4 = _this.props,
        _this$props4$alignmen = _this$props4.alignmentTracks,
        alignmentTracks = _this$props4$alignmen === void 0 ? [] : _this$props4$alignmen,
        _this$props4$dimensio = _this$props4.dimensions.width,
        width = _this$props4$dimensio === void 0 ? 200 : _this$props4$dimensio,
        laneHeight = _this$props4.laneHeight,
        _this$props4$laneSpac = _this$props4.laneSpacing,
        laneSpacing = _this$props4$laneSpac === void 0 ? 1 : _this$props4$laneSpac;
      var charWidth = _this.getCharWidth();
      var _alignmentTracks$i = alignmentTracks[i],
        _matchHighlightRanges = _alignmentTracks$i.matchHighlightRanges,
        _alignmentTracks$i$al = _alignmentTracks$i.alignmentData;
      _alignmentTracks$i$al = _alignmentTracks$i$al === void 0 ? {} : _alignmentTracks$i$al;
      var trimmedRange = _alignmentTracks$i$al.trimmedRange;
      var matchHighlightRanges = !trimmedRange ? _matchHighlightRanges : (0, _lodash.flatMap)(_matchHighlightRanges, function (r) {
        var overlap = (0, _rangeUtils.getOverlapOfNonCircularRanges)(r, trimmedRange);
        if (!overlap) return [];
        return _extends({}, r, overlap);
      });

      //need to get the chunks that can be rendered
      var redPath = ""; //draw these as just 1 path instead of a bunch of rectangles to improve browser performance
      var bluePath = "";
      // draw one grey rectangle then draw red/mismatching regions on top of it
      var height = laneHeight - laneSpacing;
      var y = 0;
      var firstRange = (0, _getXStartAndWidthFromNonCircularRange["default"])(matchHighlightRanges[0], charWidth);
      var lastRange = (0, _getXStartAndWidthFromNonCircularRange["default"])(matchHighlightRanges[matchHighlightRanges.length - 1], charWidth);
      bluePath += "M" + firstRange.xStart + "," + y + " L" + (lastRange.xStart + lastRange.width) + "," + y + " L" + (lastRange.xStart + lastRange.width) + "," + (y + height) + " L" + firstRange.xStart + "," + (y + height);
      matchHighlightRanges.forEach(function (range) {
        var _getXStartAndWidthFro2 = (0, _getXStartAndWidthFromNonCircularRange["default"])(range, charWidth),
          xStart = _getXStartAndWidthFro2.xStart,
          width = _getXStartAndWidthFro2.width;
        var toAdd = "M" + xStart + "," + y + " L" + (xStart + width) + "," + y + " L" + (xStart + width) + "," + (y + height) + " L" + xStart + "," + (y + height);
        if (!range.isMatch) {
          redPath += toAdd;
        }
      });
      return /*#__PURE__*/_react["default"].createElement("div", {
        key: i + "-lane",
        className: "minimapLane",
        "data-lane-index": i,
        style: {
          height: laneHeight,
          maxHeight: laneHeight
        }
      }, /*#__PURE__*/_react["default"].createElement("svg", {
        height: laneHeight,
        width: width,
        shapeRendering: "geometricPrecision"
      }, /*#__PURE__*/_react["default"].createElement("path", {
        className: "miniBluePath",
        d: bluePath,
        fill: "#9abeff"
      }), /*#__PURE__*/_react["default"].createElement("path", {
        className: "miniRedPath",
        d: redPath,
        fill: "red"
      })));
    });
    return _this;
  }
  var _proto = Minimap.prototype;
  _proto.shouldComponentUpdate = function shouldComponentUpdate(newProps) {
    var props = this.props;
    if (["alignmentTracks", "numBpsShownInLinearView", "scrollAlignmentView", "laneHeight", "laneSpacing"].some(function (key) {
      return props[key] !== newProps[key];
    })) return true;
    return false;
  };
  /**
   * @returns minimap compoent
   */
  _proto.render = function render() {
    var _this2 = this;
    var _this$props5 = this.props,
      _this$props5$alignmen = _this$props5.alignmentTracks,
      alignmentTracks = _this$props5$alignmen === void 0 ? [] : _this$props5$alignmen,
      _this$props5$dimensio = _this$props5.dimensions.width,
      width = _this$props5$dimensio === void 0 ? 200 : _this$props5$dimensio,
      laneHeight = _this$props5.laneHeight,
      onSizeAdjust = _this$props5.onSizeAdjust,
      minSliderSize = _this$props5.minSliderSize,
      onMinimapScrollX = _this$props5.onMinimapScrollX,
      easyStore = _this$props5.easyStore,
      selectionLayerComp = _this$props5.selectionLayerComp;
    var template /* ...nonTemplates */ = alignmentTracks[0];
    var seqLength = template.alignmentData.sequence.length;
    var charWidth = this.getCharWidth();
    var scrollHandleWidth = this.getScrollHandleWidth();
    var minimapTracksPartialHeight = laneHeight * alignmentTracks.length;
    return /*#__PURE__*/_react["default"].createElement("div", {
      ref: function ref(_ref3) {
        return _this2.minimap = _ref3;
      },
      className: "alignmentMinimap",
      style: {
        position: "relative",
        width: width,
        display: "flex",
        flexDirection: "column",
        overflowX: "visible"

        // overflowY: "hidden"
      },

      onClick: this.handleMinimapClick
    }, selectionLayerComp, /*#__PURE__*/_react["default"].createElement("div", {
      ref: function ref(_ref2) {
        if (_ref2) {
          _this2.minimapTracks = _ref2;
        }
      },
      style: {
        // maxHeight: 350,
        overflowY: minimapTracksPartialHeight > 190 ? "auto" : "hidden",
        // overflowY: "auto",
        overflowX: "hidden",
        position: "relative"
      },
      className: "alignmentMinimapTracks"
    }, /*#__PURE__*/_react["default"].createElement(YellowScrollHandle, {
      width: width,
      handleDragStart: this.handleDragStart,
      handleDrag: this.handleDrag,
      handleDragStop: this.handleDragStop,
      onMinimapScrollX: onMinimapScrollX,
      minSliderSize: minSliderSize,
      onSizeAdjust: onSizeAdjust,
      easyStore: easyStore //we use react-easy-state here to prevent costly setStates from being called
      ,
      scrollHandleWidth: scrollHandleWidth,
      alignmentTracks: alignmentTracks,
      laneHeight: laneHeight,
      minimapTracksPartialHeight: minimapTracksPartialHeight
    }), /*#__PURE__*/_react["default"].createElement(_reactList["default"], {
      itemsRenderer: function itemsRenderer(items, ref) {
        return /*#__PURE__*/_react["default"].createElement("div", {
          style: {
            marginTop: -3
            // paddingLeft: nameDivWidth
          },

          ref: ref
        }, items);
      },
      type: "uniform",
      itemSizeGetter: this.itemSizeGetter,
      itemRenderer: this.renderItem,
      length: alignmentTracks.length
    })), /*#__PURE__*/_react["default"].createElement(_Axis["default"], {
      row: {
        start: 0,
        end: seqLength
      },
      tickSpacing: (0, _massageTickSpacing.massageTickSpacing)(Math.floor(seqLength / 10)),
      bpsPerRow: seqLength,
      charWidth: charWidth,
      annotationHeight: 15,
      sequenceLength: seqLength,
      style: {
        // paddingLeft: nameDivWidth,
        height: 17
      }
    }));
  };
  return Minimap;
}(_react["default"].Component);
/**
 * Yellow Scroll handle
 * Responsible for designating the current viewing area
 * Also supports zoom/resizing using handles
 */
exports["default"] = Minimap;
var YellowScrollHandle = (0, _reactEasyState.view)( /*#__PURE__*/function (_React$Component2) {
  _inheritsLoose(YellowScrollHandleInner, _React$Component2);
  function YellowScrollHandleInner() {
    return _React$Component2.apply(this, arguments) || this;
  }
  var _proto2 = YellowScrollHandleInner.prototype;
  _proto2.render = function render() {
    var _this3 = this;
    var _this$props6 = this.props,
      scrollHandleWidth = _this$props6.scrollHandleWidth,
      width = _this$props6.width,
      easyStore = _this$props6.easyStore,
      handleDrag = _this$props6.handleDrag,
      handleDragStop = _this$props6.handleDragStop,
      minSliderSize = _this$props6.minSliderSize,
      laneHeight = _this$props6.laneHeight,
      onSizeAdjust = _this$props6.onSizeAdjust,
      handleDragStart = _this$props6.handleDragStart,
      minimapTracksPartialHeight = _this$props6.minimapTracksPartialHeight;
    var verticalVisibleRange = easyStore.verticalVisibleRange,
      percentScrolled = easyStore.percentScrolled;
    var xScroll = percentScrolled * (width - scrollHandleWidth);
    return /*#__PURE__*/_react["default"].createElement(_reactDraggable["default"], {
      bounds: "parent",
      zIndex: 105,
      handle: ".handle",
      position: {
        x: xScroll,
        y: 0
      },
      axis: "x"
      // onStart={this.onStart}
      ,
      onStop: handleDragStop,
      onDrag: handleDrag,
      onStart: handleDragStart
    }, /*#__PURE__*/_react["default"].createElement("div", {
      style: {
        height: minimapTracksPartialHeight || 0,
        // height: "100%",
        border: "none",
        top: "0px",
        position: "absolute",
        zIndex: "10"
      }
    }, /*#__PURE__*/_react["default"].createElement(_reactDraggable["default"], {
      bounds: {
        left: -xScroll,
        right: scrollHandleWidth - minSliderSize
      },
      zIndex: 105,
      position: {
        x: 0,
        y: 0
      },
      axis: "x",
      onStart: function onStart(e, _ref4) {
        var x = _ref4.x;
        _this3.x = x;
      },
      onStop: function onStop(e, _ref5) {
        var x = _ref5.x;
        var deltaX = x - _this3.x;
        var newSliderSize = scrollHandleWidth - deltaX;
        //user is resizing to the left so we need to update the scroll percentage so the slider does not jump
        var newScrollPercent = Math.min(1, (xScroll + deltaX) / (width - newSliderSize));
        onSizeAdjust(newSliderSize, newScrollPercent);
      }
    }, /*#__PURE__*/_react["default"].createElement("div", {
      style: {
        height: minimapTracksPartialHeight || 0,
        // height: "100%",
        border: "none",
        cursor: "ew-resize",
        opacity: "1",
        top: "0px",
        position: "absolute",
        zIndex: "10",
        width: 2,
        background: "black"
      },
      className: "minimapCaret"
    })), /*#__PURE__*/_react["default"].createElement("div", {
      className: "handle alignmentMinimapScrollHandle",
      dataname: "scrollGroup",
      style: {
        height: minimapTracksPartialHeight || 0,
        border: "none",
        cursor: "move",
        zIndex: "10",
        width: scrollHandleWidth,
        background: "transparent"
      }
    }, /*#__PURE__*/_react["default"].createElement("div", {
      className: "verticalScrollDisplay",
      style: {
        height: (verticalVisibleRange.end - verticalVisibleRange.start + 1) * laneHeight,
        zIndex: "-10",
        background: "#fbfb2873",
        borderTop: "2px solid yellow",
        borderBottom: "2px solid yellow",
        position: "relative",
        top: verticalVisibleRange.start * laneHeight
      }
    })), /*#__PURE__*/_react["default"].createElement(_reactDraggable["default"], {
      bounds: {
        right: minSliderSize + width - xScroll,
        left: minSliderSize
      },
      zIndex: 105,
      position: {
        x: scrollHandleWidth,
        y: 0
      },
      axis: "x",
      onStart: function onStart(e, _ref6) {
        var x = _ref6.x;
        _this3.x = x;
      },
      onStop: function onStop(e, _ref7) {
        var x = _ref7.x;
        var deltaX = _this3.x - x;
        var newSliderSize = scrollHandleWidth - deltaX;
        //user is resizing to the right so we need to update the scroll percentage so the slider does not jump
        var newScrollPercent = xScroll / (width - newSliderSize);
        onSizeAdjust(newSliderSize, newScrollPercent);
      }
    }, /*#__PURE__*/_react["default"].createElement("div", {
      style: {
        height: minimapTracksPartialHeight || 0,
        // height: "100%",
        border: "none",
        cursor: "ew-resize",
        opacity: "1",
        top: "0px",
        // right: 0,
        position: "absolute",
        zIndex: "10",
        width: 2,
        background: "black"
      },
      className: "minimapCaret"
    }))));
  };
  return YellowScrollHandleInner;
}(_react["default"].Component));
function getTrimmedRangesToDisplay(_ref8) {
  var trimmedRange = _ref8.trimmedRange,
    seqLen = _ref8.seqLen;
  if (!trimmedRange) return [];
  var inverted = (0, _rangeUtils.invertRange)(trimmedRange, seqLen);
  return (0, _rangeUtils.splitRangeIntoTwoPartsIfItIsCircular)(inverted, seqLen);
}