/* 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/gstcaps.h>
#include <gstreamermm/structure.h>
#include <libxml++/nodes/node.h>

_DEFS(gstreamermm,gst)

namespace Gst
{

_WRAP_ENUM(CapsIntersectMode, GstCapsIntersectMode, NO_GTYPE)

struct Structure;

/** A class that describes sets of media formats.
 * Caps (capabilities) are lightweight objects describing media formats. They
 * are composed of an array of Gst::Structure.
 *
 * Caps are exposed on Gst::PadTemplate to describe all possible types a given
 * pad can handle. They are also stored in the Gst::Registry along with a
 * description of the Gst::Element.
 *
 * Caps are exposed on the element pads using the Gst::Pad::get_caps() method.
 * This method describes the possible types that the pad can handle or produce
 * at runtime.
 *
 * Caps are also attached to buffers to describe to content of the data
 * pointed to by the buffer with Gst::Buffer::set_caps(). Gst::Caps attached
 * to a Gst::Buffer allow for format negotiation upstream and downstream.
 *
 * A Gst::Caps can be constructed with the following code fragment:
 *
 * @code
 * Glib::RefPtr<Gst::Caps> caps = Gst::Caps::create_simple("video/x-raw-yuv");
 * caps->set_simple("format", Gst::Fourcc('I', '4', '2', '0'));
 * caps->set_simple("framerate", Gst::Fraction(25, 1));
 * caps->set_simple("pixel-aspect-ratio", Gst::Fraction(1, 1));
 * caps->set_simple("width", 320);
 * caps->set_simple("height", 240);
 * @endcode
 */
class Caps 
{
  _CLASS_OPAQUE_REFCOUNTED(Caps, GstCaps, gst_caps_new_empty, gst_caps_ref, gst_caps_unref)
  _IGNORE(gst_caps_ref, gst_caps_unref)

public:
#ifndef DOXYGEN_SHOULD_SKIP_THIS
  static GType get_type() G_GNUC_CONST;
#endif

public:
  /** Creates a new Gst::Caps that indicates that it is compatible with any
   * media format.
   *
   * @return The new Gst::Caps.
   */
  static Glib::RefPtr<Gst::Caps> create_any();

  /** Creates a new Gst::Caps that contains one Gst::Structure.
   *
   * @param media_type The media type of the structure.
   * @return The new Gst::Caps.
   */
  static Glib::RefPtr<Gst::Caps> create_simple(const Glib::ustring& media_type);

  /** Creates a new Gst::Caps and adds the given Gst::Structure.
   * Use append_structure() to add additional structures.
   *
   * @param first_struct The first structure to add.
   * @return Returns the new Gst::Caps.
   */
  static Glib::RefPtr<Gst::Caps> create(const Structure& first_struct);

  _WRAP_METHOD(static Glib::RefPtr<Gst::Caps> create_from_string(const Glib::ustring& string), gst_caps_from_string)

  _WRAP_METHOD(Glib::RefPtr<Gst::Caps> copy() const, gst_caps_copy)
  _WRAP_METHOD(Glib::RefPtr<Gst::Caps> copy_nth(guint nth) const, gst_caps_copy_nth)
  _WRAP_METHOD(void append(const Glib::RefPtr<Gst::Caps>& caps), gst_caps_append)
  _WRAP_METHOD(void merge(const Glib::RefPtr<Gst::Caps>& caps), gst_caps_merge)

  /** Appends a structure to caps.
   *
   * @param structure The Gst::Structure to append.
   */
  void append_structure(const Structure& structure);
  _IGNORE(gst_caps_append_structure)

  /** Appends a structure to caps if its not already expressed by caps.
   *
   * @param structure The Gst::Structure to merge.
   */
  void merge_structure(Structure& structure);
  _IGNORE(gst_caps_merge_structure)

#m4 _CONVERSION(`GstStructure*', `const Structure', `Glib::wrap($3, true)')
  /** Finds the structure in caps that has the index @a idx, and returns it.
   *
   * @param index The index of the structure.
   * @return The Gst::Structure corresponding to index.
   */
  _WRAP_METHOD(const Structure get_structure(guint idx) const, gst_caps_get_structure)

  _WRAP_METHOD(void remove_structure(guint idx), gst_caps_remove_structure)
  _WRAP_METHOD(guint size() const, gst_caps_get_size)

// There's no need to take an extra reference because we are stealing the
// structure.
#m4 _CONVERSION(`GstStructure*', `Structure', `Glib::wrap($3)')
  _WRAP_METHOD(Structure steal_structure(guint index), gst_caps_steal_structure)

  /** Sets fields in a simple Gst::Caps. A simple Gst::Caps is one that only
   * has one structure. This method, like the Gst::Structure::set_field()
   * methods, translates certain GTypes to GStreamer specific GTypes for
   * functional compatibility.
   *
   * @param name Field to set.
   * @param value The value which the field should be set to.
   */
  void set_simple(const Glib::ustring& name, const Glib::ValueBase& value);
  _IGNORE(gst_caps_set_simple, gst_caps_set_simple_valist)

  /** Sets fields in a simple Gst::Caps. A simple Gst::Caps is one that only
   * has one structure. This method, like the Gst::Structure::set_field()
   * methods, translates certain GTypes to GStreamer specific GTypes for
   * functional compatibility.
   *
   * @param name Field to set.
   * @param data A value which the field should be set to (this can be any
   * supported C++ type).
   */
  template <class DataType>
  void set_simple(const Glib::ustring& name, const DataType& data);

