/**
 * infinoted_plugin_manager_load:
 * @manager: A #InfinotedPluginManager.
 * @plugin_path: The path from which to load plugins.
 * @plugins: A list of plugins to load, or %NULL.
 * @options: A #GKeyFile with configuration options for the plugins.
 * @error: Location to store error information, if any, or %NULL.
 *
 * Loads all plugins specified in @plugins from the location at @plugin_path.
 * If loading one of the module fails the function sets @error and returns
 * %FALSE, and the object ends up with no plugins loaded. If @plugins is
 * %NULL, no plugins are loaded.
 * 
 * If this function is called while there are already plugins loaded, all
 * existing plugins are unloaded first.
 *
 * Returns: %TRUE on success or %FALSE on error.
 */
gboolean
infinoted_plugin_manager_load(InfinotedPluginManager* manager,
                              const gchar* plugin_path,
                              const gchar* const* plugins,
                              GKeyFile* options,
                              GError** error)
{
  InfinotedPluginManagerPrivate* priv;
  const gchar* const* plugin;
  gboolean result;

  g_return_val_if_fail(INFINOTED_IS_PLUGIN_MANAGER(manager), FALSE);
  g_return_val_if_fail(plugin_path != NULL, FALSE);
  g_return_val_if_fail(options != NULL, FALSE);
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);

  priv = INFINOTED_PLUGIN_MANAGER_PRIVATE(manager);

  /* Unload existing plugins */
  g_free(priv->path);
  while(priv->plugins != NULL)
  {
    infinoted_plugin_manager_unload_plugin(
      manager,
      (InfinotedPluginInstance*)priv->plugins->data
    );
  }

  /* Load new plugins */
  priv->path = g_strdup(plugin_path);

  if(plugins != NULL)
  {
    for(plugin = plugins; *plugin != NULL; ++plugin)
    {
      result = infinoted_plugin_manager_load_plugin(
        manager,
        plugin_path,
        *plugin,
        options,
        error
      );

      if(result == FALSE)
      {
        while(priv->plugins != NULL)
        {
          infinoted_plugin_manager_unload_plugin(
            manager,
            (InfinotedPluginInstance*)priv->plugins->data
          );
        }

        return FALSE;
      }
    }
  }

  return TRUE;
}
/**
 * infinoted_plugin_manager_new:
 * @directory: The #InfdDirectory on which plugins should operate.
 * @log: The #InfinotedLog to write log messages to.
 * @creds: The #InfCertificateCredentials used to secure data transfer with
 * the clients, or %NULL.
 * @plugin_path: A path to the plugin modules.
 * @plugins: A list of plugins to load, or %NULL.
 * @options: A #GKeyFile with configuration options for the plugins.
 * @error: Location to store error information, if any, or %NULL.
 *
 * Creates a new #InfinotedPluginManager and loads all plugins specified
 * in @plugins from the location at @plugin_path. If loading one of the
 * module fails the function sets @error and returns %NULL. If @plugins is
 * %NULL, no plugins are initially loaded.
 *
 * Returns: A new #InfinotedPluginManager, or %NULL on error. Free with
 * infinoted_plugin_manager_free() when no longer needed.
 */
InfinotedPluginManager*
infinoted_plugin_manager_new(InfdDirectory* directory,
                             InfinotedLog* log,
                             InfCertificateCredentials* creds,
                             const gchar* plugin_path,
                             const gchar* const* plugins,
                             GKeyFile* options,
                             GError** error)
{
  InfinotedPluginManager* plugin_manager;
  const gchar* const* plugin;
  gboolean result;

  plugin_manager = g_slice_new(InfinotedPluginManager);

  plugin_manager->directory = directory;
  plugin_manager->log = log;
  plugin_manager->credentials = creds;
  plugin_manager->path = g_strdup(plugin_path);
  plugin_manager->plugins = NULL;
  plugin_manager->connections = g_hash_table_new(NULL, NULL);
  plugin_manager->sessions = g_hash_table_new(NULL, NULL);

  if(creds != NULL)
    inf_certificate_credentials_ref(creds);

  g_object_ref(directory);
  g_object_ref(log);

  g_signal_connect_after(
    G_OBJECT(directory),
    "connection-added",
    G_CALLBACK(infinoted_plugin_manager_connection_added_cb),
    plugin_manager
  );

  g_signal_connect_after(
    G_OBJECT(directory),
    "connection-removed",
    G_CALLBACK(infinoted_plugin_manager_connection_removed_cb),
    plugin_manager
  );

  g_signal_connect_after(
    G_OBJECT(directory),
    "subscribe-session",
    G_CALLBACK(infinoted_plugin_manager_subscribe_session_cb),
    plugin_manager
  );

  g_signal_connect_after(
    G_OBJECT(directory),
    "unsubscribe-session",
    G_CALLBACK(infinoted_plugin_manager_unsubscribe_session_cb),
    plugin_manager
  );

  if(plugins != NULL)
  {
    for(plugin = plugins; *plugin != NULL; ++plugin)
    {
      result = infinoted_plugin_manager_load_plugin(
        plugin_manager,
        plugin_path,
        *plugin,
        options,
        error
      );

      if(result == FALSE)
      {
        infinoted_plugin_manager_free(plugin_manager);
        return NULL;
      }
    }
  }

  return plugin_manager;
}