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

/*
 *  Copyright (C) 2005 Hiroyuki Ikzoe
 *
 *  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.
 */

/*
 * This code is based on EmbedPrompter.cpp in Mozilla.
 *
 */

#include "kz-prompt-dialog.h"

#include <stdio.h>
#include <gdk/gdkkeysyms.h>
#include <glib/gi18n.h>

#include "gobject-utils.h"
#include "kz-icons.h"

#define EMBED_MAX_BUTTONS 3

typedef struct _KzPromptDialogPrivate	KzPromptDialogPrivate;
struct _KzPromptDialogPrivate
{
	gint prompt_type;

	gchar *text_value;
	gchar *check_message;
	gboolean check_value;
	gchar *user;
	gchar *pass;

	gint      button_pressed;
	gboolean  confirm_result;
	gint      selected_item;

	GtkWidget *host_label;
	GtkWidget *message_label;
	GtkWidget *content_vbox;
	GtkWidget *parent_window;
	GtkWidget *user_field;
	GtkWidget *pass_field;
	GtkWidget *text_field;
	GtkWidget *combo_box;
	GtkWidget *check_box;
};

enum {
	PROP_0,
	PROP_PROMPT_TYPE,
	PROP_PARENT_WINDOW
};


#define KZ_PROMPT_DIALOG_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), KZ_TYPE_PROMPT_DIALOG, KzPromptDialogPrivate))

enum {
	INCLUDE_USERNAME = 1 << 0,
	INCLUDE_PASSWORD = 1 << 1,
	INCLUDE_CHECKBOX = 1 << 2,
	INCLUDE_CANCEL   = 1 << 3
};

typedef struct {
	int    flags;
	gchar *icon;
} DialogDescription;

static const DialogDescription DialogTable[] = {
	{ 0,                      GTK_STOCK_DIALOG_WARNING  },  // ALERT
	{ INCLUDE_CHECKBOX,       GTK_STOCK_DIALOG_WARNING  },  // ALERT_CHECK
	{ INCLUDE_CANCEL,         GTK_STOCK_DIALOG_QUESTION },  // CONFIRM
	{ INCLUDE_CHECKBOX |
	  INCLUDE_CANCEL,         GTK_STOCK_DIALOG_QUESTION },  // CONFIRM_CHECK
	{ INCLUDE_CANCEL |
	  INCLUDE_CHECKBOX,       GTK_STOCK_DIALOG_QUESTION },  // PROMPT
	{ INCLUDE_CANCEL |
	  INCLUDE_USERNAME |
	  INCLUDE_PASSWORD |
	  INCLUDE_CHECKBOX,       GTK_STOCK_DIALOG_QUESTION },  // PROMPT_USER_PASS
	{ INCLUDE_CANCEL |
	  INCLUDE_PASSWORD |
	  INCLUDE_CHECKBOX,       GTK_STOCK_DIALOG_QUESTION },  // PROMPT_PASS
	{ INCLUDE_CANCEL,         GTK_STOCK_DIALOG_QUESTION },  // SELECT
	{ INCLUDE_CANCEL |
	  INCLUDE_CHECKBOX,       GTK_STOCK_DIALOG_QUESTION }   // UNIVERSAL
};

static void     kz_prompt_dialog_class_init         (KzPromptDialogClass *klass);
static void     kz_prompt_dialog_init               (KzPromptDialog  *prompt);
static GObject *kz_prompt_dialog_constructor        (GType           type,
						     guint           n_props,
						     GObjectConstructParam *props);
static void     kz_prompt_dialog_dispose            (GObject        *object);
static void     kz_prompt_dialog_set_property       (GObject       *object,
						     guint          prop_id,
						     const GValue  *value,
						     GParamSpec    *pspec);
static void     kz_prompt_dialog_get_property       (GObject       *object,
						     guint          prop_id,
						     GValue        *value,
						     GParamSpec    *pspec);
static void     kz_prompt_dialog_save_dialog_values (KzPromptDialog *prompt);

static GtkDialogClass *parent_class = NULL;


KZ_OBJECT_GET_TYPE(kz_prompt_dialog, "KzPromptDialog", KzPromptDialog,
		   kz_prompt_dialog_class_init, kz_prompt_dialog_init,
		   GTK_TYPE_DIALOG)

