+ 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
+ */
+ @Override
+ public int hashCode()
+ {
+ try
+ {
+ LOCK.readLock().lock();
+ int hashCode = 1;
+ if (hiddenColumns != null)
+ {
+ for (int[] hidden : hiddenColumns)
+ {
+ hashCode = 31 * hashCode + hidden[0];
+ hashCode = 31 * hashCode + hidden[1];
+ }
+ }
+ return hashCode;
+ }
+ finally
+ {
+ LOCK.readLock().unlock();
+ }
+ }
+
+ /**
+ * Hide columns corresponding to the marked bits
+ *
+ * @param inserts
+ * - columns map to bits starting from zero
+ */
+ public void hideMarkedBits(BitSet inserts)
+ {
+ try
+ {
+ LOCK.writeLock().lock();
+ for (int firstSet = inserts
+ .nextSetBit(0), lastSet = 0; firstSet >= 0; firstSet = inserts
+ .nextSetBit(lastSet))
+ {
+ lastSet = inserts.nextClearBit(firstSet);
+ hideColumns(firstSet, lastSet - 1);
+ }
+ } finally
+ {
+ LOCK.writeLock().unlock();
+ }
+ }
+
+ /**
+ *
+ * @param inserts
+ * BitSet where hidden columns will be marked
+ */
+ public void markHiddenRegions(BitSet inserts)
+ {
+ try
+ {
+ LOCK.readLock().lock();
+ if (hiddenColumns == null)
+ {
+ return;
+ }
+ for (int[] range : hiddenColumns)
+ {
+ inserts.set(range[0], range[1] + 1);
+ }
+ }
+ finally
+ {
+ LOCK.readLock().unlock();
+ }
+ }
+
+ /**
+ * Calculate the visible start and end index of an alignment.
+ *
+ * @param width
+ * full alignment width
+ * @return integer array where: int[0] = startIndex, and int[1] = endIndex
+ */
+ public int[] getVisibleStartAndEndIndex(int width)
+ {
+ try
+ {
+ LOCK.readLock().lock();
+ int[] alignmentStartEnd = new int[] { 0, width - 1 };
+ int startPos = alignmentStartEnd[0];
+ int endPos = alignmentStartEnd[1];
+
+ int[] lowestRange = new int[] { -1, -1 };
+ int[] higestRange = new int[] { -1, -1 };
+
+ if (hiddenColumns == null)
+ {
+ return new int[] { startPos, endPos };
+ }
+
+ for (int[] hiddenCol : hiddenColumns)
+ {
+ lowestRange = (hiddenCol[0] <= startPos) ? hiddenCol : lowestRange;
+ higestRange = (hiddenCol[1] >= endPos) ? hiddenCol : higestRange;
+ }
+
+ if (lowestRange[0] == -1 && lowestRange[1] == -1)
+ {
+ startPos = alignmentStartEnd[0];
+ }
+ else
+ {
+ startPos = lowestRange[1] + 1;