  /** Sets fields in a simple Gst::Caps. A simple Gst::Caps is one that only
   * has one structure.
   *
   * @param name Field to set.
   * @param data A C string (const char*) which the field should be set to.
   */
  void set_simple(const Glib::ustring& name, const char* data);

  _WRAP_METHOD(void set_value(const Glib::ustring& field, const Glib::ValueBase& value), gst_caps_set_value)

  /** Sets the given @a field on all structures to the given value. This is a
   * convenience function for calling Gst::Structure::set_value()  on all
   * structures.
   *
   * @param name Field to set.
   * @param data A value which the field should be set to (this can be any
   * supported C++ type).
   */
  template <class DataType>
  void set_value(const Glib::ustring& name, const DataType& data);

  _WRAP_METHOD(bool is_any() const, gst_caps_is_any)
  _WRAP_METHOD(bool empty() const, gst_caps_is_empty)
  _WRAP_METHOD(bool is_fixed() const, gst_caps_is_fixed)
  _WRAP_METHOD(bool equals(const Glib::RefPtr<const Gst::Caps>& other_caps) const, gst_caps_is_equal)
  _WRAP_METHOD(bool equals_fixed(const Glib::RefPtr<const Gst::Caps>& other_caps) const, gst_caps_is_equal_fixed)
  _WRAP_METHOD(bool is_always_compatible(const Glib::RefPtr<const Gst::Caps>& other_caps) const, gst_caps_is_always_compatible)
  _WRAP_METHOD(bool is_subset(const Glib::RefPtr<const Gst::Caps>& superset_caps) const, gst_caps_is_subset)
  _WRAP_METHOD(bool can_intersect(const Glib::RefPtr<const Gst::Caps>& caps2) const, gst_caps_can_intersect)

  //This is const (returns a non const) because it always creates a new instance:
  _WRAP_METHOD(Glib::RefPtr<Gst::Caps> get_intersect(const Glib::RefPtr<const Gst::Caps>& other_caps) const, gst_caps_intersect)

  //This is const (returns a non const) because it always creates a new instance:
  _WRAP_METHOD(Glib::RefPtr<Gst::Caps> get_intersect(const Glib::RefPtr<const Gst::Caps>& other_caps, CapsIntersectMode) const, gst_caps_intersect_full)

  //This is const (returns a non const) because it always creates a new instance:
  _WRAP_METHOD(Glib::RefPtr<Gst::Caps> get_union(const Glib::RefPtr<const Gst::Caps>& other_caps) const, gst_caps_union)

  //This is const (returns a non const) because it always creates a new instance:
  _WRAP_METHOD(Glib::RefPtr<Gst::Caps> get_normal() const, gst_caps_normalize)

  _WRAP_METHOD(bool simplify(), gst_caps_do_simplify)

  /** Serializes a Gst::Caps to XML and adds it as a child node of @a parent.
   * @param parent A XML parent node.
   * @return The parent XML Node.
   */
  xmlpp::Node* save(xmlpp::Node* parent) const;
  _IGNORE(gst_caps_save_thyself)

  _WRAP_METHOD(static Glib::RefPtr<Gst::Caps> load(xmlpp::Node* parent), gst_caps_load_thyself)

  _WRAP_METHOD(Glib::ustring to_string() const, gst_caps_to_string)

  //This is const (returns a non const) because it always creates a new instance:
  _WRAP_METHOD(Glib::RefPtr<Gst::Caps> get_difference(const Glib::RefPtr<const Gst::Caps>& subtrahend_caps) const, gst_caps_subtract)

  _WRAP_METHOD(Glib::RefPtr<Gst::Caps> create_writable(), gst_caps_make_writable)
  _WRAP_METHOD(void truncate(), gst_caps_truncate)
};

/******************************* Gst::Caps *******************************/

#ifndef DOXYGEN_SHOULD_SKIP_THIS

template <class DataType>
void Caps::set_simple(const Glib::ustring& name, const DataType& data)
{
  typedef Glib::Value<DataType> ValueType;

  ValueType value;
  value.init(ValueType::value_type());
  value.set(data);
  this->set_simple(name, reinterpret_cast<Glib::ValueBase&>(value));
}

template <class DataType>
void Caps::set_value(const Glib::ustring& name, const DataType& data)
{
  typedef Glib::Value<DataType> ValueType;

  ValueType value;
  value.init(ValueType::value_type());
  value.set(data);
  this->set_value(name, reinterpret_cast<Glib::ValueBase&>(value));
}

#endif /* DOXYGEN_SHOULD_SKIP_THIS */

} //namespace Gst

#ifndef DOXYGEN_SHOULD_SKIP_THIS
namespace Glib
{

template <>
class Value< Glib::RefPtr<Gst::Caps> > : public ValueBase_Boxed
{
public:
  static GType value_type() { return Gst::Caps::get_type(); }
  void set(const Glib::RefPtr<Gst::Caps>& caps) { set_boxed(Glib::unwrap(caps)); }
  Glib::RefPtr<Gst::Caps> get()                 { return Glib::RefPtr<Gst::Caps>(reinterpret_cast<Gst::Caps*>(get_boxed())); }
};

}
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
