/**
   * Loads the plugins contained within the specified directory
   *
   * @param directory Directory to check for plugins
   * @return A list of all plugins loaded
   */
  public Plugin[] loadPlugins(File directory) {
    Validate.notNull(directory, "Directory cannot be null");
    Validate.isTrue(directory.isDirectory(), "Directory must be a directory");

    List<Plugin> result = new ArrayList<Plugin>();
    Set<Pattern> filters = fileAssociations.keySet();

    if (!(server.getUpdateFolder().equals(""))) {
      updateDirectory = new File(directory, server.getUpdateFolder());
    }

    Map<String, File> plugins = new HashMap<String, File>();
    Set<String> loadedPlugins = new HashSet<String>();
    Map<String, Collection<String>> dependencies = new HashMap<String, Collection<String>>();
    Map<String, Collection<String>> softDependencies = new HashMap<String, Collection<String>>();

    // This is where it figures out all possible plugins
    for (File file : directory.listFiles()) {
      PluginLoader loader = null;
      for (Pattern filter : filters) {
        Matcher match = filter.matcher(file.getName());
        if (match.find()) {
          loader = fileAssociations.get(filter);
        }
      }

      if (loader == null) continue;

      PluginDescriptionFile description = null;
      try {
        description = loader.getPluginDescription(file);
      } catch (InvalidDescriptionException ex) {
        server
            .getLogger()
            .log(
                Level.SEVERE,
                "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "'",
                ex);
        continue;
      }

      plugins.put(description.getName(), file);

      Collection<String> softDependencySet = description.getSoftDepend();
      if (softDependencySet != null) {
        if (softDependencies.containsKey(description.getName())) {
          // Duplicates do not matter, they will be removed together if applicable
          softDependencies.get(description.getName()).addAll(softDependencySet);
        } else {
          softDependencies.put(description.getName(), new LinkedList<String>(softDependencySet));
        }
      }

      Collection<String> dependencySet = description.getDepend();
      if (dependencySet != null) {
        dependencies.put(description.getName(), new LinkedList<String>(dependencySet));
      }

      Collection<String> loadBeforeSet = description.getLoadBefore();
      if (loadBeforeSet != null) {
        for (String loadBeforeTarget : loadBeforeSet) {
          if (softDependencies.containsKey(loadBeforeTarget)) {
            softDependencies.get(loadBeforeTarget).add(description.getName());
          } else {
            // softDependencies is never iterated, so 'ghost' plugins aren't an issue
            Collection<String> shortSoftDependency = new LinkedList<String>();
            shortSoftDependency.add(description.getName());
            softDependencies.put(loadBeforeTarget, shortSoftDependency);
          }
        }
      }
    }

    while (!plugins.isEmpty()) {
      boolean missingDependency = true;
      Iterator<String> pluginIterator = plugins.keySet().iterator();

      while (pluginIterator.hasNext()) {
        String plugin = pluginIterator.next();

        if (dependencies.containsKey(plugin)) {
          Iterator<String> dependencyIterator = dependencies.get(plugin).iterator();

          while (dependencyIterator.hasNext()) {
            String dependency = dependencyIterator.next();

            // Dependency loaded
            if (loadedPlugins.contains(dependency)) {
              dependencyIterator.remove();

              // We have a dependency not found
            } else if (!plugins.containsKey(dependency)) {
              missingDependency = false;
              File file = plugins.get(plugin);
              pluginIterator.remove();
              softDependencies.remove(plugin);
              dependencies.remove(plugin);

              server
                  .getLogger()
                  .log(
                      Level.SEVERE,
                      "Could not load '"
                          + file.getPath()
                          + "' in folder '"
                          + directory.getPath()
                          + "'",
                      new UnknownDependencyException(dependency));
              break;
            }
          }

          if (dependencies.containsKey(plugin) && dependencies.get(plugin).isEmpty()) {
            dependencies.remove(plugin);
          }
        }
        if (softDependencies.containsKey(plugin)) {
          Iterator<String> softDependencyIterator = softDependencies.get(plugin).iterator();

          while (softDependencyIterator.hasNext()) {
            String softDependency = softDependencyIterator.next();

            // Soft depend is no longer around
            if (!plugins.containsKey(softDependency)) {
              softDependencyIterator.remove();
            }
          }

          if (softDependencies.get(plugin).isEmpty()) {
            softDependencies.remove(plugin);
          }
        }
        if (!(dependencies.containsKey(plugin) || softDependencies.containsKey(plugin))
            && plugins.containsKey(plugin)) {
          // We're clear to load, no more soft or hard dependencies left
          File file = plugins.get(plugin);
          pluginIterator.remove();
          missingDependency = false;

          try {
            result.add(loadPlugin(file));
            loadedPlugins.add(plugin);
            continue;
          } catch (InvalidPluginException ex) {
            server
                .getLogger()
                .log(
                    Level.SEVERE,
                    "Could not load '"
                        + file.getPath()
                        + "' in folder '"
                        + directory.getPath()
                        + "'",
                    ex);
          }
        }
      }

      if (missingDependency) {
        // We now iterate over plugins until something loads
        // This loop will ignore soft dependencies
        pluginIterator = plugins.keySet().iterator();

        while (pluginIterator.hasNext()) {
          String plugin = pluginIterator.next();

          if (!dependencies.containsKey(plugin)) {
            softDependencies.remove(plugin);
            missingDependency = false;
            File file = plugins.get(plugin);
            pluginIterator.remove();

            try {
              result.add(loadPlugin(file));
              loadedPlugins.add(plugin);
              break;
            } catch (InvalidPluginException ex) {
              server
                  .getLogger()
                  .log(
                      Level.SEVERE,
                      "Could not load '"
                          + file.getPath()
                          + "' in folder '"
                          + directory.getPath()
                          + "'",
                      ex);
            }
          }
        }
        // We have no plugins left without a depend
        if (missingDependency) {
          softDependencies.clear();
          dependencies.clear();
          Iterator<File> failedPluginIterator = plugins.values().iterator();

          while (failedPluginIterator.hasNext()) {
            File file = failedPluginIterator.next();
            failedPluginIterator.remove();
            server
                .getLogger()
                .log(
                    Level.SEVERE,
                    "Could not load '"
                        + file.getPath()
                        + "' in folder '"
                        + directory.getPath()
                        + "': circular dependency detected");
          }
        }
      }
    }

    return result.toArray(new Plugin[result.size()]);
  }
 @Override
 public String getUpdateFolder() {
   return server.getUpdateFolder();
 }