/* 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/gstmessage.h>
#include <gstreamermm/miniobject.h>
#include <gstreamermm/wrap.h>
#include <gstreamermm/format.h>
#include <gstreamermm/clock.h>
#include <gstreamermm/query.h>

_DEFS(gstreamermm,gst)

namespace Gst
{

_WRAP_ENUM(MessageType, GstMessageType)
_WRAP_ENUM(StructureChangeType, GstStructureChangeType)

_WRAP_ENUM(StreamStatusType, GstStreamStatusType)

namespace Enums
{

/** Gets a printable name for the given message type.
 * @param type The message type.
 * @return The name of the message type.
 */
Glib::ustring get_name(MessageType type);

/** Gets the unique quark for the given message type.
 * @param type The message type.
 * @return The quark associated with the message type.
 */
Glib::QueryQuark get_quark(MessageType type);

} //namespace Enums

class Element;
class Pad;
class Structure;
class TagList;

/** A class that represents lightweight objects to signal the application of
 * pipeline events.
 * Messages are implemented as a subclass of Gst::MiniObject with a generic
 * Gst::Structure as the content. This allows for writing custom messages
 * without requiring an API change while allowing a wide range of different
 * types of messages.
 *
 * Messages are posted by objects in the pipeline and are passed to the
 * application using the Gst::Bus.
 *
 * The basic use pattern of posting a message on a Gst::Bus is as follows: 
 * @code
 * bus->post(Gst::MessageEos::create(my_element));
 * @endcode
 */
class Message : public Gst::MiniObject
{
  _CLASS_GSTMINIOBJECT(Message, GstMessage, GST_MESSAGE, Gst::MiniObject, GstMiniObject)
  _IGNORE(gst_message_ref, gst_message_unref)
  _CUSTOM_WRAP_NEW

public:
  /** Wrap a GstMessage in a C++ instance, creating an instance of a
   *  derived Gst::Message.  Gst::wrap() would just create a Gst::Message
   *  (rather than a derived one) because the derived Gst::Message classes
   *  do not correspond to GType types in the GStreamer API.
   */
  static Glib::RefPtr<Gst::Message> wrap(GstMessage* message, bool take_copy = false);

// A copy is taken so that the original is not freed by the wrapper.
#m4 _CONVERSION(`const GstStructure*',`Gst::Structure',`Glib::wrap(const_cast<GstStructure*>($3), true)')
  _WRAP_METHOD(Gst::Structure get_structure() const, gst_message_get_structure)

  /** Checks if a message is writable. If not, a writable copy is made and
   * returned.
   * @return A Gst::Message (possibly the same pointer) that is writable.
   */
   Glib::RefPtr<Gst::Message> create_writable();

  _WRAP_METHOD(guint32 get_seqnum() const, gst_message_get_seqnum)
  _WRAP_METHOD(void set_seqnum(guint32 seqnum), gst_message_set_seqnum)

  /** Get the GstMessageType of message.
   */
  _MEMBER_GET(message_type, type, MessageType, GstMessageType)

  /** Get the timestamp of message. This is the timestamp when the message was
   * created.
   */
  _MEMBER_GET(timestamp, timestamp, ClockTime, guint64)

  /** Get the object that posted the message.
   */
  _MEMBER_GET_GOBJECT(source, src, Gst::Object, GstObject*)

  /** Virtual function called when the Gst::Message needs to be copied.
   */
  virtual Glib::RefPtr<Gst::MiniObject> copy_vfunc() const;

  /** Virtual function called when the Gst::Message is about to be finalized.
   */
  virtual void finalize_vfunc();

protected:
#m4begin
  _PUSH(SECTION_PCC_CLASS_INIT_VFUNCS)
  GST_MINI_OBJECT_CLASS(klass)->copy = &copy_vfunc_callback;
  GST_MINI_OBJECT_CLASS(klass)->finalize = &finalize_vfunc_callback;
  _SECTION(SECTION_PH_VFUNCS)
  static GstMiniObject* copy_vfunc_callback(const GstMiniObject* self);
  static void finalize_vfunc_callback(GstMiniObject* self);
  _POP()
#m4end

protected:
  // This method is used in the create() methods to convert a wrapped
  // GstMessage to one of the more specific Gst::Message types.
  template <class MessageType>
    static inline Glib::RefPtr<MessageType> wrap(GstMessage* message,
    bool take_copy = false);
};

//TODO: Modify create methods of derived Message classes to return
//Glib::RefPtr<...> to the derived class and not just Gst::Message. Must deal
//with GstStructure immutability problem (bug #510301) first because casting
//Glib::RefPtrs references the objects which causes problems when GStreamer API
//tries to modify the GstStructures of the objects.

/** An end of stream message.
 * See create() for more details.
 */
class MessageEos : public Message
{
public:
  explicit MessageEos(GstMessage* castitem);

