/**
   * Get component to be rendered, if pos outside of current range getFeatureAtPosition and reset
   * currentRange, if feature is non null and not an instance of FeatureSetI then its an exon, and
   * set isExon flag
   */
  public Component getBaseComponent(int position, TierI tier, Orientation o) {

    transcript = null;

    int bp = tier.getBasePair(position);
    int oldPos = position;

    // We need to change the position if dealing with aa view
    if (tier.getType() == SequenceType.AA) {
      int offset = getOffset(position, tier);
      bp += offset * tier.getStrand().toInt();
      position = tier.getPosition(bp);
    }

    char base = tier.charAt(position);

    if (tier.featureExsitsAt(position, TierI.Level.BOTTOM)) {
      this.state = State.EXON;
      SeqFeatureI feature = tier.featureAt(position, TierI.Level.BOTTOM);
      Transcript parentClone = null;
      Transcript otherParentClone = null;

      if (tier.getType() == SequenceType.AA
          && feature.getParent() != null
          && feature.getParent().isTranscript()) {

        FeatureSetI parent = feature.getParent();
        int index = parent.getFeatureIndex(feature);

        int start = parent.getEnd();
        // the transcript start might be different than the lowest exon start
        // when in the middle of an edit
        if (parent.canHaveChildren()) {
          for (int i = 0; i < parent.size(); i++) {
            SeqFeatureI sf = parent.getFeatureAt(i);
            if ((Strand.valueOf(sf.getStrand()) == Strand.FORWARD && sf.getStart() < start)
                || (Strand.valueOf(sf.getStrand()) == Strand.REVERSE && sf.getStart() > start))
              start = sf.getStart();
          }
        }

        int translationStart = parent.getTranslationStart();
        int translationEnd = parent.getTranslationEnd();
        int translationPos = parent.getFeaturePosition(translationStart);
        int oldstart = start;
        start += ((translationPos - 1) % 3) * parent.getStrand();

        // Tring to avoid all the recalculation...
        if (feature.getParent() == currentParent
            && start == currentStart
            && featureStart == feature.getStart()
            && featureEnd == feature.getEnd()) {
          parentClone = currentParentClone;
          otherParentClone = currentParentClone2;
        } else {
          // need to get a full translation so that we can get the amino acids
          // in the UTR region
          parentClone = (Transcript) feature.getParent().clone();
          otherParentClone = (Transcript) feature.getParent().clone();

          if (!parentClone.setTranslationStart(start)) {
            start = oldstart;
            TranslationI cds = otherParentClone.getTranslation();
            cds.calcTranslationStartForLongestPeptide();
            translationStart = otherParentClone.getTranslationStart();
            translationPos = otherParentClone.getFeaturePosition(translationStart);
            start += ((translationPos - 1) % 3) * otherParentClone.getStrand();
            parentClone.setTranslationStart(start);
          }

          parentClone.setTranslationEnd(parentClone.getEnd());
          parentClone.setPeptideSequence(null);

          String translation = parentClone.translate();
          SequenceI sequence = parentClone.getPeptideSequence();

          currentParent = (Transcript) feature.getParent();
          currentParentClone = parentClone;
          currentParentClone2 = otherParentClone;
          currentStart = start;
          featureStart = feature.getStart();
          featureEnd = feature.getEnd();

          if (otherParentClone.getFeatureContaining(translationEnd) == null) {
            TranslationI cds = otherParentClone.getTranslation();
            cds.setTranslationEndFromStart();
          }
        }

        SeqFeatureI sf = parentClone.getFeatureAt(index);

        if (bp >= sf.getLow() && bp <= sf.getHigh()) {
          base = getPeptide(bp, sf);
        } else {
          base = '\0';
        }

        if (otherParentClone != null) {
          feature = otherParentClone.getFeatureAt(index);
        }

      } else if (tier.getType() == SequenceType.AA
          && feature.getParent() != null
          && !feature.getParent().isTranscript()) {
        base = '\0';
      }

      if (isUTR(bp, feature, tier)) {
        this.state = State.UTR;
      }

      if (isTranslationStart(bp, feature)) {
        this.state = State.TRANSLATION_START;
      }

      if (isTranslationEnd(bp, feature)) {
        this.state = State.TRANSLATION_END;
      }

      // Can have an error or a shift on a position but not both
      if (isSequencingErrorPosition(bp, feature, tier.getType())) {
        this.state = State.ERROR;
        // set base to the base of the new sequence?
      }

      if (isShiftPosition(bp, feature, tier.getType())) {
        this.state = State.SHIFT;
      }

    } else if (tier.featureExsitsAt(position, TierI.Level.TOP)) {
      SeqFeatureI feature = tier.featureAt(position, Level.TOP);
      this.state = State.INTRON;
      if (tier.getType() == SequenceType.AA) {
        base = '\0';
      }

      int start = feature.getEnd();
      int end = feature.getStart();

      if (feature.canHaveChildren()) {
        for (int i = 0; i < feature.size(); i++) {
          SeqFeatureI sf = feature.getFeatureAt(i);
          if ((Strand.valueOf(sf.getStrand()) == Strand.FORWARD && sf.getStart() < start)
              || (Strand.valueOf(sf.getStrand()) == Strand.REVERSE && sf.getStart() > start))
            start = sf.getStart();

          if ((Strand.valueOf(sf.getStrand()) == Strand.FORWARD && sf.getEnd() > end)
              || (Strand.valueOf(sf.getStrand()) == Strand.REVERSE && sf.getEnd() < end))
            end = sf.getEnd();
        }
      }

      if (bp <= Math.min(start, end) || bp >= Math.max(start, end)) {
        this.state = State.OUT;
        base = '\0';
      }
    } else {
      this.state = State.OUT;
      base = '\0';
    }

    if (!(state == State.SHIFT || state == State.ERROR)
        && getRegionLow() <= position
        && position <= getRegionHigh()) {
      this.state = State.SELECTED;
      base = tier.charAt(oldPos);
    }

    init(base);
    return this;
  }
  /**
   * If right mouse deselect base If end of feature drag notify AnnotationEditor (endRangeChange)
   * and recalc translation end from start
   */
  public void mouseReleased(MouseEvent e) {

    // RIGHT MOUSE CLICK
    if (MouseButtonEvent.isRightMouseClick(e)) {
      BaseRenderer rend = baseEditorPanel.getRendererAt(tier);
      if (rend instanceof SelectableDNARenderer) {
        ((SelectableDNARenderer) rend).setTargetPos(-1, -1);
        baseEditorPanel.repaint();
      }
    }

    // SEQ SELECT DRAG
    if (dragType == baseEditorPanel.SEQ_SELECT_DRAG) {
      SequenceI seq = baseEditorPanel.getSequenceForTier(startDragTier);
      int lowBP = baseEditorPanel.posToResidue(baseEditorPanel.selectLowPos());
      int highBP = baseEditorPanel.posToResidue(baseEditorPanel.selectHighPos());
      String sequence = seq.getResidues(lowBP, highBP);

      String header = " Arbitrary selection (" + seq.getName() + ": " + lowBP + "," + highBP + ")";

      // controllingWindow.copySeqToClipboard(new Sequence (header, sequence));
      ClipboardUtil.copySeqToClipboard(new Sequence(header, sequence));

      resetDragState();
      baseEditorPanel.repaint();
      return;
    }

    // NOT SEQ SELECT DRAG
    else {

      // NOT DRAGGING - RETURN
      if (!MouseButtonEvent.isLeftMouseClick(e) || !dragging || dragFeature == null) {
        resetDragState();
        return;
      }

      // DRAGGING ANNOT ENDS
      if (dragging && dragFeature != null && dragFeature.isAnnot()) {

        // NOTIFY ANNOTATION EDITOR (generates transaction)
        int oldStart = (preDragStartBasePair == -1) ? dragFeature.getStart() : preDragStartBasePair;
        int oldEnd = (preDragEndBasePair == -1) ? dragFeature.getEnd() : preDragEndBasePair;
        AnnotationEditor ae = baseEditorPanel.getAnnotationEditor();
        ae.setAnnotTerminus(
            dragFeature.getAnnotatedFeature(),
            oldStart,
            oldEnd,
            dragFeature.getStart(),
            dragFeature.getEnd());

        // RECALC CDS (if exon/transcript - not for 1 level annots)
        if (dragFeature.isExon()
            && dragFeature.getRefFeature() != null
            && (dragFeature.getRefFeature().isTranscript())) {
          // ExonI exon = (ExonI)dragFeature;
          // Transcript t = (Transcript)exon.getRefFeature();
          SeqFeatureI transcript = dragFeature.getRefFeature();
          TranslationI cds = transcript.getTranslation();
          int transStart = transcript.getStart();
          int cdsStart = cds.getTranslationStart();
          boolean isForward = transcript.isForwardStrand();
          if (cds.isMissing5prime()
              && ((isForward && transStart < cdsStart) || (!isForward && transStart > cdsStart))) {
            cds.calcTranslationStartForLongestPeptide(); // missing start
          } else {
            cds.setTranslationEndFromStart(); // got start - set end
          }
        }

        baseEditorPanel.repaint();
      }
    }

    resetDragState();
    baseEditorPanel.getCurationState().getSZAP().repaint();
  }