/* rygel-data-sink.c generated by valac 0.44.9, the Vala compiler
 * generated from rygel-data-sink.vala, do not modify */

/*
 * Copyright (C) 2012 Intel Corporation.
 * Copyright (C) 2013 Cable Television Laboratories, Inc.
 *
 * Author: Jens Georg <jensg@openismus.com>
 *         Craig Pratt <craig@ecaspia.com>
 *
 * This file is part of Rygel.
 *
 * Rygel 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.
 *
 * Rygel 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <glib-object.h>
#include <gee.h>
#include <glib.h>
#include <libsoup/soup.h>
#include <stdlib.h>
#include <string.h>

#define RYGEL_TYPE_DATA_SINK (rygel_data_sink_get_type ())
#define RYGEL_DATA_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), RYGEL_TYPE_DATA_SINK, RygelDataSink))
#define RYGEL_DATA_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), RYGEL_TYPE_DATA_SINK, RygelDataSinkClass))
#define RYGEL_IS_DATA_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), RYGEL_TYPE_DATA_SINK))
#define RYGEL_IS_DATA_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), RYGEL_TYPE_DATA_SINK))
#define RYGEL_DATA_SINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), RYGEL_TYPE_DATA_SINK, RygelDataSinkClass))

typedef struct _RygelDataSink RygelDataSink;
typedef struct _RygelDataSinkClass RygelDataSinkClass;
typedef struct _RygelDataSinkPrivate RygelDataSinkPrivate;

#define RYGEL_TYPE_DATA_SOURCE (rygel_data_source_get_type ())
#define RYGEL_DATA_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), RYGEL_TYPE_DATA_SOURCE, RygelDataSource))
#define RYGEL_IS_DATA_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), RYGEL_TYPE_DATA_SOURCE))
#define RYGEL_DATA_SOURCE_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), RYGEL_TYPE_DATA_SOURCE, RygelDataSourceIface))

typedef struct _RygelDataSource RygelDataSource;
typedef struct _RygelDataSourceIface RygelDataSourceIface;

#define RYGEL_TYPE_HTTP_SEEK_REQUEST (rygel_http_seek_request_get_type ())
#define RYGEL_HTTP_SEEK_REQUEST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), RYGEL_TYPE_HTTP_SEEK_REQUEST, RygelHTTPSeekRequest))
#define RYGEL_HTTP_SEEK_REQUEST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), RYGEL_TYPE_HTTP_SEEK_REQUEST, RygelHTTPSeekRequestClass))
#define RYGEL_IS_HTTP_SEEK_REQUEST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), RYGEL_TYPE_HTTP_SEEK_REQUEST))
#define RYGEL_IS_HTTP_SEEK_REQUEST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), RYGEL_TYPE_HTTP_SEEK_REQUEST))
#define RYGEL_HTTP_SEEK_REQUEST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), RYGEL_TYPE_HTTP_SEEK_REQUEST, RygelHTTPSeekRequestClass))

typedef struct _RygelHTTPSeekRequest RygelHTTPSeekRequest;
typedef struct _RygelHTTPSeekRequestClass RygelHTTPSeekRequestClass;

#define RYGEL_TYPE_PLAY_SPEED_REQUEST (rygel_play_speed_request_get_type ())
#define RYGEL_PLAY_SPEED_REQUEST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), RYGEL_TYPE_PLAY_SPEED_REQUEST, RygelPlaySpeedRequest))
#define RYGEL_PLAY_SPEED_REQUEST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), RYGEL_TYPE_PLAY_SPEED_REQUEST, RygelPlaySpeedRequestClass))
#define RYGEL_IS_PLAY_SPEED_REQUEST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), RYGEL_TYPE_PLAY_SPEED_REQUEST))
#define RYGEL_IS_PLAY_SPEED_REQUEST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), RYGEL_TYPE_PLAY_SPEED_REQUEST))
#define RYGEL_PLAY_SPEED_REQUEST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), RYGEL_TYPE_PLAY_SPEED_REQUEST, RygelPlaySpeedRequestClass))

typedef struct _RygelPlaySpeedRequest RygelPlaySpeedRequest;
typedef struct _RygelPlaySpeedRequestClass RygelPlaySpeedRequestClass;

#define RYGEL_TYPE_HTTP_RESPONSE_ELEMENT (rygel_http_response_element_get_type ())
#define RYGEL_HTTP_RESPONSE_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), RYGEL_TYPE_HTTP_RESPONSE_ELEMENT, RygelHTTPResponseElement))
#define RYGEL_HTTP_RESPONSE_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), RYGEL_TYPE_HTTP_RESPONSE_ELEMENT, RygelHTTPResponseElementClass))
#define RYGEL_IS_HTTP_RESPONSE_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), RYGEL_TYPE_HTTP_RESPONSE_ELEMENT))
#define RYGEL_IS_HTTP_RESPONSE_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), RYGEL_TYPE_HTTP_RESPONSE_ELEMENT))
#define RYGEL_HTTP_RESPONSE_ELEMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), RYGEL_TYPE_HTTP_RESPONSE_ELEMENT, RygelHTTPResponseElementClass))

typedef struct _RygelHTTPResponseElement RygelHTTPResponseElement;
typedef struct _RygelHTTPResponseElementClass RygelHTTPResponseElementClass;
enum  {
	RYGEL_DATA_SINK_0_PROPERTY,
	RYGEL_DATA_SINK_NUM_PROPERTIES
};
static GParamSpec* rygel_data_sink_properties[RYGEL_DATA_SINK_NUM_PROPERTIES];
#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL)))
#define _g_free0(var) (var = (g_free (var), NULL))

#define RYGEL_TYPE_HTTP_BYTE_SEEK_REQUEST (rygel_http_byte_seek_request_get_type ())
#define RYGEL_HTTP_BYTE_SEEK_REQUEST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), RYGEL_TYPE_HTTP_BYTE_SEEK_REQUEST, RygelHTTPByteSeekRequest))
#define RYGEL_HTTP_BYTE_SEEK_REQUEST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), RYGEL_TYPE_HTTP_BYTE_SEEK_REQUEST, RygelHTTPByteSeekRequestClass))
#define RYGEL_IS_HTTP_BYTE_SEEK_REQUEST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), RYGEL_TYPE_HTTP_BYTE_SEEK_REQUEST))
#define RYGEL_IS_HTTP_BYTE_SEEK_REQUEST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), RYGEL_TYPE_HTTP_BYTE_SEEK_REQUEST))
#define RYGEL_HTTP_BYTE_SEEK_REQUEST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), RYGEL_TYPE_HTTP_BYTE_SEEK_REQUEST, RygelHTTPByteSeekRequestClass))

typedef struct _RygelHTTPByteSeekRequest RygelHTTPByteSeekRequest;
typedef struct _RygelHTTPByteSeekRequestClass RygelHTTPByteSeekRequestClass;

struct _RygelDataSink {
	GObject parent_instance;
	RygelDataSinkPrivate * priv;
};

struct _RygelDataSinkClass {
	GObjectClass parent_class;
};

struct _RygelDataSourceIface {
	GTypeInterface parent_iface;
	GeeList* (*preroll) (RygelDataSource* self, RygelHTTPSeekRequest* seek, RygelPlaySpeedRequest* playspeed, GError** error);
	void (*start) (RygelDataSource* self, GError** error);
	void (*freeze) (RygelDataSource* self);
	void (*thaw) (RygelDataSource* self);
	void (*stop) (RygelDataSource* self);
};

struct _RygelDataSinkPrivate {
	RygelDataSource* source;
	SoupServer* server;
	SoupMessage* message;
	gint64 chunks_buffered;
	gint64 bytes_sent;
	gint64 max_bytes;
};

static gint RygelDataSink_private_offset;
static gpointer rygel_data_sink_parent_class = NULL;

GType rygel_data_sink_get_type (void) G_GNUC_CONST;
G_DEFINE_AUTOPTR_CLEANUP_FUNC (RygelDataSink, g_object_unref)
GType rygel_http_seek_request_get_type (void) G_GNUC_CONST;
G_DEFINE_AUTOPTR_CLEANUP_FUNC (RygelHTTPSeekRequest, g_object_unref)
GType rygel_play_speed_request_get_type (void) G_GNUC_CONST;
G_DEFINE_AUTOPTR_CLEANUP_FUNC (RygelPlaySpeedRequest, g_object_unref)
GType rygel_http_response_element_get_type (void) G_GNUC_CONST;
G_DEFINE_AUTOPTR_CLEANUP_FUNC (RygelHTTPResponseElement, g_object_unref)
GType rygel_data_source_get_type (void) G_GNUC_CONST;
#define RYGEL_DATA_SINK_MAX_BUFFERED_CHUNKS ((guint) 32)
#define RYGEL_DATA_SINK_MIN_BUFFERED_CHUNKS ((guint) 4)
RygelDataSink* rygel_data_sink_new (RygelDataSource* source,
                                    SoupServer* server,
                                    SoupMessage* message,
                                    RygelHTTPSeekRequest* offsets);
RygelDataSink* rygel_data_sink_construct (GType object_type,
                                          RygelDataSource* source,
                                          SoupServer* server,
                                          SoupMessage* message,
                                          RygelHTTPSeekRequest* offsets);
static gint64 rygel_data_sink_get_max_bytes (RygelDataSink* self,
                                      RygelHTTPSeekRequest* offsets);
static void rygel_data_sink_on_data_available (RygelDataSink* self,
                                        guint8* buffer,
                                        gint buffer_length1);
static void _rygel_data_sink_on_data_available_rygel_data_source_data_available (RygelDataSource* _sender,
                                                                          guint8* data,
                                                                          gint data_length1,
                                                                          gpointer self);
static void rygel_data_sink_on_wrote_chunk (RygelDataSink* self,
                                     SoupMessage* msg);
static void _rygel_data_sink_on_wrote_chunk_soup_message_wrote_chunk (SoupMessage* _sender,
                                                               gpointer self);
void rygel_data_source_thaw (RygelDataSource* self);
static guint8* _vala_array_dup6 (guint8* self,
                          int length);
void rygel_data_source_freeze (RygelDataSource* self);
GType rygel_http_byte_seek_request_get_type (void) G_GNUC_CONST;
G_DEFINE_AUTOPTR_CLEANUP_FUNC (RygelHTTPByteSeekRequest, g_object_unref)
gint64 rygel_http_byte_seek_request_get_range_length (RygelHTTPByteSeekRequest* self);
static void rygel_data_sink_finalize (GObject * obj);

static inline gpointer
rygel_data_sink_get_instance_private (RygelDataSink* self)
{
	return G_STRUCT_MEMBER_P (self, RygelDataSink_private_offset);
}

static gpointer
_g_object_ref0 (gpointer self)
{
	return self ? g_object_ref (self) : NULL;
}

static void
_rygel_data_sink_on_data_available_rygel_data_source_data_available (RygelDataSource* _sender,
                                                                     guint8* data,
                                                                     gint data_length1,
                                                                     gpointer self)
{
	rygel_data_sink_on_data_available ((RygelDataSink*) self, data, data_length1);
}

static void
_rygel_data_sink_on_wrote_chunk_soup_message_wrote_chunk (SoupMessage* _sender,
                                                          gpointer self)
{
	rygel_data_sink_on_wrote_chunk ((RygelDataSink*) self, _sender);
}

RygelDataSink*
rygel_data_sink_construct (GType object_type,
                           RygelDataSource* source,
                           SoupServer* server,
                           SoupMessage* message,
                           RygelHTTPSeekRequest* offsets)
{
	RygelDataSink * self = NULL;
	RygelDataSource* _tmp0_;
	SoupServer* _tmp1_;
	SoupMessage* _tmp2_;
	gchar* _tmp3_ = NULL;
	RygelDataSource* _tmp6_;
	SoupMessage* _tmp7_;
	g_return_val_if_fail (source != NULL, NULL);
	g_return_val_if_fail (server != NULL, NULL);
	g_return_val_if_fail (message != NULL, NULL);
	self = (RygelDataSink*) g_object_new (object_type, NULL);
	_tmp0_ = _g_object_ref0 (source);
	_g_object_unref0 (self->priv->source);
	self->priv->source = _tmp0_;
	_tmp1_ = _g_object_ref0 (server);
	_g_object_unref0 (self->priv->server);
	self->priv->server = _tmp1_;
	_tmp2_ = _g_object_ref0 (message);
	_g_object_unref0 (self->priv->message);
	self->priv->message = _tmp2_;
	self->priv->chunks_buffered = (gint64) 0;
	self->priv->bytes_sent = (gint64) 0;
	self->priv->max_bytes = rygel_data_sink_get_max_bytes (self, offsets);
	if (self->priv->max_bytes == G_MAXINT64) {
		gchar* _tmp4_;
		_tmp4_ = g_strdup ("MAX");
		_g_free0 (_tmp3_);
		_tmp3_ = _tmp4_;
	} else {
		gchar* _tmp5_;
		_tmp5_ = g_strdup_printf ("%" G_GINT64_FORMAT, self->priv->max_bytes);
		_g_free0 (_tmp3_);
		_tmp3_ = _tmp5_;
	}
	g_debug ("rygel-data-sink.vala:53: Setting max_bytes to %s", _tmp3_);
	_tmp6_ = self->priv->source;
	g_signal_connect_object (_tmp6_, "data-available", (GCallback) _rygel_data_sink_on_data_available_rygel_data_source_data_available, self, 0);
	_tmp7_ = self->priv->message;
	g_signal_connect_object (_tmp7_, "wrote-chunk", (GCallback) _rygel_data_sink_on_wrote_chunk_soup_message_wrote_chunk, self, 0);
	_g_free0 (_tmp3_);
	return self;
}

RygelDataSink*
rygel_data_sink_new (RygelDataSource* source,
                     SoupServer* server,
                     SoupMessage* message,
                     RygelHTTPSeekRequest* offsets)
{
	return rygel_data_sink_construct (RYGEL_TYPE_DATA_SINK, source, server, message, offsets);
}

static void
rygel_data_sink_on_wrote_chunk (RygelDataSink* self,
                                SoupMessage* msg)
{
	gint64 _tmp0_;
	g_return_if_fail (self != NULL);
	g_return_if_fail (msg != NULL);
	_tmp0_ = self->priv->chunks_buffered;
	self->priv->chunks_buffered = _tmp0_ - 1;
	if (self->priv->chunks_buffered < ((gint64) RYGEL_DATA_SINK_MIN_BUFFERED_CHUNKS)) {
		RygelDataSource* _tmp1_;
		_tmp1_ = self->priv->source;
		rygel_data_source_thaw (_tmp1_);
	}
}

static guint8*
_vala_array_dup6 (guint8* self,
                  int length)
{
	return g_memdup (self, length * sizeof (guint8));
}

static void
rygel_data_sink_on_data_available (RygelDataSink* self,
                                   guint8* buffer,
                                   gint buffer_length1)
{
	gint64 left = 0LL;
	gint64 to_send = 0LL;
	SoupMessage* _tmp0_;
	SoupMessageBody* _tmp1_;
	guint8* _tmp2_;
	gint _tmp2__length1;
	gint64 _tmp3_;
	SoupServer* _tmp4_;
	SoupMessage* _tmp5_;
	g_return_if_fail (self != NULL);
	left = self->priv->max_bytes - self->priv->bytes_sent;
	if (left <= ((gint64) 0)) {
		return;
	}
	to_send = MIN ((gint64) buffer_length1, left);
	_tmp0_ = self->priv->message;
	_tmp1_ = _tmp0_->response_body;
	_tmp2_ = ((buffer + 0) != NULL) ? _vala_array_dup6 (buffer + 0, ((gint) to_send) - 0) : ((gpointer) (buffer + 0));
	_tmp2__length1 = ((gint) to_send) - 0;
	soup_message_body_append_take (_tmp1_, _tmp2_, (gsize) _tmp2__length1);
	_tmp3_ = self->priv->chunks_buffered;
	self->priv->chunks_buffered = _tmp3_ + 1;
	self->priv->bytes_sent = self->priv->bytes_sent + to_send;
	_tmp4_ = self->priv->server;
	_tmp5_ = self->priv->message;
	soup_server_unpause_message (_tmp4_, _tmp5_);
	if (self->priv->chunks_buffered > ((gint64) RYGEL_DATA_SINK_MAX_BUFFERED_CHUNKS)) {
		RygelDataSource* _tmp6_;
		_tmp6_ = self->priv->source;
		rygel_data_source_freeze (_tmp6_);
	}
}

static gint64
rygel_data_sink_get_max_bytes (RygelDataSink* self,
                               RygelHTTPSeekRequest* offsets)
{
	gboolean _tmp0_ = FALSE;
	RygelHTTPByteSeekRequest* request = NULL;
	RygelHTTPByteSeekRequest* _tmp1_;
	RygelHTTPByteSeekRequest* _tmp2_;
	gint64 _tmp3_;
	gint64 _tmp4_;
	RygelHTTPByteSeekRequest* _tmp5_;
	gint64 _tmp6_;
	gint64 _tmp7_;
	RygelHTTPByteSeekRequest* _tmp8_;
	gint64 _tmp9_;
	gint64 _tmp10_;
	gint64 result = 0LL;
	g_return_val_if_fail (self != NULL, 0LL);
	if (offsets == NULL) {
		_tmp0_ = TRUE;
	} else {
		_tmp0_ = !RYGEL_IS_HTTP_BYTE_SEEK_REQUEST (offsets);
	}
	if (_tmp0_) {
		g_debug ("rygel-data-sink.vala:88: Setting max_bytes to MAX");
		result = G_MAXINT64;
		return result;
	}
	_tmp1_ = _g_object_ref0 (RYGEL_IS_HTTP_BYTE_SEEK_REQUEST (offsets) ? ((RygelHTTPByteSeekRequest*) offsets) : NULL);
	request = _tmp1_;
	_tmp2_ = request;
	_tmp3_ = rygel_http_byte_seek_request_get_range_length (_tmp2_);
	_tmp4_ = _tmp3_;
	if (_tmp4_ == ((gint64) -1)) {
		g_debug ("rygel-data-sink.vala:95: Setting max_bytes to MAX");
		result = G_MAXINT64;
		_g_object_unref0 (request);
		return result;
	}
	_tmp5_ = request;
	_tmp6_ = rygel_http_byte_seek_request_get_range_length (_tmp5_);
	_tmp7_ = _tmp6_;
	g_debug ("rygel-data-sink.vala:99: Setting max_bytes to %lld", _tmp7_);
	_tmp8_ = request;
	_tmp9_ = rygel_http_byte_seek_request_get_range_length (_tmp8_);
	_tmp10_ = _tmp9_;
	result = _tmp10_;
	_g_object_unref0 (request);
	return result;
}

static void
rygel_data_sink_class_init (RygelDataSinkClass * klass,
                            gpointer klass_data)
{
	rygel_data_sink_parent_class = g_type_class_peek_parent (klass);
	g_type_class_adjust_private_offset (klass, &RygelDataSink_private_offset);
	G_OBJECT_CLASS (klass)->finalize = rygel_data_sink_finalize;
}

static void
rygel_data_sink_instance_init (RygelDataSink * self,
                               gpointer klass)
{
	self->priv = rygel_data_sink_get_instance_private (self);
}

static void
rygel_data_sink_finalize (GObject * obj)
{
	RygelDataSink * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (obj, RYGEL_TYPE_DATA_SINK, RygelDataSink);
	_g_object_unref0 (self->priv->source);
	_g_object_unref0 (self->priv->server);
	_g_object_unref0 (self->priv->message);
	G_OBJECT_CLASS (rygel_data_sink_parent_class)->finalize (obj);
}

/**
 * Class that converts the push DataSource into the pull required by libsoup.
 */
GType
rygel_data_sink_get_type (void)
{
	static volatile gsize rygel_data_sink_type_id__volatile = 0;
	if (g_once_init_enter (&rygel_data_sink_type_id__volatile)) {
		static const GTypeInfo g_define_type_info = { sizeof (RygelDataSinkClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) rygel_data_sink_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (RygelDataSink), 0, (GInstanceInitFunc) rygel_data_sink_instance_init, NULL };
		GType rygel_data_sink_type_id;
		rygel_data_sink_type_id = g_type_register_static (G_TYPE_OBJECT, "RygelDataSink", &g_define_type_info, 0);
		RygelDataSink_private_offset = g_type_add_instance_private (rygel_data_sink_type_id, sizeof (RygelDataSinkPrivate));
		g_once_init_leave (&rygel_data_sink_type_id__volatile, rygel_data_sink_type_id);
	}
	return rygel_data_sink_type_id__volatile;
}