  /** Create a new eos message. This message is generated and posted in the
   * sink elements of a Gst::Bin. The bin will only forward the EOS message to
   * the application if all sinks have posted an EOS message.
   * 
   * @param src The object originating the message.
   * @return The new eos message. MT safe. 
   */
  static Glib::RefPtr<Gst::MessageEos>
    create(const Glib::RefPtr<Gst::Object>& src);
};

/** An error message.
 * See create() for more details.
 */
class MessageError : public Message
{
public:
  explicit MessageError(GstMessage* castitem);

  /** Create a new error message. The message will copy error and debug. This
   * message is posted by elements when a fatal event occured. The pipeline
   * will probably (partially) stop. The application receiving this message
   * should stop the pipeline.
   *
   * @param src The object originating the message.
   * @param error The Glib::Error for this message.
   * @param debug A debugging string for something or other.
   * @return The new error message. MT safe. 
   */
  static Glib::RefPtr<Gst::MessageError>
    create(const Glib::RefPtr<Gst::Object>& src,
    Glib::Error& error, const std::string& debug);

  /** Extracts the Glib::Error and debug string from the Gst::MessageError.
   *
   * MT safe.
   *
   * @param error Location for the Glib::Error.
   * @param debug Location for the debug message.
   */
  void parse(Glib::Error& error, std::string& debug) const;
  _IGNORE(gst_message_parse_error)

  /** Extracts and returns the Glib::Error from the Gst::MessageError.
   *
   * MT safe.
   *
   * @return The Glib::Error.
   */
  Glib::Error parse() const;

  /** Extracts and returns the debug message from the Gst::MessageError.
   *
   * MT safe.
   *
   * @return The debug message.
   */
  std::string parse_debug() const;
};

/** A warning message.
 * See create() for more details.
 */
class MessageWarning : public Message
{
public:
  explicit MessageWarning(GstMessage* castitem);

  /** Create a new warning message. The message will make copies of error and
   * debug.
   *
   * @param src The object originating the message.
   * @param error The Glib::Error for this message.
   * @param debug A debugging string for something or other.
   * @return The new warning message. MT safe. 
   */
  static Glib::RefPtr<Gst::MessageWarning>
    create(const Glib::RefPtr<Gst::Object>& src, Glib::Error& error,
    const std::string& debug);

  /** Extracts the Glib::Error and debug string from the Gst::MessageWarning.
   *
   * MT safe.
   *
   * @param error Location for the Glib::Error.
   * @param debug Location for the debug message.
   */
  void parse(Glib::Error& error, std::string& debug) const;
  _IGNORE(gst_message_parse_warning)

  /** Extracts and returns the Glib::Error from the Gst::MessageWarning.
   *
   * MT safe.
   *
   * @return The Glib::Error.
   */
  Glib::Error parse() const;

  /** Extracts and returns the debug message from the Gst::MessageWarning.
   *
   * MT safe.
   *
   * @return The debug message.
   */
  std::string parse_debug() const;
};

/** An informational message.
 * See create() for more details.
 */
class MessageInfo : public Message
{
public:
  explicit MessageInfo(GstMessage* castitem);

  /** Create a new info message.
   *
   * @param src The object originating the message.
   * @param error The Glib::Error for this message.
   * @param debug A debugging string for something or other.
   * @return The new info message.
   *
   * Since 0.10.12 MT safe.
   */
  static Glib::RefPtr<Gst::MessageInfo>
    create(const Glib::RefPtr<Gst::Object>& src,
    Glib::Error& error, const std::string& debug);

  /** Extracts the Glib::Error and debug string from the Gst::MessageInfo.
   *
   * MT safe.
   *
   * @param error Location for the Glib::Error.
   * @param debug Location for the debug message.
   */
  void parse(Glib::Error& error, std::string& debug) const;
  _IGNORE(gst_message_parse_info)

  /** Extracts and returns the Glib::Error from the Gst::MessageInfo.
   *
   * MT safe.
   *
   * @return The Glib::Error.
   */
  Glib::Error parse() const;

  /** Extracts and returns the debug message from the Gst::MessageInfo.
   *
   * MT safe.
   *
   * @return The debug message.
   */
  std::string parse_debug() const;
};

/** A tag message.
 * See create() for more details.
 */
class MessageTag : public Message
{
public:
  explicit MessageTag(GstMessage* castitem);

  /** Create a new tag message. The taglist will be copied.  The message is
   * posted by elements that discovered a new taglist.
   *
   * @param src The object originating the message.
   * @param tag_list The tag list for the message.
   * @return The new tag message. MT safe.
   */
  static Glib::RefPtr<Gst::MessageTag>
    create(const Glib::RefPtr<Gst::Object>& src, const Gst::TagList& taglist);

  /** Create a new tag message. The taglist will be copied.  The message is
   * posted by elements that discovered a new taglist.
   *
   * @param src The object originating the message.
   * @param pad The originating pad for the tag.
   * @param tag_list The tag list for the message.
   * @return The new tag message. MT safe.
   * 
   * Since 0.10.24.
   */
  static Glib::RefPtr<Gst::MessageTag>
    create(const Glib::RefPtr<Gst::Object>& src,
    const Glib::RefPtr<Gst::Pad>& pad, const Gst::TagList& taglist);

