function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
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); }
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 _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); }
import React from "react";
import { times, map } from "lodash";
import { view } from "@risingstack/react-easy-state";
import { getVisibleStartEnd } from "../utils/getVisibleStartEnd";
import { fudge2, realCharWidth } from "./constants";
import dnaToColor, { getDnaColor } from "../constants/dnaToColor";
import { hoveredAnnEasyStore } from "../helperComponents/withHover";
import { getOverlapsOfPotentiallyCircularRanges } from "@teselagen/range-utils";
import { partOverhangs } from "./partOverhangs";
import { isPositionWithinRange } from "@teselagen/range-utils";
var getChunk = function getChunk(sequence, chunkSize, chunkNumber) {
  return sequence.slice(chunkSize * chunkNumber, chunkSize * (chunkNumber + 1));
};
var Sequence = /*#__PURE__*/function (_React$Component) {
  _inheritsLoose(Sequence, _React$Component);
  function Sequence() {
    return _React$Component.apply(this, arguments) || this;
  }
  var _proto = Sequence.prototype;
  _proto.render = function render() {
    var _this$props = this.props,
      isReplacementLayer = _this$props.isReplacementLayer,
      sequence = _this$props.sequence,
      hideBps = _this$props.hideBps,
      charWidth = _this$props.charWidth,
      _this$props$container = _this$props.containerStyle,
      containerStyle = _this$props$container === void 0 ? {} : _this$props$container,
      children = _this$props.children,
      isReverse = _this$props.isReverse,
      height = _this$props.height,
      className = _this$props.className,
      _this$props$startOffs = _this$props.startOffset,
      startOffset = _this$props$startOffs === void 0 ? 0 : _this$props$startOffs,
      _this$props$chunkSize = _this$props.chunkSize,
      chunkSize = _this$props$chunkSize === void 0 ? 100 : _this$props$chunkSize,
      scrollData = _this$props.scrollData,
      showDnaColors = _this$props.showDnaColors,
      fivePrimeThreePrimeHints = _this$props.fivePrimeThreePrimeHints,
      alignmentData = _this$props.alignmentData,
      sequenceLength = _this$props.sequenceLength,
      rowStart = _this$props.rowStart,
      rowEnd = _this$props.rowEnd;

    // the fudge factor is used to position the sequence in the middle of the <text> element
    var fudge = charWidth - realCharWidth;
    var gapsBeforeSequence = 0;
    var seqReadWidth = 0;
    var rowSeqLen = sequence.length;
    var overlapToBold;
    var isDigestPart;
    [hoveredAnnEasyStore.hoveredAnn].forEach(function (ann) {
      if (ann && !isReplacementLayer) {
        var start = ann.start;
        var end = ann.end - 1;
        partOverhangs.forEach(function (h) {
          if (ann[h]) {
            isDigestPart = true;
            if (h.includes("Underhang") && isReverse) {
              return;
            } else if (h.includes("Overhang") && !isReverse) {
              return;
            }
            var overhangBps = ann[h];
            if (h.includes("fivePrime")) {
              start = start + overhangBps.length;
            } else {
              end = end - overhangBps.length;
            }
          }
        });
        overlapToBold = isDigestPart ? getOverlapsOfPotentiallyCircularRanges({
          start: start,
          end: end
        }, {
          start: rowStart,
          end: rowEnd
        }, sequenceLength) : undefined;
      }
    });
    var style = _extends({
      position: "relative",
      height: height,
      left: gapsBeforeSequence * charWidth
    }, containerStyle);
    var width = rowSeqLen * charWidth;
    var inner;
    var shared = {
      y: height - height / 4,
      className: "ve-monospace-font " + (isReverse ? " ve-sequence-reverse" : "")
    };
    if (scrollData) {
      var numChunks = Math.ceil(rowSeqLen / chunkSize);
      var chunkWidth = chunkSize * charWidth;
      //we're in the alignment view alignments only
      var _getVisibleStartEnd = getVisibleStartEnd({
          scrollData: scrollData,
          width: width
        }),
        visibleStart = _getVisibleStartEnd.visibleStart,
        visibleEnd = _getVisibleStartEnd.visibleEnd;
      inner = times(numChunks, function (i) {
        var seqChunk = getChunk(sequence, chunkSize, i);
        var textLength = charWidth * seqChunk.length;
        var x = i * chunkWidth;
        if (x > visibleEnd || x + textLength < visibleStart) return null;
        return /*#__PURE__*/React.createElement("text", _extends({
          key: i
        }, _extends({}, shared, {
          textLength: textLength - fudge - fudge2,
          x: x + fudge / 2,
          lengthAdjust: "spacing"
        })), seqChunk);
      });
    } else {
      inner = /*#__PURE__*/React.createElement("text", _extends({}, shared, {
        x: 0 + fudge / 2,
        textLength: (alignmentData ? seqReadWidth : width) - fudge - fudge2
      }), getBoldRegion({
        sequence: sequence,
        overlapToBold: overlapToBold,
        rowStart: rowStart,
        sequenceLength: sequenceLength
      }));
    }
    return /*#__PURE__*/React.createElement("div", {
      style: style,
      className: (className ? className : "") + " ve-row-item-sequence"
    }, fivePrimeThreePrimeHints && /*#__PURE__*/React.createElement("div", {
      className: "tg-" + (isReverse ? "left" : "right") + "-prime-direction tg-prime-direction"
    }, "3'"), fivePrimeThreePrimeHints && /*#__PURE__*/React.createElement("div", {
      className: "tg-" + (isReverse ? "right" : "left") + "-prime-direction tg-prime-direction"
    }, "5'"), !hideBps && /*#__PURE__*/React.createElement("svg", {
      style: {
        left: startOffset * charWidth,
        height: height,
        width: width,
        position: "absolute"
      },
      ref: "rowViewTextContainer",
      className: "rowViewTextContainer",
      height: Math.max(0, Number(height))
    }, showDnaColors && /*#__PURE__*/React.createElement(ColoredSequence, _extends({}, this.props, {
      fudge: fudge,
      totalWidth: width
    })), inner), children);
  };
  return Sequence;
}(React.Component);
export default view(Sequence);
var ColoredSequence = /*#__PURE__*/function (_React$Component2) {
  _inheritsLoose(ColoredSequence, _React$Component2);
  function ColoredSequence() {
    var _this;
    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
      args[_key] = arguments[_key];
    }
    _this = _React$Component2.call.apply(_React$Component2, [this].concat(args)) || this;
    _defineProperty(_assertThisInitialized(_this), "drawRects", function () {
      var _this$props2 = _this.props,
        charWidth = _this$props2.charWidth,
        sequence = _this$props2.sequence,
        height = _this$props2.height,
        isReverse = _this$props2.isReverse,
        alignmentData = _this$props2.alignmentData,
        getGaps = _this$props2.getGaps,
        fudge = _this$props2.fudge,
        totalWidth = _this$props2.totalWidth;
      if (alignmentData) {
        sequence = sequence.replace(/^-+/g, "").replace(/-+$/g, "");
      }
      //we use big paths instead of many individual rects to improve performance
      var colorPaths = Object.values(dnaToColor).reduce(function (acc, color) {
        acc[color] = "";
        return acc;
      }, {});
      var gapsBefore = getGaps ? getGaps({
        start: 0,
        end: 0
      }).gapsBefore : 0;
      sequence.split("").forEach(function (_char, i) {
        var width = Number(charWidth);
        var color = getDnaColor(_char, isReverse);
        var x = (i + gapsBefore) * charWidth;
        var y = 0;
        colorPaths[color] = (colorPaths[color] || "") + ("M" + x + "," + y + " L" + (x + width) + "," + y + " L" + (x + width) + "," + (y + height) + " L" + x + "," + (y + height));
      });
      var scalex = (totalWidth - fudge) / totalWidth;
      return /*#__PURE__*/React.createElement("g", {
        style: {
          transform: "scaleX(" + scalex + ")"
        }
      }, map(colorPaths, function (d, color) {
        return /*#__PURE__*/React.createElement("path", {
          transform: "tran",
          key: color,
          d: d,
          fill: color
        });
      }));
    });
    return _this;
  }
  var _proto2 = ColoredSequence.prototype;
  _proto2.shouldComponentUpdate = function shouldComponentUpdate(newProps) {
    var props = this.props;
    if (["charWidth", "sequence", "height", "isReverse", "width"].some(function (key) {
      return props[key] !== newProps[key];
    })) return true;
    if (!!props.alignmentData !== !!newProps.alignmentData) return true;
    return false;
  };
  _proto2.render = function render() {
    return this.drawRects();
  };
  return ColoredSequence;
}(React.Component);
function getBoldRegion(_ref) {
  var sequence = _ref.sequence,
    overlapToBold = _ref.overlapToBold,
    rowStart = _ref.rowStart,
    sequenceLength = _ref.sequenceLength;
  var toRet = [];
  var _ref2 = overlapToBold || [],
    a = _ref2[0],
    b = _ref2[1];
  for (var index = rowStart; index < sequence.length + rowStart; index++) {
    var element = sequence[index - rowStart];
    if (a && isPositionWithinRange(index, a, sequenceLength, true, true) || b && isPositionWithinRange(index, b, sequenceLength, true, true)) {
      toRet.push( /*#__PURE__*/React.createElement("tspan", {
        className: "isBoldSeq"
      }, element));
    } else {
      toRet.push(element);
    }
  }
  return toRet;
}