var _excluded = ["filterOpts"],
  _excluded2 = ["CompOverride", "shouldShow", "noPlural", "alignmentType", "onlyForward", "onlyReverse"];
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 _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
import { normalizePositionByRangeLength, getSequenceWithinRange, getOverlapsOfPotentiallyCircularRanges } from "@teselagen/range-utils";
import { map, camelCase, startCase, startsWith, flatMap, assign } from "lodash";
import { getComplementSequenceString } from "@teselagen/sequence-utils";
import React, { useMemo } from "react";
import pluralize from "pluralize";
import SelectionLayer from "./SelectionLayer";
import Sequence from "./Sequence";
import Axis from "./Axis";
import Orfs from "./Orfs";
import Translations from "./Translations";
import Labels from "./Labels";
import Cutsites from "./Cutsites";
import Caret from "./Caret";
import StackedAnnotations from "./StackedAnnotations";
import "./style.css";
import Chromatogram from "./Chromatograms/Chromatogram";
import { rowHeights } from "../RowView/estimateRowHeight";
import { getAllSelectionLayers } from "../utils/selectionLayer";
import { filter } from "lodash";
import { defaultCharWidth } from "../constants/rowviewContants";
import { CutsiteSelectionLayers } from "./CutsiteSelectionLayers";
function noop() {}
function filterRanges(ranges, extraProps) {
  if (extraProps === void 0) {
    extraProps = {};
  }
  if (!ranges) return ranges;
  if (extraProps.onlyForward) {
    ranges = filter(ranges, function (a) {
      return a.annotation.forward;
    });
  }
  if (extraProps.onlyReverse) {
    ranges = filter(ranges, function (a) {
      return !a.annotation.forward;
    });
  }
  return ranges;
}
function getPropsForType(props, type, pluralType, extraProps) {
  var upperPluralType = startCase(pluralType);
  var annotationRanges = filterRanges(props.row[pluralType], extraProps);
  var toRet = {
    annotationColor: props[pluralType + "Color"],
    annotationHeight: props[pluralType + "Height"] || rowHeights[pluralType].height,
    spaceBetweenAnnotations: props["spaceBetweenAnnotations" + upperPluralType] || rowHeights[pluralType].spaceBetweenAnnotations,
    marginTop: props[pluralType + "MarginTop"] || rowHeights[pluralType].marginTop,
    marginBottom: props[pluralType + "MarginBottom"] || rowHeights[pluralType].marginBottom,
    annotationRanges: annotationRanges,
    showLabels: props.annotationLabelVisibility && props.annotationLabelVisibility[pluralType],
    onClick: props[type + "Clicked"],
    onRightClick: props[type + "RightClicked"],
    onDoubleClick: props[type + "DoubleClicked"]
  };
  return toRet;
}
export default function RowItem(props) {
  var noRedux = props.noRedux,
    _props$charWidth = props.charWidth,
    charWidth = _props$charWidth === void 0 ? defaultCharWidth : _props$charWidth,
    _props$selectionLayer = props.selectionLayer,
    selectionLayer = _props$selectionLayer === void 0 ? {
      start: -1,
      end: -1
    } : _props$selectionLayer,
    _props$deletionLayers = props.deletionLayers,
    deletionLayers = _props$deletionLayers === void 0 ? {} : _props$deletionLayers,
    _props$replacementLay = props.replacementLayers,
    replacementLayers = _props$replacementLay === void 0 ? {} : _props$replacementLay,
    _props$searchLayers = props.searchLayers,
    searchLayers = _props$searchLayers === void 0 ? [] : _props$searchLayers,
    rowTopComp = props.rowTopComp,
    rowBottomComp = props.rowBottomComp,
    isProtein = props.isProtein,
    tickSpacing = props.tickSpacing,
    _props$truncateLabels = props.truncateLabelsThatDoNotFit,
    truncateLabelsThatDoNotFit = _props$truncateLabels === void 0 ? true : _props$truncateLabels,
    _props$aminoAcidNumbe = props.aminoAcidNumbersHeight,
    aminoAcidNumbersHeight = _props$aminoAcidNumbe === void 0 ? rowHeights.aminoAcidNumbers.height : _props$aminoAcidNumbe,
    _props$cutsiteLabelHe = props.cutsiteLabelHeight,
    cutsiteLabelHeight = _props$cutsiteLabelHe === void 0 ? rowHeights.cutsiteLabels.height : _props$cutsiteLabelHe,
    _props$sequenceHeight = props.sequenceHeight,
    sequenceHeight = _props$sequenceHeight === void 0 ? rowHeights.sequence.height : _props$sequenceHeight,
    _props$axisHeight = props.axisHeight,
    axisHeight = _props$axisHeight === void 0 ? rowHeights.axis.height : _props$axisHeight,
    _props$primerHeight = props.primerHeight,
    primerHeight = _props$primerHeight === void 0 ? rowHeights.primers.height : _props$primerHeight,
    _props$axisMarginTop = props.axisMarginTop,
    axisMarginTop = _props$axisMarginTop === void 0 ? rowHeights.axis.marginTop : _props$axisMarginTop,
    width = props.width,
    _props$annotationVisi = props.annotationVisibility,
    annotationVisibility = _props$annotationVisi === void 0 ? {} : _props$annotationVisi,
    _props$annotationLabe = props.annotationLabelVisibility,
    annotationLabelVisibility = _props$annotationLabe === void 0 ? {} : _props$annotationLabe,
    _props$additionalSele = props.additionalSelectionLayers,
    additionalSelectionLayers = _props$additionalSele === void 0 ? [] : _props$additionalSele,
    _props$caretPosition = props.caretPosition,
    caretPosition = _props$caretPosition === void 0 ? -1 : _props$caretPosition,
    _props$row = props.row,
    row = _props$row === void 0 ? {
      sequence: "",
      start: 0,
      end: 0,
      rowNumber: 0
    } : _props$row,
    readOnly = props.readOnly,
    isRowView = props.isRowView,
    emptyText = props.emptyText,
    alignmentType = props.alignmentType,
    alignmentData = props.alignmentData,
    _props$sequenceLength = props.sequenceLength,
    sequenceLength = _props$sequenceLength === void 0 ? row.sequence.length : _props$sequenceLength,
    chromatogramData = props.chromatogramData,
    _props$fullSequence = props.fullSequence,
    fullSequence = _props$fullSequence === void 0 ? "" : _props$fullSequence,
    _props$replacementLay2 = props.replacementLayerClicked,
    replacementLayerClicked = _props$replacementLay2 === void 0 ? noop : _props$replacementLay2,
    _props$replacementLay3 = props.replacementLayerRightClicked,
    replacementLayerRightClicked = _props$replacementLay3 === void 0 ? noop : _props$replacementLay3,
    _props$searchLayerCli = props.searchLayerClicked,
    searchLayerClicked = _props$searchLayerCli === void 0 ? noop : _props$searchLayerCli,
    _props$backgroundRigh = props.backgroundRightClicked,
    backgroundRightClicked = _props$backgroundRigh === void 0 ? noop : _props$backgroundRigh,
    _props$selectionLayer2 = props.selectionLayerRightClicked,
    selectionLayerRightClicked = _props$selectionLayer2 === void 0 ? noop : _props$selectionLayer2,
    _props$searchLayerRig = props.searchLayerRightClicked,
    searchLayerRightClicked = _props$searchLayerRig === void 0 ? noop : _props$searchLayerRig,
    _props$translationDou = props.translationDoubleClicked,
    translationDoubleClicked = _props$translationDou === void 0 ? noop : _props$translationDou,
    _props$minHeight = props.minHeight,
    minHeight = _props$minHeight === void 0 ? 22 : _props$minHeight,
    _props$bpsPerRow = props.bpsPerRow,
    bpsPerRow = _props$bpsPerRow === void 0 ? sequenceLength : _props$bpsPerRow,
    editorName = props.editorName,
    rowContainerStyle = props.rowContainerStyle,
    onScroll = props.onScroll,
    scrollData = props.scrollData,
    onlyShowLabelsThatDoNotFit = props.onlyShowLabelsThatDoNotFit,
    labelLineIntensity = props.labelLineIntensity,
    isLinearView = props.isLinearView,
    scalePct = props.scalePct,
    setScalePct = props.setScalePct,
    _props$extraAnnotatio = props.extraAnnotationProps,
    extraAnnotationProps = _props$extraAnnotatio === void 0 ? {} : _props$extraAnnotatio;
  var showChromatogram = annotationVisibility.chromatogram,
    showCutsites = annotationVisibility.cutsites,
    showCutsitesInSequence = annotationVisibility.cutsitesInSequence,
    showAxis = annotationVisibility.axis,
    showAxisNumbers = annotationVisibility.axisNumbers,
    showAminoAcidNumbers = annotationVisibility.aminoAcidNumbers,
    showDnaColors = annotationVisibility.dnaColors,
    fivePrimeThreePrimeHints = annotationVisibility.fivePrimeThreePrimeHints,
    showReverseSequence = annotationVisibility.reverseSequence,
    showSequence = annotationVisibility.sequence,
    height = annotationVisibility.height;
  var _row$sequence = row.sequence,
    sequence = _row$sequence === void 0 ? "" : _row$sequence,
    _row$cutsites = row.cutsites,
    cutsites = _row$cutsites === void 0 ? [] : _row$cutsites;
  var reverseSequence = getComplementSequenceString(alignmentData && alignmentData.sequence || sequence);
  var getGaps = useMemo(function () {
    if (alignmentData) {
      var gapMap = getGapMap(alignmentData.sequence);
      //this function is used to calculate the number of spaces that come before or inside a range
      return function (rangeOrCaretPosition) {
        if (typeof rangeOrCaretPosition !== "object") {
          return {
            gapsBefore: gapMap[Math.min(rangeOrCaretPosition, gapMap.length - 1)]
          };
        }
        //otherwise it is a range!
        var start = rangeOrCaretPosition.start,
          end = rangeOrCaretPosition.end;
        var toReturn = {
          gapsBefore: gapMap[start],
          gapsInside: gapMap[Math.min(end, gapMap.length - 1)] - gapMap[Math.min(start, gapMap.length - 1)]
        };
        return toReturn;
      };
    } else {
      return getGapsDefault;
    }
  }, [alignmentData]);
  if (!row) {
    return null;
  }
  if (!width) {
    width = bpsPerRow * charWidth;
  }
  if (isLinearView) {
    width -= (charWidth || 12) * bpsPerRow.toString().length / 2;
  }
  charWidth = charWidth || width / Math.max(bpsPerRow, 1);
  var rowStyle = {
    position: "relative",
    minHeight: minHeight,
    height: height,
    width: width + "px"
  };
  var annotationCommonProps = {
    noRedux: noRedux,
    editorName: editorName,
    charWidth: charWidth,
    bpsPerRow: bpsPerRow,
    getGaps: getGaps,
    isProtein: isProtein,
    readOnly: readOnly,
    sequenceLength: sequenceLength,
    isRowView: isRowView,
    row: {
      start: row.start,
      end: row.end
    }
  };
  var drawLabels = function drawLabels(type, noDraw, _temp) {
    var _ref = _temp === void 0 ? {} : _temp,
      filterOpts = _ref.filterOpts,
      extraProps = _objectWithoutPropertiesLoose(_ref, _excluded);
    if (noDraw) {
      return null;
    }
    var pluralType = pluralize(type);
    var ranges = filterRanges(annotationLabelVisibility[pluralType] && annotationVisibility[pluralType] ? map(row[pluralType], function (a) {
      return assign(a, {
        onClick: props[type + "Clicked"],
        onRightClick: props[type + "RightClicked"],
        onDoubleClick: props[type + "DoubleClicked"]
      });
    }) : [], filterOpts);
    if (!ranges.length) return null;
    return /*#__PURE__*/React.createElement(Labels, _extends({}, annotationCommonProps, {
      onlyShowLabelsThatDoNotFit: onlyShowLabelsThatDoNotFit,
      labelLineIntensity: labelLineIntensity,
      rangeMax: bpsPerRow,
      annotationRanges: ranges,
      annotationHeight: cutsiteLabelHeight
    }, extraProps));
  };
  var drawAnnotations = function drawAnnotations(type, extraProps) {
    if (extraProps === void 0) {
      extraProps = {};
    }
    var _extraProps = extraProps,
      CompOverride = _extraProps.CompOverride,
      shouldShow = _extraProps.shouldShow,
      noPlural = _extraProps.noPlural,
      alignmentType = _extraProps.alignmentType,
      onlyForward = _extraProps.onlyForward,
      onlyReverse = _extraProps.onlyReverse,
      otherExtraProps = _objectWithoutPropertiesLoose(_extraProps, _excluded2);
    var pluralType = noPlural ? type : pluralize(type);
    if (shouldShow !== undefined ? !shouldShow : !annotationVisibility[pluralType] || Object.keys(row[pluralType] || {}).length <= 0) {
      return null;
    }
    var CompToUse = CompOverride || StackedAnnotations;
    return /*#__PURE__*/React.createElement(CompToUse, _extends({
      truncateLabelsThatDoNotFit: truncateLabelsThatDoNotFit,
      onlyShowLabelsThatDoNotFit: onlyShowLabelsThatDoNotFit,
      type: type,
      fullSequence: fullSequence,
      containerClassName: camelCase("veRowView-" + pluralType + "Container"),
      alignmentType: alignmentType
    }, annotationCommonProps, getPropsForType(props, type, pluralType, extraProps), otherExtraProps));
  };

  // a t g a t c a g g
  // 0 1 2 3 4 5 6 8 9
  //0 1 2 3 4 5 6 7 9

  var deletionLayersToDisplay = flatMap(_extends({}, replacementLayers, deletionLayers), function (layer) {
    if (layer.caretPosition > -1) {
      return [];
    }
    var overlaps = getOverlapsOfPotentiallyCircularRanges(layer, row, sequenceLength);
    return overlaps;
  });
  var deletionLayerStrikeThrough = deletionLayersToDisplay.length ? deletionLayersToDisplay.map(function (layer, index) {
    var left = (layer.start - row.start) * charWidth;
    var width = (layer.end - layer.start + 1) * charWidth;
    return /*#__PURE__*/React.createElement("div", {
      key: "deletionLayer" + index,
      className: "ve_sequence_strikethrough",
      style: {
        left: left,
        width: width,
        top: 10,
        height: 2,
        position: "absolute",
        background: "black"
      }
    });
  }) : null;
  var translationCommonProps = {
    CompOverride: Translations,
    showAminoAcidNumbers: showAminoAcidNumbers,
    sequenceLength: sequenceLength,
    aminoAcidNumbersHeight: aminoAcidNumbersHeight
  };
  var partProps = {
    getExtraInnerCompProps: function getExtraInnerCompProps(annotationRange) {
      var annotation = annotationRange.annotation;
      var color = annotation.color;
      var colorToUse = startsWith(color, "override_") ? color.replace("override_", "") : "#ac68cc";
      var extraProps = {};
      if (typeof extraAnnotationProps["part"] === "function") {
        extraProps = extraAnnotationProps["part"](annotation);
      }
      return _extends({
        textColor: colorToUse,
        stroke: colorToUse
      }, extraProps);
    },
    alignmentType: alignmentType
  };
  return /*#__PURE__*/React.createElement("div", {
    style: rowContainerStyle,
    onContextMenu: backgroundRightClicked,
    onScroll: onScroll,
    className: "veRowItemWrapper"
  }, rowTopComp && rowTopComp, /*#__PURE__*/React.createElement("div", {
    className: "veRowItem",
    style: rowStyle
  }, /*#__PURE__*/React.createElement(SelectionLayer, _extends({
    className: "veSearchLayerContainer",
    customTitleStart: "Search match"
    // color="yellow"
    // hideCarets
    ,
    regions: searchLayers
  }, annotationCommonProps, {
    selectionLayerRightClicked: searchLayerRightClicked,
    row: alignmentData ? {
      start: 0,
      end: alignmentData.sequence.length - 1
    } : row,
    onClick: searchLayerClicked
  })), /*#__PURE__*/React.createElement(SelectionLayer, _extends({
    isDraggable: true,
    selectionLayerRightClicked: selectionLayerRightClicked
  }, annotationCommonProps, {
    row: alignmentData ? {
      start: 0,
      end: alignmentData.sequence.length - 1
    } : row,
    regions: getAllSelectionLayers({
      additionalSelectionLayers: additionalSelectionLayers,
      selectionLayer: selectionLayer
    })
  })), drawAnnotations("warning"), drawAnnotations("assemblyPiece"), drawAnnotations("lineageAnnotation"), drawLabels("part"), drawAnnotations("part", partProps), drawAnnotations("orf", {
    CompOverride: Orfs
  }), charWidth > 4 && drawAnnotations("translation", _extends({}, translationCommonProps, {
    onDoubleClick: translationDoubleClicked
  })), showChromatogram && chromatogramData && /*#__PURE__*/React.createElement(Chromatogram, _extends({
    chromatogramData: chromatogramData,
    alignmentData: alignmentData,
    scalePct: scalePct,
    setScalePct: setScalePct
  }, annotationCommonProps)), drawLabels("cutsite", !isRowView), drawLabels("primer", false, {
    filterOpts: {
      onlyForward: true
    }
  }), drawAnnotations("primer", {
    sequence: fullSequence,
    isStriped: true,
    annotationHeight: primerHeight,
    onlyForward: true
  }), /*#__PURE__*/React.createElement("div", {
    className: "veRowItemSequenceContainer",
    style: {
      position: "relative"
    }
  }, showSequence && /*#__PURE__*/React.createElement(Sequence, _extends({
    sequenceLength: sequenceLength,
    cutsites: cutsites //pass this in order to get children cutsites to re-render
    ,
    showDnaColors: showDnaColors,
    fivePrimeThreePrimeHints: fivePrimeThreePrimeHints,
    scrollData: scrollData,
    hideBps: charWidth < 7,
    sequence: alignmentData ? alignmentData.sequence : row.sequence //from alignment data and has "-"" chars in it
    ,
    rowStart: row.start,
    rowEnd: row.end,
    height: sequenceHeight,
    showCutsites: showCutsites,
    charWidth: charWidth,
    alignmentData: alignmentData
  }, annotationCommonProps), showCutsites && Object.keys(cutsites).length > 0 && /*#__PURE__*/React.createElement(Cutsites, _extends({
    sequenceLength: sequenceLength,
    annotationRanges: cutsites,
    topStrand: true
  }, annotationCommonProps)), deletionLayerStrikeThrough), emptyText, showReverseSequence && /*#__PURE__*/React.createElement(Sequence, {
    scrollData: scrollData,
    sequenceLength: sequenceLength,
    fivePrimeThreePrimeHints: fivePrimeThreePrimeHints,
    isReverse: true,
    cutsites: cutsites //pass this in order to get children cutsites to re-render
    ,
    showDnaColors: showDnaColors,
    hideBps: charWidth < 7,
    length: reverseSequence.length,
    showCutsites: showCutsites,
    rowStart: row.start,
    rowEnd: row.end,
    sequence: reverseSequence,
    height: sequenceHeight,
    charWidth: charWidth
  }, showCutsites && Object.keys(cutsites).length > 0 && /*#__PURE__*/React.createElement(Cutsites, _extends({
    topStrand: false,
    annotationRanges: cutsites
  }, annotationCommonProps)), deletionLayerStrikeThrough), showCutsites && showCutsitesInSequence && /*#__PURE__*/React.createElement(CutsiteSelectionLayers, {
    editorName: editorName,
    cutsites: cutsites,
    annotationCommonProps: annotationCommonProps,
    showReverseSequence: showReverseSequence,
    sequenceHeight: sequenceHeight,
    alignmentData: alignmentData,
    row: row
  })), drawAnnotations("primer", {
    sequence: fullSequence,
    isStriped: true,
    annotationHeight: primerHeight,
    onlyReverse: true
  }), drawLabels("primer", false, {
    filterOpts: {
      onlyReverse: true
    }
  }), drawLabels("feature"), drawAnnotations("feature"), map(replacementLayers, function (replacementLayer) {
    if (!replacementLayer) return null;
    var atCaret = replacementLayer.caretPosition > -1;
    var normedCaretPos;
    if (atCaret) {
      normedCaretPos = normalizePositionByRangeLength(replacementLayer.caretPosition, sequenceLength);
    }
    var insertedBpsLayer = _extends({}, replacementLayer, {
      start: atCaret ? normedCaretPos : replacementLayer.start,
      end: (atCaret ? normedCaretPos : replacementLayer.start) + replacementLayer.sequence.length
    });
    var sequence = insertedBpsLayer.sequence;
    var layerRangeOverlaps = getOverlapsOfPotentiallyCircularRanges(insertedBpsLayer, row, sequenceLength);
    return layerRangeOverlaps.map(function (layer, index) {
      var isStart = layer.start === insertedBpsLayer.start;
      var seqInRow = getSequenceWithinRange({
        start: layer.start - insertedBpsLayer.start,
        end: layer.end - insertedBpsLayer.start
      }, sequence);
      var startOffset = layer.start - row.start;
      var width = seqInRow.length * charWidth;
      var height = sequenceHeight;
      var bufferBottom = 4;
      var bufferLeft = 2;
      var arrowHeight = isStart ? 8 : 0;
      return /*#__PURE__*/React.createElement(Sequence, {
        sequenceLength: sequenceLength,
        isReplacementLayer: true,
        showDnaColors: showDnaColors,
        key: index,
        sequence: seqInRow,
        startOffset: startOffset,
        height: height,
        length: seqInRow.length,
        charWidth: charWidth
      }, /*#__PURE__*/React.createElement("svg", {
        style: {
          left: startOffset * charWidth,
          height: sequenceHeight,
          position: "absolute"
        },
        ref: "rowViewTextContainer",
        onClick: function onClick(event) {
          replacementLayerClicked({
            annotation: replacementLayer,
            event: event
          });
        },
        onContextMenu: function onContextMenu(event) {
          replacementLayerRightClicked({
            annotation: replacementLayer,
            event: event
          });
        },
        className: "rowViewTextContainer clickable",
        width: Math.max(0, Number(width)),
        height: Math.max(0, Number(height))
      }, /*#__PURE__*/React.createElement("polyline", {
        points: -bufferLeft + ",0 " + -bufferLeft + "," + -arrowHeight + ", " + charWidth / 2 + ",0 " + width + ",0 " + width + "," + (height + bufferBottom) + " " + -bufferLeft + "," + (height + bufferBottom) + " " + -bufferLeft + ",0",
        fill: "none",
        stroke: "black",
        strokeWidth: "2px"
      })));
    });
  }), drawAnnotations("primaryProteinSequence", _extends({}, translationCommonProps, {
    noPlural: true
  })), drawLabels("cutsite", isRowView), showAxis && /*#__PURE__*/React.createElement(Axis, _extends({
    scrollData: scrollData,
    tickSpacing: tickSpacing,
    showAxisNumbers: showAxisNumbers,
    annotationHeight: axisHeight,
    marginTop: axisMarginTop
  }, annotationCommonProps, {
    isLinearView: isLinearView
  })), caretPosition > -1 && /*#__PURE__*/React.createElement(Caret, _extends({
    caretPosition: caretPosition
  }, _extends({}, annotationCommonProps, {
    getGaps: undefined
  }), {
    row: alignmentData ? {
      start: 0,
      end: alignmentData.sequence.length - 1
    } : row
  }))), rowBottomComp && rowBottomComp);
}
function getGapMap(sequence) {
  var gapMap = [0]; //a map of position to how many gaps come before that position [0,0,0,5,5,5,5,17,17,17, ]
  sequence.split("").forEach(function (_char) {
    if (_char === "-") {
      gapMap[Math.max(0, gapMap.length - 1)] = (gapMap[Math.max(0, gapMap.length - 1)] || 0) + 1;
    } else {
      gapMap.push(gapMap[gapMap.length - 1] || 0);
      // gapMap[gapMap.length] =
    }
  });

  return gapMap;
}
// var a = getGapMap("---tagccc---tagasdfw--gg")
function getGapsDefault() {
  return {
    gapsBefore: 0,
    gapsInside: 0
  };
}