  /** Extracts the Gst::Pad and Gst::TagList from the Gst::MessageTag.
   *
   * MT safe.
   *
   * @param pad Location where the originating pad is stored.
   * @param tag_list Location for the tag-list.
   *
   * Since 0.10.24.
   */
  void parse(Glib::RefPtr<Gst::Pad>& pad, Gst::TagList& tag_list) const;

  /** Extracts and returns the Gst::TagList from the Gst::MessageTag.
   *
   * MT safe.
   *
   * @return A copy of the Gst::TagList.
   */
  Gst::TagList parse() const;
  _IGNORE(gst_message_parse_tag)

  /** Extracts and returns the Gst::Pad from the Gst::MessageTag.
   *
   * MT safe.
   *
   * @return The Gst::Pad.
   *
   * Since 0.10.24.
   */
  Glib::RefPtr<Gst::Pad> parse_pad() const;
  _IGNORE(gst_message_parse_tag_full)
};

/** A buffering message.
 * See create() for more details.
 */
class MessageBuffering : public Message
{
public:
  explicit MessageBuffering(GstMessage* castitem);

  /** Create a new buffering message. This message can be posted by an element
   * that needs to buffer data before it can continue processing. @a percent
   * should be a value between 0 and 100. A value of 100 means that the
   * buffering completed.
   *
   * When @a percent is < 100 the application should PAUSE a PLAYING pipeline.
   * When @a percent is 100, the application can set the pipeline (back) to
   * PLAYING. The application must be prepared to receive BUFFERING messages in
   * the PREROLLING state and may only set the pipeline to PLAYING after
   * receiving a message with @a percent set to 100, which can happen after the
   * pipeline completed prerolling.
   *
   * @param src The object originating the message.  
   * @param percent The buffering percent.
   * @return The new buffering message.
   *
   * Since 0.10.11 MT safe.
   */
  static Glib::RefPtr<Gst::MessageBuffering>
    create(const Glib::RefPtr<Gst::Object>& src, int percent);

  /** Extracts and returns the buffering percent from the
   * Gst::MessageBuffering.
   * @return The percent as an integer.
   */
  int parse() const;
  _IGNORE(gst_message_parse_buffering)

  /** Configures the buffering stats values in message.
   *
   * @param mode A buffering mode.
   * @param avg_in The average input rate.
   * @param avg_out The average output rate.
   * @param buffering_left Amount of buffering time left in milliseconds.
   *
   * Since 0.10.20.
   */
  void set_stats(BufferingMode mode, int avg_in, int avg_out, gint64 buffering_left);
  _IGNORE(gst_message_set_buffering_stats)

  /** Extracts the buffering stats values from message.
   *
   * @param mode Location for the buffering mode.
   * @param avg_in Location for the average input rate.
   * @param avg_out Location for the average output rate.
   * @param buffering_left Location for the amount of buffering time left.
   *
   * Since 0.10.20.
   */
  void parse_stats(BufferingMode& mode, int& avg_in, int& avg_out, gint64& buffering_left) const;
  _IGNORE(gst_message_parse_buffering_stats)

  /** Extracts and returns the buffering mode from message.
   *
   * @return The buffering mode.
   */
  BufferingMode parse_stats_buffering_mode() const;

  /** Extracts and returns the average input rate from message.
   *
   * @return The average input rate.
   */
  int parse_stats_avg_in() const;

  /** Extracts and returns the average output rate from message.
   *
   * @return The average output rate.
   */
  int parse_stats_avg_out() const;

  /** Extracts and returns the buffering time in milliseconds remaining from
   * message.
   *
   * @return The buffering time remaining.
   */
  gint64 parse_stats_buffering_left() const;
};

/** A state change message.
 * See create() for more details.
 */
class MessageStateChanged : public Message
{
public:
  explicit MessageStateChanged(GstMessage* castitem);

  /** Create a state change message. This message is posted whenever an element
   * changed its state.
   *
   * @param src The object originating the message.
   * @param oldstate The previous state.
   * @param newstate The new (current) state.
   * @param pending The pending (target) state.
   * @return The new state change message. MT safe.
   */
  static Glib::RefPtr<Gst::MessageStateChanged>
    create(const Glib::RefPtr<Gst::Object>& src, State oldstate,
    State newstate, State pending);

  /** Extracts the old, new and pending states from the
   * Gst::MessageStateChanged.
   *
   * MT safe.
   *
   * @param oldstate The previous state.
   * @param newstate The new (current) state.
   * @param pending The pending (target) state.
   */
  void parse(State& oldstate, State& newstate, State& pending) const;
  _IGNORE(gst_message_parse_state_changed)

  /** Extracts and returns the new state from the Gst::MessageStateChanged.
   *
   * MT safe.
   *
   * @return The new (current) state.
   */
  State parse() const;

