docs: private boolean _findMatches() throws IOException {
      // queue not empty
      if (!queueMatches.isEmpty()) {
        return true;
        // no more matches to be found
      } else if (currentPosition == NO_MORE_POSITIONS) {
        return false;
        // try to find matches
      } else {
        // subMatches: try to build matches while collecting
        Integer subMatchesStartPosition = null;
        Boolean subMatchesOptional = true;
        List<Match> subMatchesQueue = new ArrayList<>();
        // minimum startPosition previous, used to set lower boundary on
        // startPosition next
        Integer minStartPositionPrevious = null;
        // maximum endPosition previous, used to set upper boundary on
        // startPosition next
        Integer maxEndPositionPrevious = null;
        // other variables
        Integer minStartPositionNext = null;
        Integer minStartPosition = null;
        Integer minOptionalStartPosition = null;
        // adjusted minimum ignoreItem
        boolean adjustedMinimumIgnoreItem = false;
        // fill queue if necessary and possible
        for (int i = 0; i < queueSpans.size(); i++) {
          QueueItem item = queueSpans.get(i);
          // if span is optional, check docId
          if (!item.sequenceSpans.optional || (item.sequenceSpans.spans != null
              && item.sequenceSpans.spans.docID() == docId)) {
            // compute minimum startPosition until next non-optional item
            // used as lower boundary on endPosition next
            minStartPositionNext = null;
            for (int j = (i + 1); j < queueSpans.size(); j++) {
  
              // check for available lowestPosition
              if (!queueSpans.get(j).sequenceSpans.optional
                  && queueSpans.get(j).lowestPosition != null) {
                minStartPositionNext = (minStartPositionNext == null)
                    ? queueSpans.get(j).lowestPosition
                    : Math.min(minStartPositionNext,
                        queueSpans.get(j).lowestPosition);
                // computing restrictions not possible
              } else {
                if (!queueSpans.get(j).sequenceSpans.optional) {
                  minStartPositionNext = null;
                }
                break;
              }
            }
            // fill queue
            if ((minStartPositionPrevious == null) || subMatchesOptional) {
              fillQueue(item, null, maxEndPositionPrevious, minStartPositionNext);
            } else {
              fillQueue(item, minStartPositionPrevious, maxEndPositionPrevious,
                  minStartPositionNext);
            }
            // try to adjust minimum ignoreItem
            if (!adjustedMinimumIgnoreItem && !item.sequenceSpans.optional
                && item.filledPosition) {
              if (minOptionalStartPosition != null) {
                ignoreItem.removeBefore(docId,
                    Math.min(minOptionalStartPosition, item.lowestPosition));
              } else {
                ignoreItem.removeBefore(docId, item.lowestPosition);
              }
              adjustedMinimumIgnoreItem = true;
            }
            // check for available positions
            if (!item.sequenceSpans.optional && item.noMorePositions
                && !item.filledPosition) {
              currentPosition = NO_MORE_POSITIONS;
              return false;
            }
            // build matches
            subMatchesQueue = _glue(subMatchesQueue, subMatchesOptional, item);
            // update subMatchesOptional
            if (!item.sequenceSpans.optional) {
              subMatchesOptional = false;
            }
            // check if matches are still achievable
            if (!subMatchesOptional && subMatchesQueue.isEmpty()) {
              // clean up previous queues
              if (subMatchesStartPosition != null) {
                int cleanStartPosition = subMatchesStartPosition;
                for (int j = 0; j <= i; j++) {
                  queueSpans.get(j).del(cleanStartPosition);
                  if (!queueSpans.get(j).sequenceSpans.optional) {
                    cleanStartPosition++;
                  }
                }
              }
              return false;
            }
            // update subMatchesStartPosition
            if (subMatchesQueue.isEmpty()) {
              subMatchesStartPosition = null;
            } else {
              subMatchesStartPosition = subMatchesQueue.get(0).startPosition;
            }
            // compute minimum startPosition for next span
            if (item.lowestPosition != null) {
              minStartPositionPrevious = (minStartPositionPrevious == null)
                  ? item.lowestPosition
                  : Math.min(minStartPositionPrevious, item.lowestPosition);
            }
            // for optional spans
            if (item.sequenceSpans.optional) {
              // update stats
              if (item.lowestPosition != null) {
                minOptionalStartPosition = (minOptionalStartPosition == null)
                    ? item.lowestPosition
                    : Math.min(minOptionalStartPosition, item.lowestPosition);
              }
              // for not optional spans
            } else {
              // update stats, item.lowestPosition should be set
              minStartPosition = (minStartPosition == null) ? item.lowestPosition
                  : Math.min(minStartPosition, item.lowestPosition);
              // reset maximum endPosition for next span
              maxEndPositionPrevious = null;
            }
            // compute maximum endPosition for next span
            if (item.lowestPosition != null) {
              for (Integer endPosition : item.queue.get(item.lowestPosition)) {
                maxEndPositionPrevious = (maxEndPositionPrevious == null)
                    ? endPosition : Math.max(maxEndPositionPrevious, endPosition);
              }
            }
          }
        }
        if (subMatchesQueue.isEmpty()) {
          // condition has only optional parts
          if (subMatchesOptional) {
            // check for
            boolean allFinished = true;
            for (int i = 0; i < queueSpans.size(); i++) {
              if (!queueSpans.get(i).noMorePositions) {
                allFinished = false;
                break;
              }
            }
            if (allFinished) {
              currentPosition = NO_MORE_POSITIONS;
            }
          }
          return false;
        } else if ((minOptionalStartPosition != null)
            && (minOptionalStartPosition < subMatchesStartPosition)) {
          for (int i = 0; i < queueSpans.size(); i++) {
            if (!queueSpans.get(i).sequenceSpans.optional) {
              break;
            } else {
              queueSpans.get(i).del(minOptionalStartPosition);
            }
          }
          return false;
        } else {
          for (int i = 0; i < queueSpans.size(); i++) {
            queueSpans.get(i).del(subMatchesStartPosition);
          }
          for (Match m : subMatchesQueue) {
            if (!queueMatches.contains(m)) {
              queueMatches.add(m);
            }
          }
          ignoreItem.removeBefore(docId, queueMatches.get(0).startPosition);
          return true;
        }
      }
    }