/**
   * This method attempts to find a matching dependency quickly, by bypassing full resolution of the
   * classpath path group for a plugin. It assumes the following: 1. The dependendency is directly
   * defined by the plugin artifact (this should always be true when a plugin implements an abstract
   * method of another) 2. The plugin artifact defines no overrides that effect the dependency (this
   * should be true as the plugin should just define the version it wants directly). If the
   * performance of resolvePathGroup is improved this method could be replaced by the version below.
   */
  private RepoArtifactId fastFindMatchingDependency(Target target, RepoArtifactId id) {
    // Find the matching id that belongs to the classpath
    PathGroup pathGroup = target.getPathGroup("classpath");
    RepoArtifactId match = null;
    String matchingPath = null;
    for (Iterator i = target.getPlugin().getArtifact().getDependencies().iterator();
        i.hasNext(); ) {
      RepoDependency dependency = (RepoDependency) i.next();
      if (dependency.getId().matches(id)) {
        for (Iterator j = dependency.getPathSpecs().iterator(); j.hasNext(); ) {
          RepoPathSpec pathSpec = (RepoPathSpec) j.next();
          if (pathGroup.getPaths().contains("plugin." + pathSpec.getTo())) {
            match = dependency.getId();
            matchingPath = pathSpec.getTo();
            break;
          }
        }
      }
    }

    Assert.isTrue(
        match != null,
        target.getPlugin().getArtifact().getId().toShortString()
            + " does not declare a dependency that matches "
            + id);

    // Apply any project overrides
    for (Iterator i = overrides.iterator(); i.hasNext(); ) {
      ws.quokka.core.model.Override override = (ws.quokka.core.model.Override) i.next();
      if (override.getWithVersion() != null && override.matches(match)) {
        Set paths = override.matchingPluginPaths(target.getPlugin().getArtifact().getId());
        if (paths.contains(matchingPath) || ((paths.size() == 1) && paths.contains("*"))) {
          log.verbose("Overriding " + match.toShortString() + " to " + override.getWithVersion());
          if (log.isDebugEnabled()) {
            log.debug(
                "Applied "
                    + override
                    + (override.getLocator() == null ? "" : " from " + override.getLocator()));
          }
          return new RepoArtifactId(
              id.getGroup(), id.getName(), id.getType(), override.getWithVersion());
        }
      }
    }

    return match;

    // Slow code
    //        List artifacts = resolvePathGroup(target, "classpath");
    //        for (Iterator i = artifacts.iterator(); i.hasNext();) {
    //            RepoArtifact artifact = (RepoArtifact) i.next();
    //            if (artifact.getId().matches(id)) {
    //                return artifact.getId();
    //            }
    //        }
  }
  public List _resolvePathGroup(Target target, String pathGroupId) {
    Plugin plugin = target.getPlugin();
    PathGroup pathGroup = target.getPathGroup(pathGroupId);

    if (pathGroup == null) {
      if (plugin.getDeclaringPlugin() != null) {
        String declaringTargetName =
            plugin.getDeclaringPlugin().getNameSpace() + ":" + parseImplements(target)[2];
        pathGroup =
            plugin.getDeclaringPlugin().getTarget(declaringTargetName).getPathGroup(pathGroupId);

        // TODO: Check the path group only refers to project paths?
      }

      Assert.isTrue(
          pathGroup != null,
          "Target '"
              + target.getName()
              + "' has requested path group '"
              + pathGroupId
              + "' that does not exist");
    }

    if (log.isDebugEnabled()) {
      log.debug(
          "Resolving path: target="
              + target.getName()
              + ", pathGroup="
              + pathGroupId
              + ", pathGroupElements="
              + pathGroup.getPaths());
    }

    List paths = new ArrayList();

    // Note: merging with core is turned off here so that the proper path tree is maintained
    // However, core overrides are still applied by separating that into a different flag
    resolvePath(
        pathGroup.getPaths(),
        paths,
        false,
        pathGroup.getMergeWithCore().booleanValue(),
        target,
        false);

    if (log.isDebugEnabled()) {
      log.debug("Resolved the following paths for path group '" + pathGroup + "'");
      for (Iterator i = paths.iterator(); i.hasNext(); ) {
        ResolvedPath path = (ResolvedPath) i.next();
        log.debug(pathResolver.formatPath(path, false));
      }
    }

    ResolvedPath path = pathResolver.merge(paths);

    if (pathGroup.getMergeWithCore().booleanValue()) {
      path = mergeWithCore(path);
    }

    //        System.out.println(pathResolver.formatPath(path, false));
    StringBuffer sb = new StringBuffer();

    for (Iterator i = path.getArtifacts().iterator(); i.hasNext(); ) {
      RepoArtifact artifact = (RepoArtifact) i.next();
      sb.append(artifact.getId().toShortString()).append(";");
    }

    if (log.isDebugEnabled()) {
      log.debug(
          "Resolved path: target="
              + target.getName()
              + ", pathGroup="
              + pathGroupId
              + ", path="
              + sb.toString());
    }

    return path.getArtifacts();
  }