/* 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/gstindex.h>
#include <gstreamermm/object.h>
#include <gstreamermm/format.h>

_DEFS(gstreamermm,gst)

namespace Gst
{

_WRAP_ENUM(IndexCertainty, GstIndexCertainty)
_WRAP_ENUM(IndexEntryType, GstIndexEntryType)
_WRAP_ENUM(IndexLookupMethod, GstIndexLookupMethod)
_WRAP_ENUM(AssocFlags, GstAssocFlags)
_WRAP_ENUM(IndexResolverMethod, GstIndexResolverMethod)
_WRAP_ENUM(IndexFlags, GstIndexFlags)

/** The basic element of an index.
 */
class IndexEntry
{
  _CLASS_OPAQUE_COPYABLE(IndexEntry, GstIndexEntry, NONE, gst_index_entry_copy, gst_index_entry_free)
public:
  _WRAP_METHOD(bool assoc_map(Format format, gint64& value) const, gst_index_entry_assoc_map)
};

/** An association in an entry.
 */
class IndexAssociation
{
  _CLASS_GENERIC(IndexAssociation, GstIndexAssociation)

public:
  /// Default constructor
  IndexAssociation();

  /** Constructs a Gst::IndexAssociation from a C GstIndexAssociation type.
   * The @a castitem is left unaffected; its contents are simply copied.
   * @param castitem The GstIndexAssociation to copy contents from.
   */
   explicit IndexAssociation(const GstIndexAssociation* castitem);

  /// The format of the association.
  Gst::Format format;

  /// The value of the association
  gint64 value;
};


/** A class that generates a stream index of one or more elements in a
 * pipeline.
 */
class Index : public Object 
{
  _CLASS_GOBJECT(Index, GstIndex, GST_INDEX, Object, GstObject)

protected:
  _CTOR_DEFAULT

public:
  /** For example,
   * bool on_filter(const Glib::RefPtr<Gst::Index>& index, Gst::IndexEntry
   * entry);.
   * The filter function should return true if the entry is to be added to the
   * index, false otherwise.
   */ 
  typedef sigc::slot<bool, const Glib::RefPtr<Gst::Index>&, Gst::IndexEntry> SlotFilter;

  /** For example,
   * bool on_resolve(const Glib::RefPtr<Gst::Object>& writer, Glib::ustring&
   * writer_string);.
   * The resolve function should return true if an id could be assigned to
   * writer.
   */ 
  typedef sigc::slot<bool, const Glib::RefPtr<Gst::Index>&, const Glib::RefPtr<Gst::Object>&, Glib::ustring&> SlotResolver;

  /** Check if the index can be read from.
   * @return true if index is readable, false otherwise.
   */
  bool is_readable() const;

  /** Check if the index can be written to.
   * @return true if index is writable, false otherwise.
   */
  bool is_writable() const;

  _WRAP_METHOD(void commit(int id), gst_index_commit)
  _WRAP_METHOD(int get_group() const, gst_index_get_group)
  _WRAP_METHOD(int new_group(), gst_index_new_group)
  _WRAP_METHOD(bool set_group(int group_number), gst_index_set_group)
  _WRAP_METHOD(void set_certainty(IndexCertainty certainty), gst_index_set_certainty)
  _WRAP_METHOD(IndexCertainty get_certainty() const, gst_index_get_certainty)
  _WRAP_METHOD(bool get_writer_id(const Glib::RefPtr<Gst::Object>& writer, int& id) const, gst_index_get_writer_id)

// This conversion is used for next few add* methods (add_format,
// add_association, etc.).  A copy is taken so the original is not freed by the
// wrapper.
#m4 _CONVERSION(`GstIndexEntry*',`Gst::IndexEntry',`Glib::wrap($3, true)')

  _WRAP_METHOD(Gst::IndexEntry add_format(int id, Format format), gst_index_add_format)

#m4 _CONVERSION(`const Glib::ArrayHandle<const Gst::IndexAssociation>&', `const GstIndexAssociation*', `(const GstIndexAssociation*)(($3).data())')
  _WRAP_METHOD(Gst::IndexEntry add_association(int id, AssocFlags flags, int n, const Glib::ArrayHandle<const Gst::IndexAssociation>& list), gst_index_add_associationv)

  _WRAP_METHOD(Gst::IndexEntry add_id(int id, const Glib::ustring& description), gst_index_add_id)

  /** Finds the given format/value in the index.
   *
   * @param id The id of the index writer.
   * @param value The value to find.
   * @param method The lookup method to use.
   * @param flags Flags for the entry.
   * @param format The format of the value.
   * @return The entry associated with the value or 0 if the value was not
   * found. 
   */
  Gst::IndexEntry get_assoc_entry(int id, gint64 value,
    IndexLookupMethod method = Gst::INDEX_LOOKUP_EXACT,
    AssocFlags flags = Gst::ASSOCIATION_FLAG_NONE,
    Format format = Gst::FORMAT_DEFAULT) const;

  /** Lets the app register a custom filter slot so that it can select what
   * entries should be stored in the index.
   *
   * @param slot The filter slot to register.
   */
  void set_filter(const SlotFilter& slot);

  /** Lets the app register a custom slot to map index ids to writer
   * descriptions.
   * @param slot The resolver slot to register.
   */
  void set_resolver(const SlotResolver& slot);

  _WRAP_PROPERTY("resolver", Gst::Index::SlotResolver)

#m4 _CONVERSION(`GstIndexEntry*',`const Gst::IndexEntry&',`Glib::wrap($3, true)')
#m4 _CONVERSION(`const Gst::IndexEntry&',`GstIndexEntry*',`const_cast<GstIndexEntry*>(($3).gobj())')
  /** Emitted when a new entry is added to the index.
   */
  _WRAP_SIGNAL(void entry_added(const Gst::IndexEntry& entry), "entry-added")

  _WRAP_VFUNC(bool get_writer_id(int& writer_id, const Glib::ustring& writer_string) const, "get_writer_id")

  _WRAP_VFUNC(void commit(gint id), "commit")

  virtual void add_entry_vfunc(Gst::IndexEntry& entry);

  //TODO: Leave this vfunc for later because it is not absolutely necessary
  //right now.
  //_WRAP_VFUNC(void get_assoc_entry(Gst::LookupMethod method, Gst::AssocFlags flags, Gst::Format format, gint64 value, const SlotCompareData& compare_slot), "get_assoc_entry")

protected:
#m4begin
  _PUSH(SECTION_PCC_CLASS_INIT_VFUNCS)
  klass->add_entry = &add_entry_vfunc_callback;
  _SECTION(SECTION_PH_VFUNCS)
  static void add_entry_vfunc_callback(GstIndex* self, GstIndexEntry* entry);
  _POP()
#m4end
};

} //namespace Gst
