/* 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/gst.h>
#include <gstreamermm/message.h>
#include <gstreamermm/structure.h>
#include <gstreamermm/taglist.h>
_PINCLUDE(gstreamermm/private/miniobject_p.h)
#include <iostream>

namespace Gst
{

namespace Enums
{

Glib::ustring get_name(EventType t)
{
  return gst_event_type_get_name(GstEventType(t));
}

Glib::QueryQuark get_quark(EventType t)
{
  return Glib::QueryQuark(gst_event_type_to_quark(GstEventType(t)));
}

EventTypeFlags get_flags(EventType t)
{
  return static_cast<EventTypeFlags>(gst_event_type_get_flags(static_cast<GstEventType>(t)));
}

} //namespace Enums

Glib::RefPtr<Gst::Event> Event::create_writable()
{
  return Glib::RefPtr<Event>::cast_static(MiniObject::create_writable());
}

bool Event::is_downstream() const
{
  return GST_EVENT_IS_DOWNSTREAM(gobj());
}

bool Event::is_upstream() const
{
  return GST_EVENT_IS_UPSTREAM(gobj());
}

bool Event::is_serialized() const
{
  return GST_EVENT_IS_SERIALIZED(gobj());
}

Glib::RefPtr<Gst::EventFlushStart> EventFlushStart::create()
{
  GstEvent* event = gst_event_new_flush_start();
  return Glib::wrap_event_derived<EventFlushStart>(event, false);
}

Glib::RefPtr<Gst::EventFlushStop> EventFlushStop::create(bool reset_time)
{
  GstEvent* event = gst_event_new_flush_stop(reset_time);
  return Glib::wrap_event_derived<EventFlushStop>(event, false);
}

Glib::RefPtr<Gst::EventEos> EventEos::create()
{
  GstEvent* event = gst_event_new_eos();
  return Glib::wrap_event_derived<EventEos>(event, false);
}

Glib::RefPtr<Gst::EventNewSegment>
  EventNewSegment::create(const Gst::Segment& segment)
{
  GstEvent* event = gst_event_new_segment(segment.gobj());
  return Glib::wrap_event_derived<EventNewSegment>(event, false);
}

void EventNewSegment::parse(const GstSegment** segment) const
{
  gst_event_parse_segment(const_cast<GstEvent*>(gobj()), segment);
}

Glib::RefPtr<Gst::EventTag> EventTag::create(const Gst::TagList& taglist)
{
  //We create a copy because gst_event_new_tag() takes ownership:
  GstTagList* c_taglist = gst_tag_list_copy(taglist.gobj());
  GstEvent* event = gst_event_new_tag(c_taglist);
  return Glib::wrap_event_derived<EventTag>(event, false);
}

Gst::TagList EventTag::parse() const
{
  GstTagList* gst_taglist = gst_tag_list_new_empty();
  gst_event_parse_tag(const_cast<GstEvent*>(gobj()), &gst_taglist);
  return Gst::TagList(gst_taglist);
}

Glib::RefPtr<Gst::EventBufferSize>
  EventBufferSize::create(Format format, gint64 minsize, gint64 maxsize,
  bool async)
{
  GstEvent* event = gst_event_new_buffer_size(GstFormat(format), minsize,
    maxsize, async);
  return Glib::wrap_event_derived<EventBufferSize>(event, false);
}

void EventBufferSize::parse(Format& format, gint64& minsize, gint64& maxsize,
  bool& async) const
{
  gboolean gst_async = FALSE;
  gst_event_parse_buffer_size(const_cast<GstEvent*>(gobj()),
    (GstFormat*)&format, &minsize, &maxsize, &gst_async);
  async = gst_async;
}

gint64 EventBufferSize::parse() const
{
  gint64 gst_minsize = 0;
  gst_event_parse_buffer_size(const_cast<GstEvent*>(gobj()), 0, &gst_minsize,
    0, 0);
  return gst_minsize;
}

Gst::Format EventBufferSize::parse_format() const
{
  GstFormat gst_format = GST_FORMAT_UNDEFINED;
  gst_event_parse_buffer_size(const_cast<GstEvent*>(gobj()),
    reinterpret_cast<GstFormat*>(&gst_format), 0, 0, 0);
  return static_cast<Gst::Format>(gst_format);
}

gint64 EventBufferSize::parse_max_size() const
{
  gint64 gst_maxsize = 0;
  gst_event_parse_buffer_size(const_cast<GstEvent*>(gobj()), 0, 0,
    &gst_maxsize, 0);
  return gst_maxsize;
}

bool EventBufferSize::parse_async() const
{
  gboolean gst_async = FALSE;
  gst_event_parse_buffer_size(const_cast<GstEvent*>(gobj()), 0, 0, 0, &gst_async);
  return gst_async;
}

Glib::RefPtr<Gst::EventQos> EventQos::create(Gst::QOSType type, double proportion,
  ClockTimeDiff diff, ClockTime timestamp)
{
  GstEvent* event = gst_event_new_qos(GstQOSType(type), proportion, GstClockTimeDiff(diff),
    GstClockTime(timestamp));
  return Glib::wrap_event_derived<EventQos>(event, false);
}

void EventQos::parse(Gst::QOSType& type, double& proportion, ClockTimeDiff& diff,
  ClockTime& timestamp) const
{
  gst_event_parse_qos(const_cast<GstEvent*>(gobj()), (GstQOSType*)&type, &proportion, &diff,
    &timestamp);
}

double EventQos::parse() const
{
  double gst_proportion = 0;
  gst_event_parse_qos(const_cast<GstEvent*>(gobj()), 0, &gst_proportion, 0, 0);
  return gst_proportion;
}

Gst::ClockTimeDiff EventQos::parse_diff() const
{
  GstClockTimeDiff gst_diff = 0;
  gst_event_parse_qos(const_cast<GstEvent*>(gobj()), 0, 0, &gst_diff, 0);
  return gst_diff;
}

Gst::ClockTime EventQos::parse_timestamp() const
{
  GstClockTime gst_timestamp = 0;
  gst_event_parse_qos(const_cast<GstEvent*>(gobj()), 0, 0, 0, &gst_timestamp);
  return gst_timestamp;
}

Glib::RefPtr<Gst::EventSeek> EventSeek::create(double rate, Format format,
  SeekFlags flags, SeekType start_type, gint64 start, SeekType stop_type,
  gint64 stop)
{
  GstEvent* event = gst_event_new_seek(rate, GstFormat(format),
    GstSeekFlags(flags), GstSeekType(start_type), start,
    GstSeekType(stop_type), stop);

  return Glib::wrap_event_derived<EventSeek>(event, false);
}

void EventSeek::parse(double& rate, Format& format, SeekFlags& flags,
  SeekType& start_type, gint64& start, SeekType& stop_type, gint64& stop) const
{
  gst_event_parse_seek(const_cast<GstEvent*>(gobj()), &rate,
    (GstFormat*)&format, (GstSeekFlags*)&flags, (GstSeekType*)&start_type,
    &start, (GstSeekType*)&stop_type, &stop);
}

gint64 EventSeek::parse() const
{
  gint64 gst_start = 0;
  gst_event_parse_seek(const_cast<GstEvent*>(gobj()), 0, 0, 0, 0, &gst_start,
    0, 0);
  return gst_start;
}

double EventSeek::parse_rate() const
{
  double gst_rate = 0;
  gst_event_parse_seek(const_cast<GstEvent*>(gobj()), &gst_rate, 0, 0, 0, 0,
    0, 0);
  return gst_rate;
}

Gst::Format EventSeek::parse_format() const
{
  GstFormat gst_format = GST_FORMAT_UNDEFINED;
  gst_event_parse_seek(const_cast<GstEvent*>(gobj()), 0, &gst_format, 0, 0, 0,
    0, 0);
  return static_cast<Gst::Format>(gst_format);
}

Gst::SeekFlags EventSeek::parse_flags() const
{
  GstSeekFlags gst_flags = GST_SEEK_FLAG_NONE;
  gst_event_parse_seek(const_cast<GstEvent*>(gobj()), 0, 0, &gst_flags, 0, 0,
    0, 0);
  return static_cast<Gst::SeekFlags>(gst_flags);
}

Gst::SeekType EventSeek::parse_start_type() const
{
  GstSeekType gst_type = GST_SEEK_TYPE_NONE;
  gst_event_parse_seek(const_cast<GstEvent*>(gobj()), 0, 0, 0, &gst_type, 0,
    0, 0);
  return static_cast<Gst::SeekType>(gst_type);
}

Gst::SeekType EventSeek::parse_stop_type() const
{
  GstSeekType gst_type = GST_SEEK_TYPE_NONE;
  gst_event_parse_seek(const_cast<GstEvent*>(gobj()), 0, 0, 0, 0, 0, &gst_type,
    0);
  return static_cast<Gst::SeekType>(gst_type);
}

gint64 EventSeek::parse_stop() const
{
  gint64 gst_stop = 0;
  gst_event_parse_seek(const_cast<GstEvent*>(gobj()), 0, 0, 0, 0, 0, 0,
    &gst_stop);
  return gst_stop;
}

Glib::RefPtr<Gst::EventNavigation>
  EventNavigation::create(Gst::Structure& structure)
{
  // Make copy because event takes ownership of structure:
  GstStructure* copy = gst_structure_copy(structure.gobj());
  GstEvent* event = gst_event_new_navigation(copy);
  return Glib::wrap_event_derived<EventNavigation>(event, false);
}

Glib::RefPtr<Gst::EventLatency> EventLatency::create(ClockTime time)
{
  GstEvent* event = gst_event_new_latency(GstClockTime(time));
  return Glib::wrap_event_derived<EventLatency>(event, false);
}

ClockTime EventLatency::parse() const
{
  GstClockTime gst_latency = 0;
  gst_event_parse_latency(const_cast<GstEvent*>(gobj()), &gst_latency);
  return gst_latency;
}

Glib::RefPtr<Gst::EventStep>
  EventStep::create(Gst::Format format, guint64 amount, double rate,
  bool flush, bool intermediate)
{
  GstEvent* event = gst_event_new_step(static_cast<GstFormat>(format),
    amount, rate, flush, intermediate);
  return Glib::wrap_event_derived<EventStep>(event, false);
}

void EventStep::parse(Gst::Format& format, guint64& amount, double& rate,
  bool& flush, bool& intermediate) const
{
  gboolean gst_flush = FALSE;
  gboolean gst_intermediate = FALSE;

  gst_event_parse_step(const_cast<GstEvent*>(gobj()),
    reinterpret_cast<GstFormat*>(&format), &amount, &rate, &gst_flush,
    &gst_intermediate);

  flush = gst_flush;
  intermediate = gst_intermediate;
}

guint64 EventStep::parse() const
{
  guint64 gst_amount = 0;
  gst_event_parse_step(const_cast<GstEvent*>(gobj()), 0, &gst_amount, 0, 0, 0);
  return gst_amount;
}

Gst::Format EventStep::parse_format() const
{
  GstFormat gst_format = GST_FORMAT_UNDEFINED;
  gst_event_parse_step(const_cast<GstEvent*>(gobj()), &gst_format, 0, 0, 0, 0);
  return static_cast<Gst::Format>(gst_format);
}

double EventStep::parse_rate() const
{
  double gst_rate = 0;
  gst_event_parse_step(const_cast<GstEvent*>(gobj()), 0, 0, &gst_rate, 0, 0);
  return gst_rate;
}

bool EventStep::parse_flush() const
{
  gboolean gst_flush = FALSE;
  gst_event_parse_step(const_cast<GstEvent*>(gobj()), 0, 0, 0, &gst_flush, 0);
  return gst_flush;
}

bool EventStep::parse_intermediate() const
{
  gboolean gst_intermediate = FALSE;
  gst_event_parse_step(const_cast<GstEvent*>(gobj()), 0, 0, 0, 0,
    &gst_intermediate);
  return gst_intermediate;
}

Glib::RefPtr<Gst::EventSinkMessage>
  EventSinkMessage::create(const Glib::ustring& name, const Glib::RefPtr<Gst::Message>& msg)
{
  GstEvent* event = gst_event_new_sink_message(name.c_str(), msg->gobj());
  return Glib::wrap_event_derived<EventSinkMessage>(event, false);
}

Glib::RefPtr<Gst::Message> EventSinkMessage::parse()
{
  GstMessage* gst_msg = 0;
  gst_event_parse_sink_message(gobj(), &gst_msg);
  return Glib::wrap(gst_msg);
}

Glib::RefPtr<const Gst::Message> EventSinkMessage::parse() const
{
  GstMessage* gst_msg = 0;
  gst_event_parse_sink_message(const_cast<GstEvent*>(gobj()), &gst_msg);
  return Glib::wrap(gst_msg);
}

Glib::RefPtr<Gst::EventStreamStart>
EventStreamStart::create(const Glib::ustring& stream_id)
{
  GstEvent* event = gst_event_new_stream_start(stream_id.c_str());
  return Glib::wrap_event_derived<EventStreamStart>(event, false);
}

Glib::RefPtr<Gst::EventCaps>
EventCaps::create(const Glib::RefPtr<Gst::Caps>& caps)
{
  GstEvent* event = gst_event_new_caps(caps->gobj());
  return Glib::wrap_event_derived<EventCaps>(event, false);
}

Glib::RefPtr<Gst::Caps> EventCaps::parse()
{
  GstCaps* gst_caps = 0;
  gst_event_parse_caps(gobj(), &gst_caps);
  return Glib::wrap(gst_caps, true);
}

} //namespace Gst