static void
kz_prompt_dialog_class_init (KzPromptDialogClass *klass)
{
	GObjectClass *gobject_class;

	parent_class = g_type_class_peek_parent (klass);

	gobject_class = (GObjectClass *) klass;

	/* GtkObject signals */
	gobject_class->constructor  = kz_prompt_dialog_constructor;
	gobject_class->dispose      = kz_prompt_dialog_dispose;
	gobject_class->set_property = kz_prompt_dialog_set_property;
	gobject_class->get_property = kz_prompt_dialog_get_property;

	g_object_class_install_property
		(gobject_class,
		 PROP_PROMPT_TYPE,
		 g_param_spec_int ("prompt-type",
				 _("The dialog type"),
				 _("The type of the dialog"),
				   G_MININT,
				   G_MAXINT,
				   TYPE_ALERT,
				   G_PARAM_READWRITE |
				   G_PARAM_CONSTRUCT_ONLY));

	g_object_class_install_property
		(gobject_class,
		 PROP_PARENT_WINDOW,
		 g_param_spec_object ("parent-window",
				      _("ParentWindow"),
				      _("The parent of the dialog"),
				      GTK_TYPE_WIDGET,
				      G_PARAM_READWRITE |
				      G_PARAM_CONSTRUCT_ONLY));
	g_type_class_add_private (gobject_class, sizeof(KzPromptDialogPrivate));
}


static void
kz_prompt_dialog_init (KzPromptDialog *prompt)
{
	GtkWidget *main_vbox, *label, *hbox, *vbox, *icon;
	const gchar *icon_desc;
	KzPromptDialogPrivate *priv = KZ_PROMPT_DIALOG_GET_PRIVATE(prompt);

	priv->prompt_type = TYPE_ALERT;

	main_vbox = GTK_DIALOG(prompt)->vbox;
	gtk_box_set_spacing(GTK_BOX(main_vbox), 4);
	gtk_window_set_icon(GTK_WINDOW(prompt), kz_icon);

	if (priv->parent_window)	
		gtk_window_set_destroy_with_parent(GTK_WINDOW(prompt), TRUE);

	/* gtk will resize this for us as necessary */
	gtk_window_set_default_size(GTK_WINDOW(prompt), 100, 50);
	
	/* this HBox will contain the icon, and a vbox which contains the */
	/* dialog text and other widgets. */
	hbox = gtk_hbox_new(FALSE, 12);
	gtk_widget_show(hbox);

	// Set up dialog properties according to the GNOME HIG
	// (http://developer.gnome.org/projects/gup/hig/1.0/windows.html#alert-windows)
	gtk_container_set_border_width(GTK_CONTAINER(prompt), 6);
	gtk_dialog_set_has_separator(GTK_DIALOG(prompt), FALSE);
	gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(prompt)->vbox), 12);
	gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);

	// This is the VBox which will contain the label and other controls.
	priv->content_vbox = vbox = gtk_vbox_new(FALSE, 12);
	gtk_widget_show(vbox);

	// label for host name
	priv->host_label = label = gtk_label_new(NULL);
	gtk_widget_show(label);
	gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
	gtk_label_set_selectable(GTK_LABEL(label), TRUE);
	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);

	// now pack the label into the vbox
	priv->message_label = label = gtk_label_new(NULL);
	gtk_widget_show(label);
	gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
	gtk_label_set_selectable(GTK_LABEL(label), TRUE);
	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);

	// get the stock icon for this dialog and put it in the box
	icon_desc = DialogTable[priv->prompt_type].icon;
	icon = gtk_image_new_from_stock(icon_desc, GTK_ICON_SIZE_DIALOG);
	gtk_widget_show(icon);
	gtk_misc_set_alignment(GTK_MISC(icon), 0.5, 0.0);
	gtk_box_pack_start(GTK_BOX(hbox), icon, FALSE, FALSE, 0);

	// Pack the contentsVBox into the dialogHBox and the dialog.
	gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(prompt)->vbox), hbox, FALSE,
			FALSE, 0);
}


