/* gstreamermm - a C++ wrapper for gstreamer
 *
 * Copyright 2008 The gstreamermm Development Team
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <gst/gst.h>
#include <gstreamermm/object.h>
#include <gstreamermm/plugin.h>
#include <gstreamermm/pluginfeature.h>

_DEFS(gstreamermm,gst)

namespace Gst
{

class Plugin;
class PluginFeature;

/** An abstract base class for management of Gst::Plugin objects.
 * One registry holds the metadata of a set of plugins.
 *
 * Design:
 *
 * The Gst::Registry object is a list of plugins and some functions for dealing
 * with them. Each Gst::Plugin is matched 1-1 with a file on disk, and may or
 * may not be loaded at a given time.
 *
 * The primary source, at all times, of plugin information is each plugin file
 * itself. Thus, if an application wants information about a particular plugin,
 * or wants to search for a feature that satisfies given criteria, the primary
 * means of doing so is to load every plugin and look at the resulting
 * information that is gathered in the default registry. Clearly, this is a
 * time consuming process, so we cache information in the registry file. The
 * format and location of the cache file is internal to gstreamer.
 *
 * On startup, plugins are searched for in the plugin search path. The
 * following locations are checked in this order:
 *
 *  - location from --gst-plugin-path commandline option.
 *  - the GST_PLUGIN_PATH environment variable.
 *  - the GST_PLUGIN_SYSTEM_PATH environment variable.
 *  - default locations (if GST_PLUGIN_SYSTEM_PATH is not set). Those default
 *    locations are: ~/.gstreamer-$GST_API_VERSION/plugins/ and
 *    $prefix/libs/gstreamer-$GST_API_VERSION/.
 *
 * The registry cache file is loaded from
 * ~/.gstreamer-$GST_API_VERSION/registry-$ARCH.bin or the file listed in the
 * GST_REGISTRY env var. One reason to change the registry location is for
 * testing.
 *
 * For each plugin that is found in the plugin search path, there could be 3
 * possibilities for cached information:
 *
 *  - the cache may not contain information about a given file.
 *  - the cache may have stale information.
 *  - the cache may have current information.
 *
 * In the first two cases, the plugin is loaded and the cache updated. In
 * addition to these cases, the cache may have entries for plugins that are not
 * relevant to the current process. These are marked as not available to the
 * current process. If the cache is updated for whatever reason, it is marked
 * dirty.
 *
 * A dirty cache is written out at the end of initialization. Each entry is
 * checked to make sure the information is minimally valid. If not, the entry
 * is simply dropped.
 *
 * Implementation notes:
 *
 * The "cache" and "registry" are different concepts and can represent
 * different sets of plugins. For various reasons, at init time, the cache is
 * stored in the default registry, and plugins not relevant to the current
 * process are marked with the GST_PLUGIN_FLAG_CACHED bit. These plugins are
 * removed at the end of initialization.
 *
 * Last reviewed on 2012-03-29 (0.11.3)
 */
class Registry : public Object
{
  _CLASS_GOBJECT(Registry, GstRegistry, GST_REGISTRY, Gst::Object, GstObject)

public:
#m4 _CONVERSION(`GList*',`Glib::ListHandle< Glib::RefPtr<Gst::PluginFeature> >',`$2($3, Glib::OWNERSHIP_DEEP)')
  _WRAP_METHOD(Glib::ListHandle< Glib::RefPtr<Gst::PluginFeature> > get_feature_list(GType type), gst_registry_get_feature_list)

#m4 _CONVERSION(`GList*',`Glib::ListHandle< Glib::RefPtr<const Gst::PluginFeature> >',`$2($3, Glib::OWNERSHIP_DEEP)')
  _WRAP_METHOD(Glib::ListHandle< Glib::RefPtr<const Gst::PluginFeature> > get_feature_list(GType type) const, gst_registry_get_feature_list)

  _WRAP_METHOD(guint32 get_feature_list_cookie() const, gst_registry_get_feature_list_cookie)
  _WRAP_METHOD(Glib::ListHandle< Glib::RefPtr<Gst::PluginFeature> > get_feature_list(const Glib::ustring& name), gst_registry_get_feature_list_by_plugin)
  _WRAP_METHOD(Glib::ListHandle< Glib::RefPtr<const Gst::PluginFeature> > get_feature_list(const Glib::ustring& name) const, gst_registry_get_feature_list_by_plugin)

#m4 _CONVERSION(`GList*',`Glib::ListHandle< Glib::RefPtr<Gst::Plugin> >',`$2($3, Glib::OWNERSHIP_DEEP)')
  _WRAP_METHOD(Glib::ListHandle< Glib::RefPtr<Gst::Plugin> > get_plugin_list(), gst_registry_get_plugin_list)

#m4 _CONVERSION(`GList*',`Glib::ListHandle< Glib::RefPtr<const Gst::Plugin> >',`$2($3, Glib::OWNERSHIP_DEEP)')
  _WRAP_METHOD(Glib::ListHandle< Glib::RefPtr<const Gst::Plugin> > get_plugin_list() const, gst_registry_get_plugin_list)

