/*
 *  Copyright (C) 2003  Tommi Komulainen
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation. 
 *
 *  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
 */ 

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "hig-alert.h"

#include <glib-object.h>
#include <gtk/gtkhbox.h>
#include <gtk/gtkimage.h>
#include <gtk/gtklabel.h>
#include <gtk/gtkstock.h>
#include <gtk/gtkvbox.h>

#ifndef GTK_STOCK_DIALOG_AUTHENTICATION
#define GTK_STOCK_DIALOG_AUTHENTICATION "gtk-stock-authentication"
#endif

static GtkDialogClass *parent_class;

enum {
	PROP_0,
	PROP_ALERT_TYPE
};

static void
hig_alert_get_property (GObject    *object,
                        guint       prop_id,
			GValue     *value,
			GParamSpec *pspec)
{
	HigAlert *self;

	self = HIG_ALERT(object);

	switch (prop_id)
	{
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
		break;
	}
}

static void
_setup_image (HigAlert *self, HigAlertType alert_type)
{
	const char   *stock_id;
	GtkStockItem  item;

	switch (alert_type)
	{
	case HIG_ALERT_INFORMATION:
		stock_id = GTK_STOCK_DIALOG_INFO;
		break;

	case HIG_ALERT_ERROR:
		stock_id = GTK_STOCK_DIALOG_ERROR;
		break;

	case HIG_ALERT_CONFIRMATION:
		stock_id = GTK_STOCK_DIALOG_WARNING;
		break;

	case HIG_ALERT_AUTHENTICATION:
		stock_id = GTK_STOCK_DIALOG_AUTHENTICATION;
		if (!gtk_stock_lookup (stock_id, &item))
			stock_id = GTK_STOCK_DIALOG_QUESTION;
		break;

	default:
		g_warning ("Unknown HigAlertType %d", alert_type);
		stock_id = GTK_STOCK_DIALOG_INFO;
		break;
	}

	if (gtk_stock_lookup (stock_id, &item))
	{
		gtk_image_set_from_stock (GTK_IMAGE(self->image), stock_id, 
				          GTK_ICON_SIZE_DIALOG);
	}
	else
		g_warning ("Stock dialog ID \"%s\" doesn't exist?", stock_id);
}

static void
hig_alert_set_property (GObject      *object,
                        guint         prop_id,
			const GValue *value,
			GParamSpec   *pspec)
{
	HigAlert *self;

	self = HIG_ALERT(object);

	switch (prop_id)
	{
	case PROP_ALERT_TYPE:
		_setup_image (self, g_value_get_enum (value));
		break;

	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
		break;
	}
}

static void
hig_alert_style_set (GtkWidget *widget, GtkStyle *previous_style)
{
	/* just preventing GtkDialog from messing with spacings */
}

static void
hig_alert_class_init (HigAlertClass *klass)
{
	GObjectClass *object_class = G_OBJECT_CLASS(klass);
	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);

	parent_class = g_type_class_peek_parent (klass);

	object_class->set_property = hig_alert_set_property;
	object_class->get_property = hig_alert_get_property;

	g_object_class_install_property (object_class, PROP_ALERT_TYPE,
		g_param_spec_enum ("alert_type",
			           "Alert Type",
				   "The type of the alert",
				   HIG_TYPE_ALERT_TYPE,
				   HIG_ALERT_INFORMATION,
				   G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));

	widget_class->style_set = hig_alert_style_set;
}

static void
_make_font_bold_and_larger (GtkWidget *widget)
{
	PangoFontDescription *font_desc;
	gint                  size;

	gtk_widget_ensure_style (widget);
	size = pango_font_description_get_size (widget->style->font_desc);

	font_desc = pango_font_description_from_string ("bold");
	pango_font_description_set_size (font_desc, size * PANGO_SCALE_LARGE);

	gtk_widget_modify_font (widget, font_desc);
	pango_font_description_free (font_desc);
}