  /** Extracts and returns the old state from the Gst::MessageStateChanged.
   *
   * MT safe.
   *
   * @return The old state.
   */
  State parse_old() const;

  /** Extracts and returns the pending state from the Gst::MessageStateChanged.
   *
   * MT safe.
   *
   * @return The pending state.
   */
  State parse_pending() const;
};

/** A state dirty message.
 * See create() for more details.
 */
class MessageStateDirty : public Message
{
public:
  explicit MessageStateDirty(GstMessage* castitem);

  /** Create a state dirty message. This message is posted whenever an element
   * changed its state asynchronously and is used internally to update the
   * states of container objects.
   *
   * @param src The object originating the message.
   * @return The new state dirty message. MT safe.
   */
  static Glib::RefPtr<Gst::MessageStateDirty>
    create(const Glib::RefPtr<Gst::Object>& src);
};

/** A step done message.
 * See create() for more details.
 */
class MessageStepDone : public Message
{
public:
  explicit MessageStepDone(GstMessage* castitem);

  /** Create a step done message.  This message is posted by elements when they
   * complete a part, when @a intermediate set to true, or a complete step
   * operation.
   *
   * @a duration will contain the amount of time (in Gst::FORMAT_TIME) of the
   * stepped @a amount of media in format @a format.
   *
   * @param src The object originating the message.
   * @param format The format of amount.
   * @param amount The amount of stepped data.
   * @param rate The rate of the stepped amount.
   * @param flush Is this an flushing step.
   * @param intermediate Is this an intermediate step.
   * @param duration The duration of the data.
   * @param eos The step caused EOS.
   * @return The new step done message. MT safe.
   *
   * Since 0.10.24.
   */
  static Glib::RefPtr<Gst::MessageStepDone>
    create(const Glib::RefPtr<Gst::Object>& src, Gst::Format format,
    guint64 amount, double rate, bool flush, bool intermediate,
    guint64 duration, bool eos);

  /** Extract the values of the step done message.
   *
   * MT safe.
   *
   * @param format Result location for the format.
   * @param amount Result location for the amount.
   * @param rate Result location for the rate.
   * @param flush Result location for the flush flag.
   * @param intermediate Result location for the intermediate flag.
   * @param duration Result location for the duration.
   * @param eos Result location for the EOS flag.
   *
   * Since 0.10.24.
   */
  void parse(Gst::Format& format, guint64& amount, double& rate, bool& flush,
    bool& intermediate, guint64& duration, bool& eos) const;
  _IGNORE(gst_message_parse_step_done)

  /** Extracts the duration of the step done message.
   * @return The duration.
   */
  guint64 parse() const;

  /** Extracts the format of the step done message.
   * @return The format.
   */
  Gst::Format parse_format() const;

  /** Extracts the amount of the step done message.
   * @return The amount.
   */
  guint64 parse_amount() const;

  /** Extracts the rate of the step done message.
   * @return The rate.
   */
  double parse_rate() const;

  /** Extracts the flush flag of the step done message.
   * @return The flush flag.
   */
  bool parse_flush() const;

  /** Extracts the intermediate flag of the step done message.
   * @return The intermediate flag.
   */
  bool parse_intermediate() const;

  /** Extracts the eos flag of the step done message.
   * @return The eos flag.
   */
  bool parse_eos() const;
};

/** A clock provide message.
 * See create() for more details.
 */
class MessageClockProvide : public Message
{
public:
  explicit MessageClockProvide(GstMessage *message);

  /** Create a clock provide message. This message is posted whenever an
   * element is ready to provide a clock or lost its ability to provide a clock
   * (maybe because it paused or became EOS).
   *
   * This message is mainly used internally to manage the clock selection.
   *
   * @param src The object originating the message.
   * @param clock The clock it provides.
   * @param ready true if the sender can provide a clock.
   * @return The new provide clock message. MT safe.
   */
  static Glib::RefPtr<Gst::MessageClockProvide>
    create(const Glib::RefPtr<Gst::Object>& src,
    const Glib::RefPtr<Gst::Clock>& clock, bool ready);

  /** Extracts the clock and ready flag from the Gst::MessageClockProvide. The
   * clock object returned remains valid until the message is freed.
   *
   * MT safe.
   *
   * @param clock Location in which to hold a clock object.
   * @param ready Location in which to hold the ready flag.
   */
  void parse(Glib::RefPtr<Gst::Clock>& clock, bool& ready) const;
  _IGNORE(gst_message_parse_clock_provide)

  /** Extracts and returns the clock from the Gst::MessageClockProvide. The
   * clock object returned remains valid until the message is freed.
   *
   * MT safe.
   *
   * @return The clock object of the message.
   */
  Glib::RefPtr<Gst::Clock> parse();

  /** Extracts and returns the clock from the Gst::MessageClockProvide. The
   * clock object returned remains valid until the message is freed.
   *
   * MT safe.
   *
   * @return The clock object of the message.
   */
  Glib::RefPtr<const Gst::Clock> parse() const;

