/* 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/gsttagsetter.h>
#include <glibmm/interface.h>
#include <gstreamermm/enums.h>
#include <gstreamermm/taglist.h>

_DEFS(gstreamermm,gst)

namespace Gst
{

/** An interface that allows setting and retrieval of media metadata.
 * Elements that support changing a stream's metadata will implement this
 * interface. Examples of such elements are 'vorbisenc', 'theoraenc' and
 * 'id3v2mux'.
 *
 * If you just want to retrieve metadata in your application then all you need
 * to do is watch for tag messages on your pipeline's bus. This interface is
 * only for setting metadata, not for extracting it. To set tags from the
 * application, find tagsetter elements and set tags using e.g. merge_tags() or
 * add_tags(). The application should do that before the element goes to
 * Gst::STATE_PAUSED.
 * @ingroup GstInterfaces
 */
class TagSetter : public Glib::Interface
{
  _CLASS_INTERFACE(TagSetter, GstTagSetter, GST_TAG_SETTER, GstTagSetterIFace)

public:
  _WRAP_METHOD(void reset_tags(), gst_tag_setter_reset_tags)
  _WRAP_METHOD(void merge_tags(const Gst::TagList& list, TagMergeMode mode = TAG_MERGE_PREPEND), gst_tag_setter_merge_tags)

  /** Adds the given Glib::ValueBase on the setter using the given merge mode. 
   *
   * @param tag The tag to set.
   * @param value The value to set the tag to.
   * @param mode The mode to use.
   */
  void add_tag(Tag tag, const Glib::ValueBase& value, TagMergeMode mode = TAG_MERGE_PREPEND);
  _IGNORE(gst_tag_setter_add_tag_valist,
          gst_tag_setter_add_tag_value,
          gst_tag_setter_add_tag_valist_values)

  /** Adds the given Glib::ValueBase on the setter using the given merge mode. 
   *
   * @param tag The tag to set.
   * @param value The value to set the tag to.
   * @param mode The mode to use.
   */
  void add_tag(const Glib::ustring& tag, const Glib::ValueBase& value,
    TagMergeMode mode = TAG_MERGE_PREPEND);

  /** Adds the given value on the setter using the given merge mode.
   *
   * @param tag The tag to set.
   * @param data The value to set the tag to (this may be any supported C++
   * type).
   * @param mode The mode to use.
   */
  template <class DataType>
  void add_tag(Tag tag, const DataType& data, TagMergeMode mode = TAG_MERGE_PREPEND);

  /** Adds the given value on the setter using the given merge mode.
   *
   * @param tag The tag to set.
   * @param data The value to set the tag to (this may be any supported C++
   * type).
   * @param mode The mode to use.
   */
  template <class DataType>
    void add_tag(const Glib::ustring& tag, const DataType& data,
    TagMergeMode mode = TAG_MERGE_PREPEND);

  /** Adds the given value on the setter using the given merge mode. 
   *
   * @param tag The tag to set.
   * @param data The value to set the tag to.
   * @param mode The mode to use.
   */
  void add_tag(Tag tag, const char* data, TagMergeMode mode = TAG_MERGE_PREPEND);

  /** Adds the given value on the setter using the given merge mode. 
   *
   * @param tag The tag to set.
   * @param data The value to set the tag to.
   * @param mode The mode to use.
   */
  void add_tag(const Glib::ustring& tag, const char* data,
    TagMergeMode mode = TAG_MERGE_PREPEND);

// A copy is taken so that the original is not freed by the wrapper.
#m4 _CONVERSION(`const GstTagList*',`const Gst::TagList',`Glib::wrap_taglist(const_cast<GstTagList*>($3), true)')
  _WRAP_METHOD(const Gst::TagList get_tag_list() const, gst_tag_setter_get_tag_list)

  _WRAP_METHOD(void set_tag_merge_mode(TagMergeMode mode), gst_tag_setter_set_tag_merge_mode)
  _WRAP_METHOD(TagMergeMode get_tag_merge_mode() const, gst_tag_setter_get_tag_merge_mode)

  //Variable argument functions are ignored.
  _IGNORE(gst_tag_setter_add_tags, gst_tag_setter_add_tag_values)
};

#ifndef DOXYGEN_SHOULD_SKIP_THIS

/************************** Gst::TagSetter ***************************/

template <class DataType>
void TagSetter::add_tag(Tag tag, const DataType& data, TagMergeMode mode)
{
  typedef Glib::Value<DataType> ValueType;

  ValueType value;
  value.init(ValueType::value_type());
  value.set(data);
  this->add_tag(tag, (Glib::ValueBase)(value), mode);
}

template <class DataType>
  void TagSetter::add_tag(const Glib::ustring& tag, const DataType& data,
  TagMergeMode mode)
{
  typedef Glib::Value<DataType> ValueType;

  ValueType value;
  value.init(ValueType::value_type());
  value.set(data);
  this->add_tag(tag, (Glib::ValueBase)(value), mode);
}

#endif /* DOXYGEN_SHOULD_SKIP_THIS */

} // namespace Gst
