/* 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/gstregistry.h>
#include <gstreamermm/object.h>
#include <gstreamermm/plugin.h>
#include <gstreamermm/pluginfeature.h>

_DEFS(gstreamermm,gst)

namespace Gst
{

class Plugin;
class PluginFeature;

/** Gst::Registry - Abstract base class for management of Gst::Plugin objects.
  * One registry holds the metadata of a set of plugins. All registries build
  * the GstRegistryPool.
  *
  * Design:
  *
  * The Gst::Registry object is a list of plugins and some functions for
  * dealing with them. Gst::Plugins are matched 1-1 with a file on disk, and
  * may or may not be loaded at a given time. There may be multiple
  * Gst::Registry objects, but the "default registry" is the only object that
  * has any meaning to the core.
  *
  * The registry.xml file is actually a cache of plugin information. This is
  * unlike versions prior to 0.10, where the registry file was the primary
  * source of plugin information, and was created by the gst-register command.
  *
  * 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.xml file.
  *
  * On startup, plugins are searched for in the plugin search path. This path
  * can be set directly using the GST_PLUGIN_PATH environment variable. The
  * registry file is loaded from
  * ~/.gstreamer-$GST_MAJORMINOR/registry-$ARCH.xml or the file listed in the
  * GST_REGISTRY env var. The only 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 "default 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 intitialization.
 */
class Registry : public Object
{
  _CLASS_GOBJECT(Registry, GstRegistry, GST_REGISTRY, Gst::Object, GstObject)

public:
  _WRAP_METHOD(static Glib::RefPtr<Gst::Registry> get_default(), gst_registry_get_default)

#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(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::ustring >',`$2($3, Glib::OWNERSHIP_DEEP)')
  _WRAP_METHOD(Glib::ListHandle< Glib::ustring > get_path_list() const, gst_registry_get_path_list)

#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(bool add_plugin(const Glib::RefPtr<Gst::Plugin>& plugin), gst_registry_add_plugin)
  _WRAP_METHOD(void remove_plugin(const Glib::RefPtr<Gst::Plugin>& plugin), gst_registry_remove_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 registry Registry to query.
   * @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 registry Registry to query.
   * @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(void add_path(const Glib::ustring& path), gst_registry_add_path)
  _WRAP_METHOD(void scan_path(const Glib::ustring& path), gst_registry_scan_path)
  // binary or xml registry cache depends on USE_BINARY_REGISTRY def in
  // gstregistry.h

#ifdef USE_BINARY_REGISTRY
  /** Read the contents of the binary cache file at location into registry.
   *
   * @param location A filename.
   * @return true on success.
   */
  bool binary_read_cache(const Glib::ustring& location);
  _IGNORE(gst_registry_xml_read_cache)

  /** Write the registry to a cache to file at given location.
   *
   * @param location A filename.
   * @return true on success.
   */
  void binary_write_cache(const Glib::ustring& location) const;
#else
  /** Read the contents of the XML cache file at location into registry.
   *
   * @param location A filename.
   * @return true on success. 
   */
  bool xml_read_cache(const Glib::ustring& location);
  _IGNORE(gst_registry_xml_read_cache)

  /** Write registry in an XML format at the location given by location.
   * Directories are automatically created.
   *
   * @param location A filename.
   * @return true on success.
   */
  bool xml_write_cache(const Glib::ustring& location) const;
  _IGNORE(gst_registry_xml_write_cache)
#endif

  _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(const Glib::RefPtr<Gst::PluginFeature>& feature), gst_registry_add_feature)
  _WRAP_METHOD(static bool check_feature_version(const Glib::ustring& feature_name, guint min_major, guint min_minor, guint min_micro), gst_default_registry_check_feature_version)

#m4 _CONVERSION(`GstPluginFeature*',`const Glib::RefPtr<Gst::PluginFeature>&',`Glib::wrap($3, true)')

  /** Signals that a feature has been added to the registry (possibly replacing
   * a previously-added one by the same name)
   */
  _WRAP_SIGNAL(void feature_added(const Glib::RefPtr<Gst::PluginFeature>& feature), "feature-added")

#m4 _CONVERSION(`GstPlugin*',`const Glib::RefPtr<Gst::Plugin>&',`Glib::wrap($3, true)')

  /** Signals that a plugin has been added to the registry (possibly replacing
   * a previously-added one by the same name)
   */
  _WRAP_SIGNAL(void plugin_added(const Glib::RefPtr<Gst::Plugin>& plugin), "plugin-added")
};

} // namespace Gst