static void
hig_alert_init (HigAlert *self)
{
	GtkWidget *hbox, *hbox2;

	self->image = gtk_image_new_from_stock (NULL, GTK_ICON_SIZE_DIALOG);
	gtk_misc_set_alignment (GTK_MISC(self->image), 0.5, 0.0);
	self->primary_text = g_object_new (GTK_TYPE_LABEL,
		"selectable", TRUE,
		"wrap",       TRUE,
		"xalign",     0.0, 
		"yalign",     0.0,
		NULL);
	_make_font_bold_and_larger (self->primary_text);

	self->secondary_text = g_object_new (GTK_TYPE_LABEL,
		"selectable", TRUE,
		"wrap",       TRUE,
		"xalign",     0.0, 
		"yalign",     0.0,
		NULL);

	hbox = gtk_hbox_new (FALSE, 12);
	self->text_vbox = gtk_vbox_new (FALSE, 12);

	gtk_box_pack_start (GTK_BOX(hbox), self->image, FALSE, FALSE, 0);
	gtk_box_pack_start (GTK_BOX(hbox), self->text_vbox, TRUE, TRUE, 0);

	gtk_box_pack_start (GTK_BOX(self->text_vbox), self->primary_text,
			    FALSE, FALSE, 0);
	gtk_box_pack_start (GTK_BOX(self->text_vbox), self->secondary_text,
			    FALSE, FALSE, 0);

	gtk_box_pack_start (GTK_BOX(GTK_DIALOG(self)->vbox), 
			    hbox,
			    FALSE, FALSE, 0);

	/* Pack an extra hbox at the end of the dialog just before the
	 * action_area, this gives us the 24 pixel space */
	hbox2 = gtk_hbox_new (FALSE, 0);
	gtk_box_pack_end (GTK_BOX(GTK_DIALOG(self)->vbox), hbox2, TRUE, FALSE, 0);

	gtk_widget_show (hbox);
	gtk_widget_show (hbox2);
	gtk_widget_show (self->image);
	gtk_widget_show (self->text_vbox);

	g_object_set (G_OBJECT(self),
	        "border-width",  6,
		"has-separator", FALSE,
		"resizable",     FALSE,
		"title",         "",
		NULL);
	g_object_set (G_OBJECT(GTK_DIALOG(self)->vbox),
	        "border-width",  6,
		"spacing",      12,
		NULL);
	gtk_box_set_spacing (GTK_BOX(GTK_DIALOG(self)->action_area), 6);
}

GType
hig_alert_get_type (void)
{
	static GType type = 0;
	if (!type)
	{
		static const GTypeInfo info =
		{
			sizeof (HigAlertClass),
			NULL,
			NULL,
			(GClassInitFunc) hig_alert_class_init,
			NULL,
			NULL,
			sizeof (HigAlert),
			0,
			(GInstanceInitFunc) hig_alert_init,
		};

		type = g_type_register_static (GTK_TYPE_DIALOG, "HigAlert",
				               &info, 0);
	}
	return type;
}

GtkWidget *
hig_alert_new (GtkWindow      *parent,
	       GtkDialogFlags  flags,
	       HigAlertType    alert_type,
	       const char     *primary_text,
	       const char     *secondary_text,
	       const char     *first_button_text,
	       ...)
{
	GtkWidget *widget;
	HigAlert  *self;
	va_list    args;

	widget = g_object_new (HIG_TYPE_ALERT, "alert_type", alert_type, 0);

	self = HIG_ALERT(widget);

	if (parent != NULL)
	{
		gtk_window_set_transient_for (GTK_WINDOW(widget),
					      GTK_WINDOW(parent));
	}

	if (flags & GTK_DIALOG_MODAL)
		gtk_window_set_modal (GTK_WINDOW(widget), TRUE);

	if (flags & GTK_DIALOG_DESTROY_WITH_PARENT)
		gtk_window_set_destroy_with_parent (GTK_WINDOW(widget), TRUE);


	hig_alert_set_primary_printf (self, "%s", primary_text);
	hig_alert_set_secondary_printf (self, "%s", secondary_text);

	va_start (args, first_button_text);
	while (first_button_text)
	{
		int response_id;

		response_id = va_arg (args, int);

		gtk_dialog_add_button (GTK_DIALOG(self), first_button_text, response_id);

		first_button_text = va_arg (args, const char *);
	}
	va_end (args);

	return widget;
}

static void
_label_set_text_valist (GtkWidget  *label,
                        const char *fmt,
			va_list     args)
{
	char *text;

	text = g_strdup_vprintf (fmt, args);
	if (text)
	{
		gtk_label_set_markup (GTK_LABEL(label), text);
		g_free (text);
		gtk_widget_show (label);
	}
	else
		gtk_widget_hide (label);
}

void
hig_alert_set_primary_printf (HigAlert   *self,
                              const char *fmt,
			      ...)
{
	va_list args;

	va_start (args, fmt);
	_label_set_text_valist (self->primary_text, fmt, args);
	va_end (args);
}

void
hig_alert_set_secondary_printf (HigAlert   *self,
                                const char *fmt,
				...)
{
	va_list args;

	va_start (args, fmt);
	_label_set_text_valist (self->secondary_text, fmt, args);
	va_end (args);
}

void
hig_alert_add_widget (HigAlert  *self,
                      GtkWidget *widget)
{
	gtk_box_pack_start (GTK_BOX(self->text_vbox), widget, FALSE, FALSE, 0);
}

GType
hig_alert_type_get_type (void)
{
	static GType etype = 0;
	if (etype == 0) {
		static const GEnumValue values[] = {
			{ HIG_ALERT_INFORMATION,    "HIG_ALERT_INFORMATION",    "information" },
			{ HIG_ALERT_ERROR,          "HIG_ALERT_ERROR",          "error" },
			{ HIG_ALERT_CONFIRMATION,   "HIG_ALERT_CONFIRMATION",   "confirmation" },
			{ HIG_ALERT_AUTHENTICATION, "HIG_ALERT_AUTHENTICATION", "authentication" },
			{ 0, NULL, NULL }
		};
		etype = g_enum_register_static ("HigAlertType", values);
	}
	return etype;
}