  _WRAP_METHOD(void remove_plugin(const Glib::RefPtr<Gst::Plugin>& plugin), gst_registry_remove_plugin)

  _WRAP_METHOD(bool add_plugin(Glib::RefPtr<Gst::Plugin>&& plugin), gst_registry_add_plugin)

  /// A add_plugin() convenience overload. Allows to re-use @a plugin parameter after function call.
  void add_plugin(const Glib::RefPtr<Gst::Plugin>& plugin);
  /** Runs a filter against all plugins in the registry and returns a List with
   * the results. If the first flag is set, only the first match is returned
   * (as a list with a single object).
   *
   * @param filter The filter to use.
   * @param first Only return first match.
   * @return A list of Gst::Plugin. MT safe.
   *
   */
  Glib::ListHandle< Glib::RefPtr<Gst::Plugin> > get_plugin_list(const Plugin::SlotFilter& filter, bool first);
  _IGNORE(gst_registry_plugin_filter)

  /** Runs a filter against all plugins in the registry and returns a List with
   * the results. If the first flag is set, only the first match is returned
   * (as a list with a single object).
   *
   * @param filter The filter to use.
   * @param first Only return first match.
   * @return A list of Gst::Plugin. MT safe.
   *
   */
  Glib::ListHandle< Glib::RefPtr<const Gst::Plugin> > get_plugin_list(const Plugin::SlotFilter& filter, bool first) const;

  /** Runs a filter against all features of the plugins in the registry and
   * returns a List with the results. If the first flag is set, only the first
   * match is returned (as a list with a single object).
   *
   * @param filter The filter to use.
   * @param first Only return first match.
   * @return A list of Gst::PluginFeature. MT safe.
   */
  Glib::ListHandle< Glib::RefPtr<Gst::PluginFeature> > get_feature_list(const PluginFeature::SlotFilter& filter, bool first);
  _IGNORE(gst_registry_feature_filter)

  /** Runs a filter against all features of the plugins in the registry and
   * returns a List with the results. If the first flag is set, only the first
   * match is returned (as a list with a single object).
   *
   * @param filter The filter to use.
   * @param first Only return first match.
   * @return A list of Gst::PluginFeature. MT safe.
   */
  Glib::ListHandle< Glib::RefPtr<const Gst::PluginFeature> > get_feature_list(const PluginFeature::SlotFilter& filter, bool first) const;

  _WRAP_METHOD(Glib::RefPtr<Gst::Plugin> find_plugin(const Glib::ustring& name), gst_registry_find_plugin)
  _WRAP_METHOD(Glib::RefPtr<const Gst::Plugin> find_plugin(const Glib::ustring& name) const, gst_registry_find_plugin, constversion)
  _WRAP_METHOD(Glib::RefPtr<Gst::PluginFeature> find_feature(const Glib::ustring& name, GType type), gst_registry_find_feature)
  _WRAP_METHOD(Glib::RefPtr<const Gst::PluginFeature> find_feature(const Glib::ustring& name, GType type) const, gst_registry_find_feature, constversion)
  _WRAP_METHOD(Glib::RefPtr<Gst::PluginFeature> lookup_feature(const Glib::ustring& name), gst_registry_lookup_feature)
  _WRAP_METHOD(Glib::RefPtr<const Gst::PluginFeature> lookup_feature(const Glib::ustring& name) const, gst_registry_lookup_feature, constversion)
  _WRAP_METHOD(bool scan_path(const Glib::ustring& path), gst_registry_scan_path)

  _WRAP_METHOD(Glib::RefPtr<Gst::Plugin> lookup(const Glib::ustring& filename), gst_registry_lookup)
  _WRAP_METHOD(Glib::RefPtr<const Gst::Plugin> lookup(const Glib::ustring& filename) const, gst_registry_lookup, constversion)
  _WRAP_METHOD(void remove_feature(const Glib::RefPtr<Gst::PluginFeature>& feature), gst_registry_remove_feature)
  _WRAP_METHOD(void add_feature(Glib::RefPtr<Gst::PluginFeature>&& feature), gst_registry_add_feature)
  _WRAP_METHOD(bool check_feature_version(const Glib::ustring& feature_name, guint min_major, guint min_minor, guint min_micro), gst_registry_check_feature_version)

  /// This methods appear in .defs file, because they are removed from API using #if 0 directive.
  /// h2def.py script can't detect that case, so methods have to be ignored manually.
  _IGNORE(gst_registry_add_path, gst_registry_get_path_list)

  /// A add_feature() convenience overload. Allows to re-use @a feature parameter after function call.
  void add_feature(const Glib::RefPtr<Gst::PluginFeature>& feature);

  static Glib::RefPtr<Gst::Registry> get();
};

} // namespace Gst
