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

/* $Id$ */

/* Copyright (C) 1998-99 Martin Baulig
   This file is part of LibGTop 2.0.

   Contributed by Martin Baulig <martin@home-of-linux.org>, April 1998.

   LibGTop 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.

   LibGTop 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 LibGTop; see the file COPYING. If not, write to the
   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
*/

#include <glibtop.h>

#include <glib-object.h>

static void glibtop_client_class_init    (glibtop_client_class   *klass);
static void glibtop_client_init          (glibtop_client         *client);
static void glibtop_client_finalize      (GObject                *object);

static gpointer parent_class = NULL;

#include <glibtop-client-private.h>

enum {
    GLIBTOP_CLIENT_SIGNAL_ERROR,
    GLIBTOP_CLIENT_SIGNAL_WARNING,
    LAST_SIGNAL
};

static guint glibtop_client_signals [LAST_SIGNAL] = { 0 };

GType
glibtop_client_get_type (void)
{
    static GType glibtop_client_type = 0;

    if (!glibtop_client_type) {
	static const GTypeInfo glibtop_client_info = {
	    sizeof (glibtop_client_class),
	    NULL,		/* base_class_init */
	    NULL,		/* base_class_finalize */
	    (GClassInitFunc) glibtop_client_class_init,
	    NULL,		/* class_finalize */
	    NULL,		/* class_data */
	    sizeof (glibtop_client),
	    16,			/* n_preallocs */
	    (GInstanceInitFunc) glibtop_client_init,
	};

	glibtop_client_type = g_type_register_static
	    (G_TYPE_OBJECT, "glibtop_client", &glibtop_client_info, 0);
    }

    return glibtop_client_type;
}

static void
glibtop_client_error_handler (glibtop_client *client, GError *error)
{
    g_return_if_fail (GLIBTOP_IS_CLIENT (client));

    if (error == NULL)
	return;

    g_error ("%s (%d): %s", g_quark_to_string (error->domain),
	     error->code, error->message);
}

static void
glibtop_client_warning_handler (glibtop_client *client, GError *error)
{
    g_return_if_fail (GLIBTOP_IS_CLIENT (client));

    if (error == NULL)
	return;

    g_warning ("%s (%d): %s", g_quark_to_string (error->domain),
	       error->code, error->message);

}

static void
glibtop_client_class_init (glibtop_client_class *klass)
{
    GObjectClass *gobject_class;

    gobject_class = (GObjectClass *) klass;

    parent_class = g_type_class_peek_parent (klass);

    glibtop_client_signals [GLIBTOP_CLIENT_SIGNAL_ERROR] =
	g_signal_new ("error",
		       G_TYPE_FROM_CLASS (klass),
		       G_SIGNAL_RUN_LAST,
		       G_STRUCT_OFFSET (glibtop_client_class, error),
		       NULL, NULL,
		       g_cclosure_marshal_VOID__POINTER,
		       G_TYPE_NONE, 1, G_TYPE_POINTER, NULL);

    glibtop_client_signals [GLIBTOP_CLIENT_SIGNAL_WARNING] =
	g_signal_new ("warning",
		       G_TYPE_FROM_CLASS (klass),
		       G_SIGNAL_RUN_LAST,
		       G_STRUCT_OFFSET (glibtop_client_class, warning),
		       NULL, NULL,
		       g_cclosure_marshal_VOID__POINTER,
		       G_TYPE_NONE, 1, G_TYPE_POINTER, NULL);

    klass->error = glibtop_client_error_handler;
    klass->warning = glibtop_client_warning_handler;

    gobject_class->finalize = glibtop_client_finalize;
}

static void
glibtop_client_init (glibtop_client *glibtop)
{
    glibtop_client_private *priv;

    priv = g_new0 (glibtop_client_private, 1);
    glibtop->_priv = priv;
}

static void
glibtop_client_finalize (GObject *object)
{
    glibtop_client *glibtop;
    glibtop_client_private *priv = NULL;
    GSList *c;

    glibtop = GLIBTOP_CLIENT (object);
    priv = glibtop->_priv;

    for (c = priv->backend_list; c; c = c->next)
	g_object_unref (G_OBJECT (c->data));
    g_slist_free (priv->backend_list);

    g_free (priv);

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

glibtop_client *
glibtop_client_new (void)
{
    return g_object_new (GLIBTOP_TYPE_CLIENT, NULL);
}

void
glibtop_client_propagate_error (glibtop_client *client, GError *error)
{
    GValue params [2] = { { 0, }, { 0, } };

    g_return_if_fail (GLIBTOP_IS_CLIENT (client));

    if (error == NULL)
	return;

    g_value_init (params, GLIBTOP_CLIENT_TYPE (client));
    g_value_set_object (params, G_OBJECT (client));

    g_value_init (params + 1, G_TYPE_POINTER);
    g_value_set_pointer (params + 1, error);

    g_signal_emitv (params,
		    glibtop_client_signals [GLIBTOP_CLIENT_SIGNAL_ERROR],
		    0, NULL);

    g_value_unset (params + 1);
    g_value_unset (params + 0);
}

void
glibtop_client_propagate_warning (glibtop_client *client, GError *error)
{
    GValue params [2] = { { 0, }, { 0, } };

    g_return_if_fail (GLIBTOP_IS_CLIENT (client));

    if (error == NULL)
	return;

    g_value_init (params, GLIBTOP_CLIENT_TYPE (client));
    g_value_set_object (params, G_OBJECT (client));

    g_value_init (params + 1, G_TYPE_POINTER);
    g_value_set_pointer (params + 1, error);

    g_signal_emitv (params,
		    glibtop_client_signals [GLIBTOP_CLIENT_SIGNAL_WARNING],
		    0, NULL);

    g_value_unset (params + 1);
    g_value_unset (params + 0);
}

void
glibtop_client_open_backend (glibtop_client *client, const char *backend_name,
			     guint64 features, const char **backend_args)
{
    glibtop_backend *backend;
    GError *error = NULL;

    g_return_if_fail (GLIBTOP_IS_CLIENT (client));

    backend = glibtop_backend_get (backend_name, features, backend_args,
				   &error);
    if (!backend) {
	glibtop_client_propagate_error (client, error);
	g_error_free (error);
	return;
    }

    glibtop_client_add_backend (client, backend);
}

void
glibtop_client_add_backend (glibtop_client *client,
			    glibtop_backend *backend)
{
    g_return_if_fail (GLIBTOP_IS_CLIENT (client));
    g_return_if_fail (GLIBTOP_IS_BACKEND (backend));

    client->_priv->backend_list = g_slist_append
	(client->_priv->backend_list, backend);
}

void
glibtop_client_remove_backend (glibtop_client *client,
			       glibtop_backend *backend)
{
    GSList *c;

    g_return_if_fail (GLIBTOP_IS_CLIENT (client));
    g_return_if_fail (GLIBTOP_IS_BACKEND (backend));

    c = g_slist_find (client->_priv->backend_list, backend);
    if (!c) return;

    g_slist_remove_link (client->_priv->backend_list, c);
    g_object_unref (G_OBJECT (backend));
}
