+ * Add gaps into the sequences aligned to profileseq under the given
+ * AlignmentView
+ *
+ * @param profileseq
+ * @param al
+ * - alignment to have gaps inserted into it
+ * @param input
+ * - alignment view where sequence corresponding to profileseq is
+ * first entry
+ * @return new HiddenColumns for new alignment view, with insertions into
+ * profileseq marked as hidden.
+ */
+ public static HiddenColumns propagateInsertions(SequenceI profileseq,
+ AlignmentI al, AlignmentView input)
+ {
+ int profsqpos = 0;
+
+ char gc = al.getGapCharacter();
+ Object[] alandhidden = input.getAlignmentAndHiddenColumns(gc);
+ HiddenColumns nview = (HiddenColumns) alandhidden[1];
+ SequenceI origseq = ((SequenceI[]) alandhidden[0])[profsqpos];
+ nview.propagateInsertions(profileseq, al, origseq);
+ return nview;
+ }
+
+ /**
+ *
+ * @param profileseq
+ * - sequence in al which corresponds to origseq
+ * @param al
+ * - alignment which is to have gaps inserted into it
+ * @param origseq
+ * - sequence corresponding to profileseq which defines gap map for
+ * modifying al
+ */
+ private void propagateInsertions(SequenceI profileseq, AlignmentI al,
+ SequenceI origseq)
+ {
+ char gc = al.getGapCharacter();
+ // recover mapping between sequence's non-gap positions and positions
+ // mapping to view.
+ pruneDeletions(ShiftList.parseMap(origseq.gapMap()));
+ int[] viscontigs = al.getHiddenColumns().getVisibleContigs(0,
+ profileseq.getLength());
+ int spos = 0;
+ int offset = 0;
+
+ // add profile to visible contigs
+ for (int v = 0; v < viscontigs.length; v += 2)
+ {
+ if (viscontigs[v] > spos)
+ {
+ StringBuffer sb = new StringBuffer();
+ for (int s = 0, ns = viscontigs[v] - spos; s < ns; s++)
+ {
+ sb.append(gc);
+ }
+ for (int s = 0, ns = al.getHeight(); s < ns; s++)
+ {
+ SequenceI sqobj = al.getSequenceAt(s);
+ if (sqobj != profileseq)
+ {
+ String sq = al.getSequenceAt(s).getSequenceAsString();
+ if (sq.length() <= spos + offset)
+ {
+ // pad sequence
+ int diff = spos + offset - sq.length() - 1;
+ if (diff > 0)
+ {
+ // pad gaps
+ sq = sq + sb;
+ while ((diff = spos + offset - sq.length() - 1) > 0)
+ {
+ // sq = sq
+ // + ((diff >= sb.length()) ? sb.toString() : sb
+ // .substring(0, diff));
+ if (diff >= sb.length())
+ {
+ sq += sb.toString();
+ }
+ else
+ {
+ char[] buf = new char[diff];
+ sb.getChars(0, diff, buf, 0);
+ sq += buf.toString();
+ }
+ }
+ }
+ sq += sb.toString();
+ }
+ else
+ {
+ al.getSequenceAt(s).setSequence(
+ sq.substring(0, spos + offset) + sb.toString()
+ + sq.substring(spos + offset));
+ }
+ }
+ }
+ // offset+=sb.length();
+ }
+ spos = viscontigs[v + 1] + 1;
+ }
+ if ((offset + spos) < profileseq.getLength())
+ {
+ // pad the final region with gaps.
+ StringBuffer sb = new StringBuffer();
+ for (int s = 0, ns = profileseq.getLength() - spos - offset; s < ns; s++)
+ {
+ sb.append(gc);
+ }
+ for (int s = 0, ns = al.getHeight(); s < ns; s++)
+ {
+ SequenceI sqobj = al.getSequenceAt(s);
+ if (sqobj == profileseq)
+ {
+ continue;
+ }
+ String sq = sqobj.getSequenceAsString();
+ // pad sequence
+ int diff = origseq.getLength() - sq.length();
+ while (diff > 0)
+ {
+ // sq = sq
+ // + ((diff >= sb.length()) ? sb.toString() : sb
+ // .substring(0, diff));
+ if (diff >= sb.length())
+ {
+ sq += sb.toString();
+ }
+ else
+ {
+ char[] buf = new char[diff];
+ sb.getChars(0, diff, buf, 0);
+ sq += buf.toString();
+ }
+ diff = origseq.getLength() - sq.length();
+ }
+ }
+ }
+ }
+
+ /**
+ * remove any hiddenColumns or selected columns and shift remaining based on a
+ * series of position, range deletions.
+ *
+ * @param deletions
+ */
+ private void pruneDeletions(ShiftList deletions)
+ {
+ if (deletions != null)
+ {
+ final List<int[]> shifts = deletions.getShifts();
+ if (shifts != null && shifts.size() > 0)
+ {
+ pruneDeletions(shifts);
+
+ // and shift the rest.
+ this.compensateForEdits(deletions);
+ }
+ }
+ }
+
+ /**
+ * Adjust hidden column boundaries based on a series of column additions or
+ * deletions in visible regions.
+ *
+ * @param shiftrecord
+ * @return
+ */
+ private ShiftList compensateForEdits(ShiftList shiftrecord)
+ {
+ if (shiftrecord != null)
+ {
+ final List<int[]> shifts = shiftrecord.getShifts();
+ if (shifts != null && shifts.size() > 0)
+ {
+ int shifted = 0;
+ for (int i = 0, j = shifts.size(); i < j; i++)
+ {
+ int[] sh = shifts.get(i);
+ compensateForDelEdits(shifted + sh[0], sh[1]);
+ shifted -= sh[1];
+ }
+ }
+ return shiftrecord.getInverse();
+ }
+ return null;
+ }
+
+ /**
+ * Returns a hashCode built from hidden column ranges