/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */

/*
 *  Copyright (C) 2003 Hiroyuki Ikezoe
 *  Copyright (C) 2003 Takuro Ashie
 *
 *  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, 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.
 */

#include <glib/gi18n.h>
#include "gobject-utils.h"
#include "kz-downloader-group.h"

enum {
	ADD_SIGNAL,
	REMOVE_SIGNAL,
	ERROR_SIGNAL,
	PROGRESS_SIGNAL,
	LAST_SIGNAL
};


KzDownloaderGroup *dlgrp_single = NULL;

static void kz_downloader_group_class_init (KzDownloaderGroupClass *klass);
static void kz_downloader_group_init       (KzDownloaderGroup      *dlgrp);

static void connect_signals                (KzDownloaderGroup *dlgrp,
					    KzDownloader      *dl);
static void disconnect_signals             (KzDownloaderGroup *dlgrp,
					    KzDownloader      *dl);

static void cb_download_complete (KzDownloader *dl, KzDownloaderGroup *dlgrp);
static void cb_download_error    (KzDownloader *dl, KzDownloaderGroup *dlgrp);
static void cb_download_progress (KzDownloader *dl, KzDownloaderGroup *dlgrp);

static GObjectClass *parent_class = NULL;
static gint kz_downloader_group_signals[LAST_SIGNAL] = {0};


KZ_OBJECT_GET_TYPE(kz_downloader_group, "KzDownloaderGroup", KzDownloaderGroup,
		   kz_downloader_group_class_init, kz_downloader_group_init,
		   G_TYPE_OBJECT)

static void
kz_downloader_group_class_init (KzDownloaderGroupClass *klass)
{
	GObjectClass *gobject_class;

	parent_class = g_type_class_peek_parent (klass);

	gobject_class = (GObjectClass *) klass;

	/* GObject class */
	gobject_class->dispose = kz_downloader_group_dispose;

	klass->add       = NULL;
	klass->remove    = NULL;
	klass->error     = NULL;
	klass->progress  = NULL;

	kz_downloader_group_signals[ADD_SIGNAL]
		= g_signal_new ("add",
				G_TYPE_FROM_CLASS (klass),
				G_SIGNAL_RUN_LAST,
				G_STRUCT_OFFSET (KzDownloaderGroupClass, add),
				NULL, NULL,
				g_cclosure_marshal_VOID__OBJECT,
				G_TYPE_NONE, 1,
				KZ_TYPE_DOWNLOADER);
	kz_downloader_group_signals[REMOVE_SIGNAL]
		= g_signal_new ("remove",
				G_TYPE_FROM_CLASS (klass),
				G_SIGNAL_RUN_LAST,
				G_STRUCT_OFFSET (KzDownloaderGroupClass, remove),
				NULL, NULL,
				g_cclosure_marshal_VOID__OBJECT,
				G_TYPE_NONE, 1,
				KZ_TYPE_DOWNLOADER);
	kz_downloader_group_signals[ERROR_SIGNAL]
		= g_signal_new ("error",
				G_TYPE_FROM_CLASS (klass),
				G_SIGNAL_RUN_LAST,
				G_STRUCT_OFFSET (KzDownloaderGroupClass, error),
				NULL, NULL,
				g_cclosure_marshal_VOID__OBJECT,
				G_TYPE_NONE, 1,
				KZ_TYPE_DOWNLOADER);
	kz_downloader_group_signals[PROGRESS_SIGNAL]
		= g_signal_new ("progress",
				G_TYPE_FROM_CLASS (klass),
				G_SIGNAL_RUN_LAST,
				G_STRUCT_OFFSET (KzDownloaderGroupClass, progress),
				NULL, NULL,
				g_cclosure_marshal_VOID__OBJECT,
				G_TYPE_NONE, 1,
				KZ_TYPE_DOWNLOADER);
}


static void
kz_downloader_group_init (KzDownloaderGroup *dlgrp)
{
	dlgrp->items = NULL;
}


void
kz_downloader_group_dispose (GObject *object)
{
	KzDownloaderGroup *dlgrp = KZ_DOWNLOADER_GROUP(object);

	if (dlgrp->items)
	{
		g_slist_free(dlgrp->items);
		dlgrp->items = NULL;
	}

	if (dlgrp_single && dlgrp_single == dlgrp)
	{
		dlgrp_single = NULL;
	}

	if (G_OBJECT_CLASS (parent_class)->dispose)
		G_OBJECT_CLASS (parent_class)->dispose(object);
}


KzDownloaderGroup *
kz_downloader_group_new (void)
{
	KzDownloaderGroup *dlgrp = KZ_DOWNLOADER_GROUP(g_object_new(KZ_TYPE_DOWNLOADER_GROUP, NULL));

	return dlgrp;
}


KzDownloaderGroup *
kz_downloader_group_get_instance (void)
{
	if (!dlgrp_single)
		dlgrp_single = kz_downloader_group_new();
	else
		g_object_ref(dlgrp_single);

	return dlgrp_single;
}


