/* gstreamermm - a C++ wrapper for gstreamer
 *
 * Copyright 2008-2016 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>
#include <gstreamermm/buffer.h>
#include <gstreamermm/toc.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());
}

bool EventFlushStop::parse_reset_time() const
{
  gboolean reset_time;
  gst_event_parse_flush_stop(const_cast<GstEvent*>(gobj()), &reset_time);
  return reset_time;
}

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

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_min_size() const
{
  gint64 gst_minsize = 0;
  gst_event_parse_buffer_size(const_cast<GstEvent*>(gobj()), 0, &gst_minsize,
    nullptr, nullptr);
  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;
}

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);
}

QOSType EventQos::parse_type() const
{
  GstQOSType type;
  gst_event_parse_qos(const_cast<GstEvent*>(gobj()), &type, nullptr, nullptr, nullptr);
  return static_cast<Gst::QOSType>(type);
}

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

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

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

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_start() const
{
  gint64 gst_start = 0;
  gst_event_parse_seek(const_cast<GstEvent*>(gobj()), nullptr, nullptr, nullptr, nullptr, &gst_start,
    nullptr, nullptr);
  return gst_start;
}

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

Gst::Format EventSeek::parse_format() const
{
  GstFormat gst_format = GST_FORMAT_UNDEFINED;
  gst_event_parse_seek(const_cast<GstEvent*>(gobj()), nullptr, &gst_format, nullptr, nullptr, nullptr,
    nullptr, nullptr);
  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()), nullptr, nullptr, &gst_flags, nullptr, nullptr,
    nullptr, nullptr);
  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()), nullptr, nullptr, nullptr, &gst_type, nullptr,
    nullptr, nullptr);
  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()), nullptr, nullptr, nullptr, nullptr, nullptr, &gst_type,
    nullptr);
  return static_cast<Gst::SeekType>(gst_type);
}

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

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

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_amount() const
{
  guint64 gst_amount = 0;
  gst_event_parse_step(const_cast<GstEvent*>(gobj()), nullptr, &gst_amount, nullptr, nullptr, nullptr);
  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, nullptr, nullptr, nullptr, nullptr);
  return static_cast<Gst::Format>(gst_format);
}

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

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

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

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

Glib::RefPtr<const Gst::Message> EventSinkMessage::parse_message() const
{
  return const_cast<Gst::EventSinkMessage*>(this)->parse_message();
}

void EventToc::parse(Glib::RefPtr<Gst::Toc>& toc, bool& updated)
{
  GstToc *gst_toc = nullptr;
  gboolean gst_updated;
  gst_event_parse_toc(gobj(), &gst_toc, &gst_updated);
  updated = gst_updated;
  toc = Glib::wrap(gst_toc);
}

void EventToc::parse(Glib::RefPtr<const Gst::Toc>& toc, bool& updated) const
{
  const_cast<EventToc*>(this)->parse(toc, updated);
}

Glib::RefPtr<Gst::Toc> EventToc::parse_toc()
{
  GstToc *gst_toc = nullptr;
  gst_event_parse_toc(gobj(), &gst_toc, nullptr);
  return Glib::wrap(gst_toc);
}

Glib::RefPtr<const Gst::Toc> EventToc::parse_toc() const
{
  return const_cast<EventToc*>(this)->parse_toc();
}

bool EventToc::parse_updated() const
{
  gboolean gst_updated;
  gst_event_parse_toc(const_cast<GstEvent*>(gobj()), nullptr, &gst_updated);
  return gst_updated;
}

void EventProtection::parse(Glib::ustring& system_id, Glib::RefPtr<Gst::Buffer>& data, Glib::ustring& origin) const
{
  const gchar *gst_system_id = nullptr, *gst_origin = nullptr;
  GstBuffer *gst_buffer;
  gst_event_parse_protection(const_cast<GstEvent*>(gobj()), &gst_system_id, &gst_buffer, &gst_origin);
  system_id = gst_system_id;
  data = Glib::wrap(gst_buffer, true);
  origin = gst_origin;
}

Glib::ustring EventProtection::parse_system_id() const
{
  const gchar *gst_system_id = nullptr;
  gst_event_parse_protection(const_cast<GstEvent*>(gobj()), &gst_system_id, nullptr, nullptr);
  return Glib::ustring(gst_system_id);
}

Glib::RefPtr<Gst::Buffer> EventProtection::parse_data()
{
  GstBuffer* gst_data = nullptr;
  gst_event_parse_protection(const_cast<GstEvent*>(gobj()), nullptr, &gst_data, nullptr);
  return Glib::wrap(gst_data, true);
}

Glib::RefPtr<const Gst::Buffer> EventProtection::parse_data() const
{
  return const_cast<EventProtection*>(this)->parse_data();
}

Glib::ustring EventProtection::parse_origin() const
{
  const gchar *gst_origin = nullptr;
  gst_event_parse_protection(const_cast<GstEvent*>(gobj()), nullptr, nullptr, &gst_origin);
  return Glib::ustring(gst_origin);
}

void EventSegmentDone::parse(Gst::Format& format, gint64& position) const
{
  GstFormat gst_format;
  gst_event_parse_segment_done(const_cast<GstEvent*>(gobj()), &gst_format, &position);
  format = static_cast<Gst::Format>(gst_format);
}

Gst::Format EventSegmentDone::parse_format() const
{
  GstFormat format;
  gst_event_parse_segment_done(const_cast<GstEvent*>(gobj()), &format, nullptr);
  return static_cast<Gst::Format>(format);
}

gint64 EventSegmentDone::parse_position() const
{
  gint64 position;
  gst_event_parse_segment_done(const_cast<GstEvent*>(gobj()), nullptr, &position);
  return position;
}

Gst::ClockTime EventGap::parse_timestamp() const
{
  GstClockTime timestamp;
  gst_event_parse_gap(const_cast<GstEvent*>(gobj()), &timestamp, nullptr);
  return timestamp;
}

Gst::ClockTime EventGap::parse_duration() const
{
  GstClockTime duration;
  gst_event_parse_gap(const_cast<GstEvent*>(gobj()), nullptr, &duration);
  return duration;
}

Glib::ustring EventStreamStart::parse_stream_id() const
{
  const gchar* gst_stream_id = nullptr;
  gst_event_parse_stream_start(const_cast<GstEvent*>(gobj()), &gst_stream_id);
  return Glib::ustring(gst_stream_id);
}

Gst::StreamFlags EventStreamStart::parse_stream_flags() const
{
  GstStreamFlags flags;
  gst_event_parse_stream_flags (const_cast<GstEvent*>(gobj()), &flags);
  return static_cast<Gst::StreamFlags>(flags);
}

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

Glib::RefPtr<const Gst::Caps> EventCaps::parse_caps() const
{
  return const_cast<EventCaps*>(this)->parse_caps();
}

Gst::Segment EventSegment::copy_segment() const
{
  const GstSegment *gst_segment;
  gst_event_parse_segment(const_cast<GstEvent*>(gobj()), &gst_segment);
  return Gst::Segment(const_cast<GstSegment*>(gst_segment), true);

}

Glib::ustring EventTocSelect::parse_uid() const
{
  gchar *gst_uid;
  gst_event_parse_toc_select(const_cast<GstEvent*>(gobj()), &gst_uid);
  Glib::ustring uid = gst_uid;
  g_free(gst_uid);
  return uid;
}


} //namespace Gst
