/**
  * Verify that the match is what it is supposed to be
  *
  * @param end don't go beyond this node
  */
 void verify(VariantGraphNode<T> end) {
   VariantGraphNode<T> temp = start;
   int pos = graphOffset;
   int compared = 0;
   while (temp != null && compared < length) {
     assert temp != end;
     VariantGraphArc<T> a = temp.pickOutgoingArc(version);
     if (a.dataLen() < pos) {
       pos -= a.dataLen();
     } else if (a.dataLen() == pos) {
       pos = 0;
       temp = a.to;
     } else if (a.dataLen() == 0) {
       temp = a.to;
       continue;
     } else {
       List<T> arcData = a.getData();
       while (compared < length && pos < a.dataLen()) {
         // FIXME: increment in assertion!
         assert arcData.get(pos++).equals(data.get(compared++));
         if (pos == a.dataLen()) {
           pos = 0;
           break;
         }
       }
     }
     temp = a.to;
   }
 }
 /**
  * Do we use any part of the path in the graph that is also used by another match?
  *
  * @param b the other Match
  * @return true if the b match uses any arc from our path
  */
 public boolean overlaps(VariantGraphMatch<T> b) {
   VariantGraphArc<T> aArc = start.pickOutgoingArc(version);
   VariantGraphArc<T> bArc = b.start.pickOutgoingArc(b.version);
   int i = 0;
   int aCurrArcIndex = 0;
   int bCurrArcIndex = 0;
   // advance to match-start in a
   while (i < graphOffset) {
     if (i + aArc.dataLen() < graphOffset) {
       i += aArc.dataLen();
       aArc = aArc.to.pickOutgoingArc(version);
       aCurrArcIndex = 0;
     } else {
       aCurrArcIndex = graphOffset - i;
       i = graphOffset;
     }
   }
   i = 0;
   // advance to match-start in b
   while (i < b.graphOffset) {
     if (i + bArc.dataLen() < b.graphOffset) {
       i += bArc.dataLen();
       bArc = bArc.to.pickOutgoingArc(b.version);
       bCurrArcIndex = 0;
     } else {
       bCurrArcIndex = b.graphOffset - i;
       i = b.graphOffset;
     }
   }
   // advance byte by byte to match-end
   i = 0;
   while (i < length) {
     if (aArc == bArc && aCurrArcIndex == bCurrArcIndex) {
       return true;
     } else {
       // move to next a-arc
       while (aCurrArcIndex == aArc.dataLen()) {
         aArc = aArc.to.pickOutgoingArc(version);
         aCurrArcIndex = 0;
       }
       aCurrArcIndex++;
       // move to next b-arc
       while (bCurrArcIndex == bArc.dataLen()) {
         bArc = bArc.to.pickOutgoingArc(b.version);
         bCurrArcIndex = 0;
       }
       bCurrArcIndex++;
       i++;
     }
   }
   return false;
 }
 /**
  * Check that no element of the path contains the new version or is a parent whose child contains
  * that version.
  *
  * @param newVersion the new version that the arc can't traverse
  * @return true if the conditions hold, false otherwise
  */
 boolean checkPath(Witness newVersion) {
   VariantGraphArc<T> a = start.pickOutgoingArc(version);
   int posWithinArc = 0;
   int distTravelled = 0;
   // advance to graphOffset
   while (distTravelled < graphOffset) {
     if (distTravelled + a.dataLen() < graphOffset) {
       distTravelled += a.dataLen();
       a = a.to.pickOutgoingArc(version);
       posWithinArc = 0;
     } else {
       posWithinArc = graphOffset - distTravelled;
       break;
     }
   }
   // now traverse the path
   if (a.versions.contains(newVersion) || (a.isParent() && a.hasChildInVersion(newVersion))) {
     return false;
   } else {
     distTravelled = 0;
     while (distTravelled < length) {
       // move to next arc
       while (posWithinArc == a.dataLen()) {
         a = a.to.pickOutgoingArc(version);
         if (a.versions.contains(newVersion)
             || (a.isParent() && a.hasChildInVersion(newVersion))) {
           return false;
         }
         posWithinArc = 0;
       }
       posWithinArc++;
       distTravelled++;
     }
     return true;
   }
 }
 /**
  * Separate out the path from the graph by adding new nodes as required. If already split off just
  * returns the path. Note that we first split all the arcs as required, then retraverse the path
  * to put the split arcs into the array. This way we don't accidentally split an arc already in
  * the array of arcs we are building.
  *
  * @return an array of arcs belonging to the match path
  */
 VariantGraphArc<T>[] getMatchPath() throws MVDException {
   if (path == null || !isPathValid()) {
     Vector<VariantGraphArc<T>> parents = new Vector<VariantGraphArc<T>>();
     VariantGraphArc<T>[] splits;
     VariantGraphArc<T> a = start.pickOutgoingArc(version);
     assert a != null;
     int distance = 0;
     int splitStart = 0;
     int splitEnd = 0;
     // move forward to graphOffset
     // NB leading arcs may be empty
     while (distance <= graphOffset) {
       if (distance + a.dataLen() <= graphOffset) {
         distance += a.dataLen();
         a = a.to.pickOutgoingArc(version);
         assert a != null && a.versions.contains(version);
       } else {
         splitStart = graphOffset - distance;
         distance = graphOffset;
         break;
       }
     }
     // if the split-point is not 0, split
     if (splitStart > 0) {
       assert a.versions.contains(version);
       splits = a.split(splitStart);
       a = splits[1];
       assert a != null && a.versions.contains(version);
     }
     // now advance distance to the end of the match
     // a is the first arc of the path
     while (distance < graphOffset + length) {
       assert a != null;
       if (distance + a.dataLen() <= graphOffset + length) {
         distance += a.dataLen();
         // parents.add( a );
         VariantGraphArc<T> b = a.to.pickOutgoingArc(version);
         if (b == null) // if a.to is the end-node
         {
           assert a.to.outdegree() == 0;
           break;
         } else {
           assert a.versions.contains(version);
           a = b;
         }
       } else {
         splitEnd = graphOffset + length - distance;
         distance = graphOffset + length;
       }
     }
     if (splitEnd > 0) {
       splits = a.split(splitEnd);
       // a = splits[0];
       // parents.add( a );
     }
     // now retraverse the path (which should now be
     // correctly split) and build the path array
     a = start.pickOutgoingArc(version);
     distance = 0;
     // move back to start of path - should fit exactly
     while (distance < graphOffset) {
       distance += a.dataLen();
       a = a.to.pickOutgoingArc(version);
     }
     assert distance == graphOffset;
     distance = 0;
     while (distance < length) {
       parents.add(a);
       distance += a.dataLen();
       a = a.to.pickOutgoingArc(version);
     }
     assert distance == length;
     splits = new VariantGraphArc[parents.size()];
     path = parents.toArray(splits);
   }
   return path;
 }