/* -*- 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 "gobject-utils.h"
#include "kz-downloader-group.h"
#include "intl.h"

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


KzDownloaderGrp *dlgrp_single = NULL;

static void kz_downloader_grp_class_init (KzDownloaderGrpClass *klass);
static void kz_downloader_grp_init       (KzDownloaderGrp      *dlgrp);

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

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


KZ_OBJECT_GET_TYPE(kz_downloader_grp, "KzDownloaderGrp", KzDownloaderGrp,
		   kz_downloader_grp_class_init, kz_downloader_grp_init,
		   G_TYPE_OBJECT)

static void
kz_downloader_grp_class_init (KzDownloaderGrpClass *klass)
{
	GObjectClass *gobject_class;

	parent_class = g_type_class_peek_parent (klass);

	gobject_class = (GObjectClass *) klass;

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

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

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


static void
kz_downloader_grp_init (KzDownloaderGrp *dlgrp)
{
	dlgrp->items = NULL;
}


void
kz_downloader_grp_dispose (GObject *object)
{
	KzDownloaderGrp *dlgrp = KZ_DOWNLOADER_GRP(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);
}


KzDownloaderGrp *
kz_downloader_grp_new (void)
{
	KzDownloaderGrp *dlgrp = KZ_DOWNLOADER_GRP(g_object_new(KZ_TYPE_DOWNLOADER_GRP, NULL));

	return dlgrp;
}


KzDownloaderGrp *
kz_downloader_grp_get_instance (void)
{
	if (!dlgrp_single)
		dlgrp_single = kz_downloader_grp_new();
	else
		g_object_ref(dlgrp_single);

	return dlgrp_single;
}


static void
disconnect_signal(KzDownloader *dl, KzDownloaderGrp *dlgrp)
{
	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
cb_download_complete (KzDownloader *dl, KzDownloaderGrp *dlgrp)
{
	g_return_if_fail(KZ_IS_DOWNLOADER_GRP(dlgrp));
	g_return_if_fail(KZ_IS_DOWNLOADER(dl));

	disconnect_signal(dl, dlgrp);

	kz_downloader_grp_remove_item(dlgrp, dl);
}


static void
cb_download_error (KzDownloader *dl, KzDownloaderGrp *dlgrp)
{
	g_return_if_fail(KZ_IS_DOWNLOADER_GRP(dlgrp));
	g_return_if_fail(KZ_IS_DOWNLOADER(dl));

	disconnect_signal(dl, dlgrp);

	kz_downloader_grp_remove_item(dlgrp, dl);
}


static void
cb_download_progress (KzDownloader *dl, KzDownloaderGrp *dlgrp)
{
	g_return_if_fail(KZ_IS_DOWNLOADER_GRP(dlgrp));
	g_return_if_fail(KZ_IS_DOWNLOADER(dl));

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


void
kz_downloader_grp_add_item (KzDownloaderGrp *dlgrp, KzDownloader *dl)
{
	g_return_if_fail(KZ_IS_DOWNLOADER_GRP(dlgrp));
	g_return_if_fail(KZ_IS_DOWNLOADER(dl));

	dlgrp->items = g_slist_append(dlgrp->items, 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);	
	/* start download */
	kz_downloader_to_file(dl);

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


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

	g_object_unref(G_OBJECT(dl));

	return FALSE;
}


void
kz_downloader_grp_remove_item (KzDownloaderGrp *dlgrp, KzDownloader *dl)
{
	g_return_if_fail(KZ_IS_DOWNLOADER_GRP(dlgrp));
	g_return_if_fail(KZ_IS_DOWNLOADER(dl));
	g_signal_emit(G_OBJECT (dlgrp),
		      kz_downloader_grp_signals[REMOVE_SIGNAL],
		      0, dl);
	g_slist_remove(dlgrp->items, dl);
	g_idle_add(idle_remove_item, dl);
}