static GObject*
kz_prompt_dialog_constructor (GType                  type,
			      guint                  n_props,
			      GObjectConstructParam *props)
{
	KzPromptDialog *prompt;
	KzPromptDialogPrivate *priv;
	GObject *object;
	GObjectClass *klass = G_OBJECT_CLASS(parent_class);
	gint prompt_type;
	int widgetFlags;

	object = klass->constructor(type, n_props, props);

	prompt = KZ_PROMPT_DIALOG(object);
	priv = KZ_PROMPT_DIALOG_GET_PRIVATE (object);

	if (priv->parent_window)
		gtk_window_set_transient_for(GTK_WINDOW(prompt), GTK_WINDOW(priv->parent_window));

	prompt_type = priv->prompt_type;
	widgetFlags = DialogTable[prompt_type].flags;

	if (widgetFlags & (INCLUDE_USERNAME | INCLUDE_PASSWORD)) 
	{

	// If we're creating a username and/or password field, make an hbox
	// which will contain two vboxes, one for the labels and one for the
	// text fields.  This will let us line up the textfields.

		GtkWidget* userPassHBox = gtk_hbox_new(FALSE, 12);
		GtkWidget* userPassLabels = gtk_vbox_new(TRUE, 6);
		GtkWidget* userPassFields = gtk_vbox_new(TRUE, 6);

		if (widgetFlags & INCLUDE_USERNAME) 
		{
			GtkWidget* userLabel = gtk_label_new("User Name:");
			gtk_box_pack_start(GTK_BOX(userPassLabels), userLabel, FALSE,
					FALSE, 0);

			priv->user_field = gtk_entry_new();

			gtk_entry_set_activates_default(GTK_ENTRY(priv->user_field), TRUE);

			gtk_box_pack_start(GTK_BOX(userPassFields), priv->user_field, FALSE,
					FALSE, 0);
		}
		if (widgetFlags & INCLUDE_PASSWORD) 
		{
			GtkWidget* passLabel = gtk_label_new("Password:");
			gtk_box_pack_start(GTK_BOX(userPassLabels), passLabel, FALSE,
					FALSE, 0);

			priv->pass_field = gtk_entry_new();

			gtk_entry_set_visibility(GTK_ENTRY(priv->pass_field), FALSE);
			gtk_entry_set_activates_default(GTK_ENTRY(priv->pass_field), TRUE);

			gtk_box_pack_start(GTK_BOX(userPassFields), priv->pass_field, FALSE,
					FALSE, 0);
		}

		gtk_box_pack_start(GTK_BOX(userPassHBox), userPassLabels, FALSE,
				FALSE, 0);
		gtk_box_pack_start(GTK_BOX(userPassHBox), userPassFields, FALSE,
				FALSE, 0);
		gtk_box_pack_start(GTK_BOX(priv->content_vbox), userPassHBox, FALSE, FALSE, 0);
		gtk_widget_show_all(userPassLabels);
		gtk_widget_show_all(userPassFields);
		gtk_widget_show_all(userPassHBox);
	}

	if (prompt_type == TYPE_PROMPT) 
	{
		priv->text_field = gtk_entry_new();

		gtk_entry_set_activates_default(GTK_ENTRY(priv->text_field), TRUE);

		gtk_box_pack_start(GTK_BOX(priv->content_vbox), priv->text_field, FALSE, FALSE, 0);
	}

	// Add a checkbox
	if (widgetFlags & INCLUDE_CHECKBOX)
	{
		priv->check_box = gtk_check_button_new_with_label(NULL);

		gtk_box_pack_start(GTK_BOX(priv->content_vbox), priv->check_box, FALSE, FALSE, 0);
	}

	// Add a dropdown menu
	if (prompt_type == TYPE_SELECT) 
	{
		// Build up a GtkMenu containing the items
		priv->combo_box = gtk_combo_box_new_text();

		gtk_box_pack_start(GTK_BOX(priv->content_vbox), priv->combo_box, FALSE, FALSE, 0);
	}

	if (prompt_type == TYPE_UNIVERSAL) 
	{
		gtk_dialog_set_default_response(GTK_DIALOG(prompt), 0);
	}
	else 
	{
		GtkWidget* okButton;
		// Create standard ok and cancel buttons
		if (widgetFlags & INCLUDE_CANCEL)
			gtk_dialog_add_button(GTK_DIALOG(prompt), GTK_STOCK_CANCEL,
					GTK_RESPONSE_CANCEL);

		okButton = gtk_dialog_add_button(GTK_DIALOG(prompt),
				GTK_STOCK_OK,
				GTK_RESPONSE_ACCEPT);
		gtk_widget_grab_default(okButton);
	}

	return object;
}


