private void resolveDeleteByDependency() {
    // delete by depend
    boolean hasModifications = true;
    while (hasModifications) {
      log.debug("Check uninstall dependencies");
      hasModifications = false;
      for (Plugin plugin : deletions) {
        if (!additions.contains(plugin)) {
          for (Plugin dep : getDependants(plugin)) {
            if (!deletions.contains(dep) && dep.isInstalled()) {
              log.debug("Add to deletions: " + dep);
              deletions.add(dep);
              hasModifications = true;
            }
            if (additions.contains(dep)) {
              log.debug("Remove from additions: " + dep);
              additions.remove(dep);
              hasModifications = true;
            }
          }
        }

        if (hasModifications) {
          break; // prevent ConcurrentModificationException
        }
      }
    }
  }
  private void resolveDeleteLibs() {
    for (Plugin plugin : deletions) {
      if (additions.contains(plugin)) { // skip upgrades
        continue;
      }

      Map<String, String> libs = plugin.getLibs(plugin.getInstalledVersion());
      for (String lib : libs.keySet()) {
        if (Plugin.getLibInstallPath(lib) != null) {
          libDeletions.add(lib);
        } else {
          log.warn("Did not find library to uninstall it: " + lib);
        }
      }
    }

    for (Plugin plugin : allPlugins.keySet()) {
      if (additions.contains(plugin) || (plugin.isInstalled() && !deletions.contains(plugin))) {
        String ver =
            additions.contains(plugin)
                ? plugin.getCandidateVersion()
                : plugin.getInstalledVersion();
        // log.debug("Affects " + plugin + " v" + ver);
        Map<String, String> libs = plugin.getLibs(ver);
        for (String lib : libs.keySet()) {
          if (libDeletions.contains(lib)) {
            log.debug("Won't delete lib " + lib + " since it is used by " + plugin);
            libDeletions.remove(lib);
          }
        }
      }
    }
  }
  private void resolveInstallByDependency() {
    // resolve dependencies
    boolean hasModifications = true;
    while (hasModifications) {
      log.debug("Check install dependencies: " + additions);
      hasModifications = false;
      for (Plugin plugin : additions) {
        for (String pluginID : plugin.getDepends()) {
          Plugin depend = getPluginByID(pluginID);

          if (!depend.isInstalled() || deletions.contains(depend)) {
            if (!additions.contains(depend)) {
              log.debug("Add to install: " + depend);
              additions.add(depend);
              hasModifications = true;
            }
          }
        }

        if (hasModifications) {
          break; // prevent ConcurrentModificationException
        }
      }
    }
  }
 private void resolveUpgrades() {
   // detect upgrades
   for (Map.Entry<Plugin, Boolean> entry : allPlugins.entrySet()) {
     Plugin plugin = entry.getKey();
     if (entry.getValue()
         && plugin.isInstalled()
         && !plugin.getInstalledVersion().equals(plugin.getCandidateVersion())) {
       log.debug("Upgrade: " + plugin);
       deletions.add(plugin);
       additions.add(plugin);
     }
   }
 }