  /** Extracts and returns the ready flag from the Gst::MessageClockProvide.
   *
   * MT safe.
   *
   * @return The ready flag of the message.
   */
  bool parse_ready() const;
};

/** A clock lost message.
 * See create() for more details.
 */
class MessageClockLost : public Message
{
public:
  explicit MessageClockLost(GstMessage* castitem);

  /** Create a clock lost message. This message is posted whenever the clock is
   * not valid anymore.  If this message is posted by the pipeline, the
   * pipeline will select a new clock again when it goes to PLAYING. It might
   * therefore be needed to set the pipeline to PAUSED and PLAYING again.
   *
   * @param src The object originating the message.
   * @param clock The clock that was lost.
   * @return The new clock lost message. MT safe. 
   */
  static Glib::RefPtr<Gst::MessageClockLost>
    create(const Glib::RefPtr<Gst::Object>& src,
    const Glib::RefPtr<Gst::Clock>& clock);

  /** Extracts and returns the lost clock from the Gst::MessageClockLost. The
   * clock object returned remains valid until the message is freed.
   *
   * MT safe.
   * @return The lost clock.
   */
  Glib::RefPtr<Gst::Clock> parse();
  _IGNORE(gst_message_parse_clock_lost)

  /** Extracts and returns the lost clock from the Gst::MessageClockLost. The
   * clock object returned remains valid until the message is freed.
   *
   * MT safe.
   * @return The lost clock.
   */
  Glib::RefPtr<const Gst::Clock> parse() const;
};

/** A new clock message.
 * See create() for more details.
 */
class MessageNewClock: public Message
{
public:
  explicit MessageNewClock(GstMessage* castitem);

  /** Create a new clock message. This message is posted whenever the pipeline
   * selectes a new clock for the pipeline.
   *
   * @param src The object originating the message.
   * @param clock The new selected clock.
   * @return The new new clock message. MT safe.
   */
  static Glib::RefPtr<Gst::MessageNewClock>
    create(const Glib::RefPtr<Gst::Object>& src,
    const Glib::RefPtr<Gst::Clock>& clock);

  /** Extracts and returns the new clock from the Gst::MessageNewClock. The
   * clock object returned remains valid until the message is freed.
   *
   * MT safe.
   *
   * @return The selected new clock.
   */
  Glib::RefPtr<Gst::Clock> parse();
  _IGNORE(gst_message_parse_new_clock)

  /** Extracts and returns the new clock from the Gst::MessageNewClock. The
   * clock object returned remains valid until the message is freed.
   *
   * MT safe.
   *
   * @return The selected new clock.
   */
  Glib::RefPtr<const Gst::Clock> parse() const;
};

/** An application message.
 * See create() for more details.
 */
class MessageApplication : public Message
{
public:
  explicit MessageApplication(GstMessage *message);

  /** Create a new application-typed message. GStreamer will never create these
   * messages; they are a gift from us to you. Enjoy.
   *
   * @param src The object originating the message.
   * @param structure The structure for the message.  The structure will be
   * copied.
   * @return The new application message. MT safe.
   */
  static Glib::RefPtr<Gst::MessageApplication>
    create(const Glib::RefPtr<Gst::Object>& src, Gst::Structure& structure);

  /** Create a new application-typed message (no Gst::Structure is needed).
   * GStreamer will never create these messages; they are a gift from us to
   * you. Enjoy.
   *
   * @param src The object originating the message.
   * @return The new application message. MT safe.
   */
  static Glib::RefPtr<Gst::MessageApplication>
    create(const Glib::RefPtr<Gst::Object>& src);
};

/** An element specific message.
 * See create() for more details.
 */
class MessageElement : public Message
{
public:
  explicit MessageElement(GstMessage* castitem);

  /** Create a new element-specific message. This is meant as a generic way of
   * allowing one-way communication from an element to an application, for
   * example "the firewire cable was unplugged". The format of the message
   * should be documented in the element's documentation.
   *
   * @param src The object originating the message.
   * @param structure The structure for the message. The message will take a
   * copy of the structure.
   * @return The new element message. MT safe.
   */
  static Glib::RefPtr<Gst::MessageElement>
    create(const Glib::RefPtr<Gst::Object>& src, Gst::Structure& structure);

  /** Create a new element-specific message. This is meant as a generic way of
   * allowing one-way communication from an element to an application, for
   * example "the firewire cable was unplugged". The format of the message
   * should be documented in the element's documentation. No Gst::Structure is
   * needed.
   *
   * @param src The object originating the message.
   * @return The new element message. MT safe.
   */
  static Glib::RefPtr<Gst::MessageElement>
    create(const Glib::RefPtr<Gst::Object>& src);
};

/** A custom message.
 * See create() for more details.
 */
class MessageCustom : public Message
{
public:
  explicit MessageCustom(GstMessage* castitem);