static void
kz_prompt_dialog_dispose (GObject *object)
{
	KzPromptDialogPrivate *priv = KZ_PROMPT_DIALOG_GET_PRIVATE (object);

	if (priv->parent_window)
		g_object_unref(priv->parent_window);
	if (priv->text_value)
		g_free(priv->text_value);
	if (priv->user)
		g_free(priv->user);
	if (priv->pass)
		g_free(priv->pass);
	priv->parent_window = NULL;

	priv->text_value   = NULL;
	priv->user         = NULL;
	priv->pass         = NULL;
	priv->parent_window = NULL;

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


static void
kz_prompt_dialog_set_property (GObject         *object,
			       guint            prop_id,
			       const GValue    *value,
			       GParamSpec      *pspec)
{
	KzPromptDialogPrivate *priv = KZ_PROMPT_DIALOG_GET_PRIVATE (object);
  
	switch (prop_id)
	{
	case PROP_PROMPT_TYPE:
		priv->prompt_type = g_value_get_int(value);
		break;
	case PROP_PARENT_WINDOW:
		priv->parent_window = g_object_ref(g_value_get_object(value));
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
		break;
	}
}


static void
kz_prompt_dialog_get_property (GObject         *object,
			       guint            prop_id,
			       GValue          *value,
			       GParamSpec      *pspec)
{
	KzPromptDialogPrivate *priv = KZ_PROMPT_DIALOG_GET_PRIVATE (object);

	switch (prop_id)
	{
    	case PROP_PROMPT_TYPE:
      		g_value_set_int (value, priv->prompt_type);
      		break;
	case PROP_PARENT_WINDOW:
		g_value_set_object(value, priv->parent_window);
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
		break;
	}
}


GtkWidget *
kz_prompt_dialog_new_with_parent (PromptType type, GtkWindow *parent_window)
{
	KzPromptDialog *dialog;

	dialog = g_object_new(KZ_TYPE_PROMPT_DIALOG,
			      "prompt-type",   type,
			      "parent-window", parent_window,
			      NULL);

	return GTK_WIDGET(dialog);
}

GtkWidget *
kz_prompt_dialog_new(PromptType type)
{
	KzPromptDialog *dialog;

	dialog = g_object_new(KZ_TYPE_PROMPT_DIALOG,
			      "prompt-type",   type,
			      "parent-window", NULL,
			      NULL);

	return GTK_WIDGET(dialog);
}

void
kz_prompt_dialog_set_host (KzPromptDialog *prompt, const gchar *hostname)
{
	gchar *text;
	KzPromptDialogPrivate *priv = KZ_PROMPT_DIALOG_GET_PRIVATE (prompt);

	
	text = g_strdup_printf (_("Hostname: %s"), hostname);
	
	gtk_label_set_text(GTK_LABEL(priv->host_label), text);

	g_free(text);
}

void
kz_prompt_dialog_set_title (KzPromptDialog *prompt, const gchar *title)
{
	gtk_window_set_title(GTK_WINDOW(prompt), title);
}

void
kz_prompt_dialog_set_text_value (KzPromptDialog *prompt, const gchar *text)
{
	KzPromptDialogPrivate *priv = KZ_PROMPT_DIALOG_GET_PRIVATE (prompt);
	
	gtk_entry_set_text(GTK_ENTRY(priv->text_field), text);
	gtk_widget_show(priv->text_field);
}

void
kz_prompt_dialog_set_check_message (KzPromptDialog *prompt, const gchar *check_message)
{
	KzPromptDialogPrivate *priv = KZ_PROMPT_DIALOG_GET_PRIVATE (prompt);

	gtk_button_set_label(GTK_BUTTON(priv->check_box), check_message);
	gtk_widget_show(priv->check_box);
}

void
kz_prompt_dialog_set_check_value (KzPromptDialog *prompt, const gboolean value)
{
	KzPromptDialogPrivate *priv = KZ_PROMPT_DIALOG_GET_PRIVATE (prompt);
	
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->check_box),
				     value);
}

void
kz_prompt_dialog_set_message_text (KzPromptDialog *prompt, const gchar *message_text)
{
	KzPromptDialogPrivate *priv = KZ_PROMPT_DIALOG_GET_PRIVATE (prompt);
	
	gtk_label_set_text(GTK_LABEL(priv->message_label), message_text);
}

void
kz_prompt_dialog_set_user (KzPromptDialog *prompt, const gchar *user)
{
	KzPromptDialogPrivate *priv = KZ_PROMPT_DIALOG_GET_PRIVATE (prompt);
	
	gtk_entry_set_text(GTK_ENTRY(priv->user_field), user);
}

void
kz_prompt_dialog_set_password (KzPromptDialog *prompt, const gchar *pass)
{
	KzPromptDialogPrivate *priv = KZ_PROMPT_DIALOG_GET_PRIVATE (prompt);

	gtk_entry_set_text(GTK_ENTRY(priv->pass_field), pass);
}

