/**
   * Returns <code>true</code> if this task is blocked by its dependencies; <code>false</code>
   * otherwise.
   *
   * <p>A task is blocked by dependencies if a task with an ID matching one or more of the
   * dependencies is running or in the queue before this one.
   *
   * <p><strong>ATTENTION: Make sure this is only called from inside a synchronized block!</strong>
   *
   * @return
   */
  private boolean isBlockedByDependencies() {
    for (ProgressThread pg : currentThreads) {
      if (dependencies.contains(pg.getID())) {
        return true;
      }
    }
    // now check tasks in queue as there might be a dependency waiting for one himself
    for (ProgressThread pg : queuedThreads) {
      // loop over queued tasks until we reach ourself, if no dependencies have been found
      // by then, we can start!
      if (pg.equals(this)) {
        break;
      }
      if (dependencies.contains(pg.getID())) {
        return true;
      }
    }

    return false;
  }
  /**
   * Removes all queued threads that depend on the progress threads with the provided IDs. Also all
   * thread that depend on the threads that have been removed are removed recursively.
   *
   * <p><strong>ATTENTION: Make sure this is only called from inside a synchronized block!</strong>
   *
   * @param ids the progress thread IDs the queued progress threads should be checked for
   */
  private static final void removeQueuedThreadsWithDependency(String... ids) {
    Iterator<ProgressThread> iterator = queuedThreads.iterator();

    // iterator over queued threads and remove the remove the ones that depend on one of the
    // provided IDs
    Set<String> cancelledThreads = new HashSet<>();
    while (iterator.hasNext()) {
      ProgressThread pg = iterator.next();
      if (!Collections.disjoint(Arrays.asList(ids), pg.getDependencies())) {
        iterator.remove();
        cancelledThreads.add(pg.getID());
      }
    }

    // also remove all the ones depending on the ones that have been cancelled.
    if (!cancelledThreads.isEmpty()) {
      removeQueuedThreadsWithDependency(
          cancelledThreads.toArray(new String[cancelledThreads.size()]));
    }
  }