  /** Create a new custom-typed message. This can be used for anything not
   * handled by other message-specific functions to pass a message to the app.
   *
   * @param type The Gst::MessageType to distinguish messages.
   * @param src The object originating the message.
   * @param structure The Gst::Structure for the message. The message will take
   * a copy of the structure.
   * @return The new message. MT safe.
   */
  static Glib::RefPtr<Gst::MessageCustom>
    create(MessageType type, const Glib::RefPtr<Gst::Object>& src,
    Gst::Structure& structure);

  /** Create a new custom-typed message. This can be used for anything not
   * handled by other message-specific functions to pass a message to the app.
   * No Gst::Structure is needed.
   *
   * @param type The Gst::MessageType to distinguish messages.
   * @param src The object originating the message.
   * @return The new message. MT safe.
   */
  static Glib::RefPtr<Gst::MessageCustom>
    create(MessageType type, const Glib::RefPtr<Gst::Object>& src);
};

/** A segment start message.
 * See create() for more details.
 */
class MessageSegmentStart : public Message
{
public:
  explicit MessageSegmentStart(GstMessage* castitem);

  /** Create a new segment message. This message is posted by elements that
   * start playback of a segment as a result of a segment seek. This message is
   * not received by the application but is used for maintenance reasons in
   * container elements.
   *
   * @param src The object originating the message.
   * @param format The format of the position being played.
   * @param position The position of the segment being played.
   * @return The new segment start message. MT safe.
   */
  static Glib::RefPtr<Gst::MessageSegmentStart>
    create(const Glib::RefPtr<Gst::Object>& src, Format format,
    gint64 position);

  /** Extracts the position and format from the segment start message.
   *
   * MT safe.
   *
   * @param format Result location for the format.
   * @param position Result location for the position.
   */
  void parse(Format& format, gint64& position) const;
  _IGNORE(gst_message_parse_segment_start)

  /** Extracts and returns the position from the segment start message.
   *
   * MT safe.
   *
   * @return The position.
   */
  gint64 parse() const;

  /** Extracts and returns the format from the segment start message.
   *
   * MT safe.
   *
   * @return The format.
   */
  Format parse_format() const;
};

/** A segment done message.
 * See create() for more details.
 */
class MessageSegmentDone : public Message
{
public:
  explicit MessageSegmentDone(GstMessage* castitem);

  /** Create a new segment done message. This message is posted by elements
   * that finish playback of a segment as a result of a segment seek. This
   * message is received by the application after all elements that posted a
   * Gst::MessageSegmentStart have posted the Gst::MessageSegmentDone.
   *
   * @param src The object originating the message.  
   * @param format The format of the position being done.
   * @param position The position of the segment being done.
   * @return The new segment done message. MT safe.
   */
  static Glib::RefPtr<Gst::MessageSegmentDone>
    create(const Glib::RefPtr<Gst::Object>& src, Format format,
    gint64 position);

  /** Extracts the position and format from the segment done message.
   *
   * MT safe.
   *
   * @param format Result location for the format.
   * @param position Result location for the position.
   */
  void parse(Format& format, gint64& position) const;
  _IGNORE(gst_message_parse_segment_done)

  /** Extracts and returns the position from the segment done message.
   *
   * MT safe.
   *
   * @return The position.
   */
  gint64 parse() const;

  /** Extracts and returns the format from the segment done message.
   *
   * MT safe.
   *
   * @return The format.
   */
  Format parse_format() const;
};

/** A duration message.
 * See create() for more details.
 */
class MessageDuration : public Message
{
public:
  explicit MessageDuration(GstMessage* castitem);

  /** Create a new duration message. This message is posted by elements that
   * know the duration of a stream in a specific format. This message is
   * received by bins and is used to calculate the total duration of a
   * pipeline. Elements may post a duration message with a duration of
   * Gst::CLOCK_TIME_NONE to indicate that the duration has changed and the
   * cached duration should be discarded. The new duration can then be
   * retrieved via a query.
   *
   * @param src The object originating the message.
   * @param format The format of the duration.  
   * @param duration The new duration.  
   * @return The new duration message. MT safe.
   */
  static Glib::RefPtr<Gst::MessageDuration>
    create(const Glib::RefPtr<Gst::Object>& src, Format format,
    gint64 duration);

  /** Extracts the duration and format from the duration message. The duration
   * might be Gst::CLOCK_TIME_NONE, which indicates that the duration has
   * changed. Applications should always use a query to retrieve the duration
   * of a pipeline.
   *
   * MT safe.
   *
   * @param format Result location for the format.
   * @param duration Result location for the duration.
   */
  void parse(Format& format, gint64& duration) const;
  _IGNORE(gst_message_parse_duration)

  /** Extracts and returns the duration from the duration message. The duration
   * might be Gst::CLOCK_TIME_NONE, which indicates that the duration has
   * changed. Applications should always use a query to retrieve the duration
   * of a pipeline.
   *
   * MT safe.
   *
   * @return The duration.
   */
  gint64 parse() const;