static void
disconnect_signals(KzDownloaderGroup *dlgrp, KzDownloader *dl)
{
	g_signal_handlers_disconnect_by_func(G_OBJECT(dl),
					     G_CALLBACK(cb_download_complete),
					     dlgrp);
	g_signal_handlers_disconnect_by_func(G_OBJECT(dl),
					     G_CALLBACK(cb_download_error),
					     dlgrp);
	g_signal_handlers_disconnect_by_func(G_OBJECT(dl),
					     G_CALLBACK(cb_download_progress),
					     dlgrp);
}


static void
connect_signals (KzDownloaderGroup *dlgrp, KzDownloader *dl)
{
	/* connect signals */
	g_signal_connect(G_OBJECT(dl), "completed",
			 G_CALLBACK(cb_download_complete), dlgrp);
	g_signal_connect(G_OBJECT(dl), "error",
			 G_CALLBACK(cb_download_error), dlgrp);	
	g_signal_connect(G_OBJECT(dl), "io_in",
			 G_CALLBACK(cb_download_progress), dlgrp);	

	g_signal_emit(G_OBJECT (dlgrp),
		      kz_downloader_group_signals[ADD_SIGNAL],
		      0, dl);
}


static void
cb_download_complete (KzDownloader *dl, KzDownloaderGroup *dlgrp)
{
	g_return_if_fail(KZ_IS_DOWNLOADER_GROUP(dlgrp));
	g_return_if_fail(KZ_IS_DOWNLOADER(dl));

	disconnect_signals(dlgrp, dl);

	kz_downloader_group_remove_item(dlgrp, dl);
}


static void
cb_download_error (KzDownloader *dl, KzDownloaderGroup *dlgrp)
{
	g_return_if_fail(KZ_IS_DOWNLOADER_GROUP(dlgrp));
	g_return_if_fail(KZ_IS_DOWNLOADER(dl));

	disconnect_signals(dlgrp, dl);

	kz_downloader_group_remove_item(dlgrp, dl);
}


static void
cb_download_progress (KzDownloader *dl, KzDownloaderGroup *dlgrp)
{
	g_return_if_fail(KZ_IS_DOWNLOADER_GROUP(dlgrp));
	g_return_if_fail(KZ_IS_DOWNLOADER(dl));

	g_signal_emit(G_OBJECT (dlgrp),
		      kz_downloader_group_signals[PROGRESS_SIGNAL],
		      0, dl);
}


void
kz_downloader_group_add_item (KzDownloaderGroup *dlgrp,
			      const gchar *uri)
{
	KzDownloader *dl;
	gchar *basename;

	g_return_if_fail(KZ_IS_DOWNLOADER_GROUP(dlgrp));
	g_return_if_fail(uri);

	basename = g_path_get_basename(uri);
	dl = kz_downloader_new_with_filename(uri, basename);
	if (!dl)
		return;

	dlgrp->items = g_slist_append(dlgrp->items, dl);
	connect_signals(dlgrp, dl);
	
	kz_downloader_to_file(dl);

	g_free(basename);
}


void
kz_downloader_group_add_item_with_filename (KzDownloaderGroup *dlgrp,
			      		    const gchar *uri,
					    const gchar *filename)
{
	KzDownloader *dl;

	g_return_if_fail(KZ_IS_DOWNLOADER_GROUP(dlgrp));
	g_return_if_fail(uri);

	dl = kz_downloader_new_with_filename(uri, filename);
	if (!dl)
		return;

	dlgrp->items = g_slist_append(dlgrp->items, dl);
	connect_signals(dlgrp, dl);
	
	kz_downloader_to_file(dl);
}


void
kz_downloader_group_add_downloader (KzDownloaderGroup *dlgrp,
				    KzDownloader *dl)
{
	g_return_if_fail(KZ_IS_DOWNLOADER_GROUP(dlgrp));
	g_return_if_fail(KZ_IS_DOWNLOADER(dl));

	g_object_ref(G_OBJECT(dl));
	dlgrp->items = g_slist_append(dlgrp->items, KZ_DOWNLOADER(dl));

	connect_signals(dlgrp, KZ_DOWNLOADER(dl));
}


static gboolean
idle_remove_item(gpointer data)
{
	KzDownloader *dl = data;

	g_object_unref(G_OBJECT(dl));

	return FALSE;
}


void
kz_downloader_group_remove_item (KzDownloaderGroup *dlgrp, KzDownloader *dl)
{
	g_return_if_fail(KZ_IS_DOWNLOADER_GROUP(dlgrp));
	g_return_if_fail(KZ_IS_DOWNLOADER(dl));
	g_signal_emit(G_OBJECT (dlgrp),
		      kz_downloader_group_signals[REMOVE_SIGNAL],
		      0, dl);
	dlgrp->items = g_slist_remove(dlgrp->items, dl);
	g_idle_add(idle_remove_item, dl);
}
