/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*  validator.c
 *	Copyright (C) 2006 Armin Burgmeier
 *
 *	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 Library 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include "validator.h"

#include <gtk/gtk.h>

typedef struct _CgValidatorPrivate CgValidatorPrivate;
struct _CgValidatorPrivate
{
	GtkWidget *widget;
	GSList *entry_list;
};

#define CG_VALIDATOR_PRIVATE(o) \
	(G_TYPE_INSTANCE_GET_PRIVATE( \
		(o), \
		CG_TYPE_VALIDATOR, \
		CgValidatorPrivate \
	))

enum {
	PROP_0,

	/* Construct only */
	PROP_WIDGET
};

static GObjectClass *parent_class = NULL;

static void
cg_validator_entry_changed_cb (GtkEntry *entry,
                               gpointer user_data)
{
	CgValidator *validator;
	validator = CG_VALIDATOR (user_data);

	cg_validator_revalidate (validator);
}

static void
cg_validator_init (CgValidator *validator)
{
	CgValidatorPrivate *priv;
	priv = CG_VALIDATOR_PRIVATE (validator);

	priv->widget = NULL;
	priv->entry_list = NULL;
}

static void 
cg_validator_finalize (GObject *object)
{
	CgValidator *validator;
	CgValidatorPrivate *priv;
	GSList *item;
	
	validator = CG_VALIDATOR (object);
	priv = CG_VALIDATOR_PRIVATE (validator);
	
	for (item = priv->entry_list; item != NULL; item = item->next)
	{
		g_signal_handlers_disconnect_by_func (
			G_OBJECT (item->data), G_CALLBACK (cg_validator_entry_changed_cb),
			validator);
	}
	
	g_slist_free (priv->entry_list);
	priv->entry_list = NULL;

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

static void
cg_validator_set_property (GObject *object,
                           guint prop_id,
                           const GValue *value,
                           GParamSpec *pspec)
{
	CgValidator *validator;
	CgValidatorPrivate *priv;

	g_return_if_fail (CG_IS_VALIDATOR (object));

	validator = CG_VALIDATOR (object);
	priv = CG_VALIDATOR_PRIVATE (validator);

	switch (prop_id)
	{
	case PROP_WIDGET:
		priv->widget = GTK_WIDGET (g_value_get_object (value));
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
		break;
	}
}

static void
cg_validator_get_property (GObject *object,
                           guint prop_id,
                           GValue *value, 
                           GParamSpec *pspec)
{
	CgValidator* validator;
	CgValidatorPrivate* priv;

	g_return_if_fail(CG_IS_VALIDATOR(object));

	validator = CG_VALIDATOR(object);
	priv = CG_VALIDATOR_PRIVATE(validator);

	switch(prop_id)
	{
	case PROP_WIDGET:
		g_value_set_object(value, G_OBJECT(priv->widget));
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
		break;
	}
}

static void
cg_validator_class_init (CgValidatorClass* klass)
{
	GObjectClass *object_class = G_OBJECT_CLASS (klass);
	parent_class = g_type_class_peek_parent (klass);

	g_type_class_add_private (klass, sizeof (CgValidatorPrivate));

	object_class->finalize = cg_validator_finalize;
	object_class->set_property = cg_validator_set_property;
	object_class->get_property = cg_validator_get_property;

	g_object_class_install_property (object_class,
	                                 PROP_WIDGET,
	                                 g_param_spec_object ("widget",
	                                                      "Widget",
	                                                      "Widget to make insensitive if the entries are empty",
	                                                      GTK_TYPE_WIDGET,
	                                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
}

GType
cg_validator_get_type (void)
{
	static GType our_type = 0;

	if(our_type == 0)
	{
		static const GTypeInfo our_info =
		{
			sizeof (CgValidatorClass),
			(GBaseInitFunc) NULL,
			(GBaseFinalizeFunc) NULL,
			(GClassInitFunc) cg_validator_class_init,
			NULL,
			NULL,
			sizeof (CgValidator),
			0,
			(GInstanceInitFunc) cg_validator_init,
			NULL
		};

		our_type = g_type_register_static (G_TYPE_OBJECT, "CgValidator",
		                                   &our_info, 0);
	}

	return our_type;
}

CgValidator *
cg_validator_new (GtkWidget *widget,
                  ...)
{
	CgValidator *validator;
	CgValidatorPrivate *priv;
	GtkEntry *entry;
	va_list arglist;

	validator = CG_VALIDATOR (g_object_new (CG_TYPE_VALIDATOR, "widget",
	                                        widget, NULL));

	priv = CG_VALIDATOR_PRIVATE (validator);

	va_start (arglist, widget);
	entry = va_arg (arglist, GtkEntry *);
	while (entry != NULL)
	{
		g_signal_connect (G_OBJECT (entry), "changed",
		                  G_CALLBACK (cg_validator_entry_changed_cb),
		                  validator);

		priv->entry_list = g_slist_prepend (priv->entry_list, entry);
		entry = va_arg (arglist, GtkEntry *);
	}
	
	cg_validator_revalidate (validator);
	return validator;
}

void
cg_validator_revalidate (CgValidator *validator)
{
	CgValidatorPrivate *priv;
	GtkEntry *entry;
	GSList *item;
	gchar *text;
	
	priv = CG_VALIDATOR_PRIVATE (validator);
	for (item = priv->entry_list; item != NULL; item = item->next)
	{
		entry = GTK_ENTRY (item->data);
		text = g_strdup (gtk_entry_get_text (entry));
		g_strchomp (text);
		if (*text == '\0') break;
	}
	
	if (item == NULL)
		gtk_widget_set_sensitive (priv->widget, TRUE);
	else
		gtk_widget_set_sensitive (priv->widget, FALSE);
}