  /** Extracts and returns the format from the duration message. Applications
   * should always use a query to retrieve the duration
   * of a pipeline.
   *
   * MT safe.
   *
   * @return The format.
   */
  Format parse_format() const;
};

/** A latency message.
 * See create() for more details.
 */
class MessageLatency : public Message
{
public:
  explicit MessageLatency(GstMessage* castitem);

  /** Creates a new latency message.  This message can be posted by elements
   * when their latency requirements have changed.
   *
   * @param src The object originating the message.
   * @return The new latency message. MT safe.
   *
   * Since 0.10.12.
   */
  static Glib::RefPtr<Gst::MessageLatency>
    create(const Glib::RefPtr<Gst::Object>& src);
};

/** An asynchronous start message.
 * See create() for more details.
 */
class MessageAsyncStart : public Message
{
public:
  explicit MessageAsyncStart(GstMessage* castitem);

  /** Creates a new async message.  This message is posted by elements when
   * they start an ASYNC state change. new_base_time is set to true when the
   * element lost its state when it was PLAYING.
   *
   * @param src The object originating the message.
   * @param new_base_time If a new base_time should be set on the element.
   * @return The new async_start message. MT safe.
   *
   * Since 0.10.13 
   */
  static Glib::RefPtr<Gst::MessageAsyncStart>
    create(const Glib::RefPtr<Gst::Object>& src, bool new_base_time);

  /** Extract and return the boolean new_base_time from the async_start
   * message.
   *
   * MT safe.
   *
   * @return The new_base_time boolean.
   *
   * Since 0.10.13.
   */
  bool parse() const;
  _IGNORE(gst_message_parse_async_start)
};

/** An asynchronous done message.
 * See create() for more details.
 */
class MessageAsyncDone : public Message
{
public:
  explicit MessageAsyncDone(GstMessage* castitem);

  /** Create an async done message. The message is posted when elements
   * completed an ASYNC state change.
   *
   * @param src The object originating the message.  
   * @return The new async_done message. MT safe.
   */
  static Glib::RefPtr<Gst::MessageAsyncDone>
    create(const Glib::RefPtr<Gst::Object>& src);
};

/** A step start message.
 * See create() for more details.
 */
class MessageStepStart : public Message
{
public:
  explicit MessageStepStart(GstMessage* castitem);

  /** Create a step start message.  This message is posted by elements when
   * they accept or activate a new step event for @a amount in @a format.
   *
   * @a active is set to false when the element accepted the new step event and
   * has queued it for execution in the streaming threads.
   *
   * @a active is set to true when the element has activated the step operation
   * and is now ready to start executing the step in the streaming thread.
   * After this message is emited, the application can queue a new step
   * operation in the element.
   *
   * @param src The object originating the message.  
   * @param active If the step is active or queued.  
   * @param format The format of amount.  
   * @param amount The amount of stepped data.
   * @param rate The rate of the stepped amount.  
   * @param flush Is this an flushing step.
   * @param intermediate Is this an intermediate step.
   * @return The new step start message. MT safe.
   *
   * Since 0.10.24.
   */
  static Glib::RefPtr<Gst::MessageStepStart>
    create(const Glib::RefPtr<Gst::Object>& src, bool active,
    Gst::Format format, guint64 amount, double rate, bool flush,
    bool intermediate);

  /** Extract the values of the step start message.
   *
   * MT safe.
   *
   * @param active Result location for the active flag.  
   * @param format Result location for the format.  
   * @param amount Result location for the amount.  
   * @param rate Result location for the rate.  
   * @param flush Result location for the flush flag.  
   * @param intermediate Result location for the intermediate flag.
   *
   * Since 0.10.24.
   */
  void parse(bool& active, Gst::Format& format, guint64& amount, double& rate,
    bool& flush, bool& intermediate) const;
  _IGNORE(gst_message_parse_step_start)

  /** Extracts the amount of the step start message.
   * @return The amount.
   */
  guint64 parse() const;

  /** Extracts the active flag of the step start message.
   * @return The active flag.
   */
  bool parse_active() const;

  /** Extracts the format of the step start message.
   * @return The format.
   */
  Gst::Format parse_format() const;

  /** Extracts the rate of the step start message.
   * @return The rate.
   */
  double parse_rate() const;

  /** Extracts the flush flag of the step start message.
   * @return The flush flag.
   */
  bool parse_flush() const;

  /** Extracts the intermediate flag of the step start message.
   * @return The intermediate flag.
   */
  bool parse_intermediate() const;
};

/** A structure change message.
 * See create() for more details.
 */
class MessageStructureChange : public Message
{
public:
  explicit MessageStructureChange(GstMessage* castitem);