void
kz_prompt_dialog_set_buttons (KzPromptDialog *prompt, const gchar *button0_label,
		       const gchar *button1_label,
		       const gchar *button2_label)
{
	// Create buttons based on the flags passed in.
	if (button0_label && strlen(button0_label))
		gtk_dialog_add_button(GTK_DIALOG(prompt), button0_label, 0);
	if (button1_label && strlen(button1_label))
		gtk_dialog_add_button(GTK_DIALOG(prompt), button1_label, 1);
	if (button2_label && strlen(button2_label))
		gtk_dialog_add_button(GTK_DIALOG(prompt), button2_label, 2);
}

void
kz_prompt_dialog_set_items (KzPromptDialog *prompt, const gchar **item_array, guint count)
{
	gint i;
	KzPromptDialogPrivate *priv = KZ_PROMPT_DIALOG_GET_PRIVATE (prompt);
	
	for (i = 0; i < count; i++)
	{
		gtk_combo_box_append_text(GTK_COMBO_BOX(priv->combo_box),
					  item_array[i]);
	}

	gtk_widget_show(priv->combo_box);
}

gboolean
kz_prompt_dialog_get_check_value (KzPromptDialog *prompt)
{
	KzPromptDialogPrivate *priv = KZ_PROMPT_DIALOG_GET_PRIVATE (prompt);

	return priv->check_value;
}

gboolean
kz_prompt_dialog_get_confirm_value (KzPromptDialog *prompt)
{
	KzPromptDialogPrivate *priv = KZ_PROMPT_DIALOG_GET_PRIVATE (prompt);

	return priv->confirm_result;
}

const gchar *
kz_prompt_dialog_get_text_value (KzPromptDialog *prompt)
{
	KzPromptDialogPrivate *priv = KZ_PROMPT_DIALOG_GET_PRIVATE (prompt);

	return priv->text_value;
}

const gchar *
kz_prompt_dialog_get_user (KzPromptDialog *prompt)
{
	KzPromptDialogPrivate *priv = KZ_PROMPT_DIALOG_GET_PRIVATE (prompt);

	return priv->user;
}

const gchar *
kz_prompt_dialog_get_password (KzPromptDialog *prompt)
{
	KzPromptDialogPrivate *priv = KZ_PROMPT_DIALOG_GET_PRIVATE (prompt);

	return priv->pass;
}

gint
kz_prompt_dialog_get_button_pressed (KzPromptDialog *prompt)
{
	KzPromptDialogPrivate *priv = KZ_PROMPT_DIALOG_GET_PRIVATE (prompt);

	return priv->button_pressed;
}

gint
kz_prompt_dialog_get_selected_item (KzPromptDialog *prompt)
{
	KzPromptDialogPrivate *priv = KZ_PROMPT_DIALOG_GET_PRIVATE (prompt);

	return priv->selected_item;
}


void
kz_prompt_dialog_run (KzPromptDialog *prompt)
{
	gint response;
	KzPromptDialogPrivate *priv = KZ_PROMPT_DIALOG_GET_PRIVATE (prompt);
	
	gtk_widget_show(GTK_WIDGET(prompt));
	response = gtk_dialog_run(GTK_DIALOG(prompt));
	switch (response) 
	{
		case GTK_RESPONSE_NONE:
		case GTK_RESPONSE_CANCEL:
		case GTK_RESPONSE_DELETE_EVENT:
			priv->confirm_result = FALSE;
			break;
		case GTK_RESPONSE_ACCEPT:
			priv->confirm_result = TRUE;
			kz_prompt_dialog_save_dialog_values(prompt);
			break;
		default:
			priv->button_pressed = response;
			kz_prompt_dialog_save_dialog_values(prompt);
	}
}

static void
kz_prompt_dialog_save_dialog_values (KzPromptDialog *prompt)
{
	KzPromptDialogPrivate *priv = KZ_PROMPT_DIALOG_GET_PRIVATE (prompt);

	if (priv->user_field)
		priv->user = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->user_field)));

	if (priv->pass_field)
		priv->pass = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->pass_field)));

	if (priv->check_box)
		priv->check_value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->check_box));

	if (priv->text_field)
		priv->text_value = g_strdup(gtk_entry_get_text(GTK_ENTRY(priv->text_field)));

	if (priv->combo_box)
		priv->selected_item = gtk_combo_box_get_active(GTK_COMBO_BOX(priv->combo_box));
}

