/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/* camel-stream-data-wrapper.c
 *
 * Copyright 1999, 2000 HelixCode (http://www.helixcode.com)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program 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
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 * Author: Ettore Perazzoli
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <gtk/gtk.h>

#include "camel-stream-data-wrapper.h"


static CamelDataWrapperClass *parent_class = NULL;


/* CamelDataWrapper methods.  */

static void
write_to_stream (CamelDataWrapper *data_wrapper,
		 CamelStream *output_stream)
{
#define BUFFER_SIZE 4096
	gchar buffer[BUFFER_SIZE];
	CamelStreamDataWrapper *stream_data_wrapper;
	CamelStream *input_stream;

	stream_data_wrapper = CAMEL_STREAM_DATA_WRAPPER (data_wrapper);
	input_stream = stream_data_wrapper->stream;

	while (TRUE) {
		gchar *p;
		gint read, written;

		read = camel_stream_read (input_stream, buffer, BUFFER_SIZE);
		if (read == 0)
			break;

		p = buffer;
		while (read > 0) {
			written = camel_stream_write (output_stream, p, read);

			/* FIXME no way to report an error?!  */
			if (written == -1)
				break;

			p += written;
			read -= written;
		}
	}
#undef BUFFER_SIZE
}

static CamelStream *
get_stream (CamelDataWrapper *data_wrapper)
{
	CamelStreamDataWrapper *stream_data_wrapper;

	stream_data_wrapper = CAMEL_STREAM_DATA_WRAPPER (data_wrapper);
	return stream_data_wrapper->stream;
}


/* GtkObject methods.  */

static void
destroy (GtkObject *object)
{
	CamelStreamDataWrapper *stream_data_wrapper;
	GtkObject *stream_object;

	stream_data_wrapper = CAMEL_STREAM_DATA_WRAPPER (object);

	stream_object = GTK_OBJECT (object);
	stream_data_wrapper->stream = NULL;

	gtk_object_unref (stream_object);
}


/* This handles destruction of the associated CamelDataWrapper outside
   CamelStreamDataWrapper, for debuggin purposes (this should never happen).  */
static void
stream_destroy_cb (GtkObject *object,
		   gpointer data)
{
	CamelStreamDataWrapper *wrapper;

	wrapper = CAMEL_STREAM_DATA_WRAPPER (data);

	/* Hack: when we destroy the stream ourselves, we set the `stream'
           member to NULL first, so that we can recognize when this is done out
           of our control.  */
	if (wrapper->stream != NULL) {
		g_warning ("CamelSimpleDataWrapperStream: associated CamelSimpleDataWrapper was destroyed.");
		wrapper->stream = NULL;
	}
}


static void
class_init (CamelStreamDataWrapperClass *class)
{
	GtkObjectClass *object_class;
	CamelDataWrapperClass *data_wrapper_class;

	object_class = GTK_OBJECT_CLASS (class);
	object_class->destroy = destroy;

	data_wrapper_class = CAMEL_DATA_WRAPPER_CLASS (class);
	data_wrapper_class->write_to_stream = write_to_stream;
	data_wrapper_class->get_stream = get_stream;

	parent_class = gtk_type_class (camel_data_wrapper_get_type ());
}

static void
init (CamelStreamDataWrapper *wrapper)
{
	wrapper->stream = NULL;
}


GtkType
camel_stream_data_wrapper_get_type (void)
{
	static GtkType type = 0;

	if (type == 0) {
		static const GtkTypeInfo info = {
			"CamelStreamDataWrapper",
			sizeof (CamelStreamDataWrapper),
			sizeof (CamelStreamDataWrapperClass),
			(GtkClassInitFunc) class_init,
			(GtkObjectInitFunc) init,
			/* reserved_1 */ NULL,
			/* reserved_2 */ NULL,
			(GtkClassInitFunc) NULL,
		};

		type = gtk_type_unique (camel_data_wrapper_get_type (), &info);
	}

	return type;
}

/**
 * camel_stream_data_wrapper_construct:
 * @wrapper: A CamelStreamDataWrapper object
 * @stream: A Camel stream object
 * 
 * Construct @wrapper associating @stream to it.  Notice that, after this call,
 * @stream is conceptually owned by @wrapper and will be destroyed when
 * @wrapper is destroyed.
 **/
void
camel_stream_data_wrapper_construct (CamelStreamDataWrapper *wrapper,
				     CamelStream *stream)
{
	g_return_if_fail (wrapper != NULL);
	g_return_if_fail (CAMEL_IS_STREAM_DATA_WRAPPER (wrapper));
	g_return_if_fail (stream != NULL);
	g_return_if_fail (CAMEL_IS_STREAM (stream));

	wrapper->stream = stream;
	gtk_signal_connect (GTK_OBJECT (stream), "destroy",
			    GTK_SIGNAL_FUNC (stream_destroy_cb), wrapper);
}

/**
 * camel_stream_data_wrapper_new:
 * @stream: A Camel stream object
 * 
 * Create a new stream data wrapper object for @stream.  Notice that, after
 * this call, @stream is conceptually owned by the new wrapper and will be
 * destroyed when the wrapper is destroyed.
 * 
 * Return value: A pointer to the new CamelStreamDataWrapper object.
 **/
CamelDataWrapper *
camel_stream_data_wrapper_new (CamelStream *stream)
{
	CamelDataWrapper *wrapper;

	wrapper = gtk_type_new (camel_stream_data_wrapper_get_type ());
	camel_stream_data_wrapper_construct
		(CAMEL_STREAM_DATA_WRAPPER (wrapper), stream);

	return wrapper;
}