  /** Create a new structure change message. This message is posted when the
   * structure of a pipeline is in the process of being changed, for example
   * when pads are linked or unlinked.
   *
   * @a src should be the srcpad that unlinked or linked.
   *
   * @param src The object originating the message.
   * @param type The change type.
   * @param owner The owner element of src.
   * @param busy Whether the structure change is busy.
   * @return The new structure change message. MT safe.
   *
   * Since 0.10.22.
   */
  static Glib::RefPtr<Gst::MessageStructureChange>
    create(const Glib::RefPtr<Gst::Object>& src,
    Gst::StructureChangeType type, const Glib::RefPtr<Gst::Element>& owner,
    bool busy);

  /** Extracts the change type and completion status from the Gst::Message.
   * MT safe.
   *
   * @param type A reference to hold the change type.
   * @param owner The owner element of the message source.
   * @param busy A reference to hold whether the change is in progress or has
   * been completed.
   *
   * Since 0.10.22.
   */
  void parse(Gst::StructureChangeType& type,
    Glib::RefPtr<Gst::Element>& owner, bool& busy) const;
  _IGNORE(gst_message_parse_structure_change)

  /** Extracts the change type from the Gs::tMessage.
   * MT safe.
   *
   * @return The change type.
   *
   * Since 0.10.22.
   */
  Gst::StructureChangeType parse() const;

  /** Extracts the owner from the Gst::Message.
   * MT safe.
   *
   * @return The owner element of the message source.
   *
   * Since 0.10.22.
   */
  Glib::RefPtr<Gst::Element> parse_owner() const;

  /** Extracts the completion status from the Gst::Message.
   * MT safe.
   *
   * @return whether the change is in progress or has been completed.
   *
   * Since 0.10.22.
   */
  bool parse_busy() const;
};

/** A request state message.
 * See create() for more details.
 */
class MessageRequestState : public Message
{
public:
  explicit MessageRequestState(GstMessage* castitem);

  /** This message can be posted by elements when they want to have their
   * state changed. A typical use case would be an audio server that wants to
   * pause the pipeline because a higher priority stream is being played.
   *
   * @param src The object originating the message.
   * @param state The new requested state.
   * @return The new requst state message. MT safe.
   *
   * Since 0.10.23.
   */
  static Glib::RefPtr<Gst::MessageRequestState>
    create(const Glib::RefPtr<Gst::Object>& src, Gst::State state);

  /** Extract the requested state from the request_state message.
   * @return The state. MT safe.
   *
   * Since 0.10.23.
   */
  Gst::State parse() const;
  _IGNORE(gst_message_parse_request_state)
};

/** A stream status message.
 * See create() for more details.
 */
class MessageStreamStatus : public Message
{
public:
  explicit MessageStreamStatus(GstMessage* castitem);

  /** Create a new stream status message. This message is posted when a
   * streaming thread is created/destroyed or when the state changed. 
   *
   * @param src The object originating the message.  
   * @param type The stream status type.  
   * @param owner The owner element of @a src.  
   * @return The new stream status message. MT safe.
   */
  static Glib::RefPtr<Gst::MessageStreamStatus>
    create(const Glib::RefPtr<Gst::Object>& src, Gst::StreamStatusType type,
    const Glib::RefPtr<Gst::Element>& owner);

  /** Configures the object handling the streaming thread. This is usually a
   * Gst::Task object but other objects might be added in the future.
   * @param object The object controlling the streaming.
   *
   * Since 0.10.24.
   */
  void set_object(const Glib::RefPtr<Gst::Object>& object);
  _IGNORE(gst_message_set_stream_status_object)

  /** Extracts the object managing the streaming thread from message.
   * @return The object that manages the streaming thread. The actual object
   * is usually a Gst::Task but other types can be added in the future. The
   * object remains valid as long as the message is valid. 
   */
  Glib::RefPtr<Gst::Object> get_object() const;
  _IGNORE(gst_message_get_stream_status_object)

  /** Extracts the stream status type and owner of the Gst::Message. The
   * returned owner remains valid for as long as the reference to the message
   * is valid.
   *
   * MT safe.
   *
   * @param type A reference to hold the status type.
   * @param owner A reference to hold the owner Gst::Element.
   *
   * Since 0.10.24.
   */
  void parse(Gst::StreamStatusType& type, Glib::RefPtr<Gst::Element>& owner) const;
  _IGNORE(gst_message_parse_stream_status)

  /** Extracts the stream status type.
   *
   * MT safe.
   *
   * @return The stream status type.
   *
   * Since 0.10.24.
   */
  Gst::StreamStatusType parse() const;

  /** Extracts the owner of the Gst::Message. The returned owner remains valid
   * for as long as the reference to the message is valid.
   *
   * MT safe.
   *
   * @return The owner Gst::Element.
   *
   * Since 0.10.24.
   */
  Glib::RefPtr<Gst::Element> parse_owner() const;
};

/****************************** Gst::Message **************************/

template <class MessageType>
  Glib::RefPtr<MessageType> Message::wrap(GstMessage* message, bool take_copy)
{
  Glib::RefPtr<Gst::Message> result = wrap(message, take_copy);
  return Glib::RefPtr<MessageType>::cast_dynamic(result);
}

} //namespace Gst
