/**
  * Called when a change is made to a configuration node, such that its dependency graph
  * <em>may</em> now be larger than it previously was, and the node should be visited.
  */
 public void onMoreSelected(ConfigurationNode configuration) {
   // Add to the end of the queue, so that we traverse the graph in breadth-wise order to pick up
   // as many conflicts as
   // possible before attempting to resolve them
   if (queued.add(configuration)) {
     queue.addLast(configuration);
   }
 }
 /**
  * Called when a change is made to a configuration node, such that its dependency graph
  * <em>may</em> now be smaller than it previously was, and the node should be visited.
  */
 public void onFewerSelected(ConfigurationNode configuration) {
   // Add to the front of the queue, to flush out configurations that are no longer required.
   if (queued.add(configuration)) {
     queue.addFirst(configuration);
   }
 }
 public ConfigurationNode peek() {
   return queue.isEmpty() ? null : queue.getFirst();
 }
 public ConfigurationNode pop() {
   ConfigurationNode next = queue.removeFirst();
   queued.remove(next);
   return next;
 }
    private Collection<List<ModuleVersionIdentifier>> calculatePaths(
        BrokenDependency brokenDependency) {
      // Include the shortest path from each version that has a direct dependency on the broken
      // dependency, back to the root

      Map<ModuleVersionResolveState, List<ModuleVersionIdentifier>> shortestPaths =
          new LinkedHashMap<ModuleVersionResolveState, List<ModuleVersionIdentifier>>();
      List<ModuleVersionIdentifier> rootPath = new ArrayList<ModuleVersionIdentifier>();
      rootPath.add(root.moduleRevision.id);
      shortestPaths.put(root.moduleRevision, rootPath);

      Set<ModuleVersionResolveState> directDependees =
          new LinkedHashSet<ModuleVersionResolveState>();
      for (ConfigurationNode node : brokenDependency.requiredBy) {
        directDependees.add(node.moduleRevision);
      }

      Set<ModuleVersionResolveState> seen = new HashSet<ModuleVersionResolveState>();
      LinkedList<ModuleVersionResolveState> queue = new LinkedList<ModuleVersionResolveState>();
      queue.addAll(directDependees);
      while (!queue.isEmpty()) {
        ModuleVersionResolveState version = queue.getFirst();
        if (version == root.moduleRevision) {
          queue.removeFirst();
        } else if (seen.add(version)) {
          for (ConfigurationNode configuration : version.configurations) {
            for (DependencyEdge dependencyEdge : configuration.incomingEdges) {
              queue.add(0, dependencyEdge.from.moduleRevision);
            }
          }
        } else {
          queue.remove();
          List<ModuleVersionIdentifier> shortest = null;
          for (ConfigurationNode configuration : version.configurations) {
            for (DependencyEdge dependencyEdge : configuration.incomingEdges) {
              List<ModuleVersionIdentifier> candidate =
                  shortestPaths.get(dependencyEdge.from.moduleRevision);
              if (candidate == null) {
                continue;
              }
              if (shortest == null) {
                shortest = candidate;
              } else if (shortest.size() > candidate.size()) {
                shortest = candidate;
              }
            }
          }
          if (shortest == null) {
            continue;
          }
          List<ModuleVersionIdentifier> path = new ArrayList<ModuleVersionIdentifier>();
          path.addAll(shortest);
          path.add(version.id);
          shortestPaths.put(version, path);
        }
      }

      List<List<ModuleVersionIdentifier>> paths = new ArrayList<List<ModuleVersionIdentifier>>();
      for (ModuleVersionResolveState version : directDependees) {
        List<ModuleVersionIdentifier> path = shortestPaths.get(version);
        paths.add(path);
      }
      return paths;
    }