/* this file is part of gnome-gdb, a GUI for the gdb
 *
 * AUTHORS
 *       Sven Herzberg        <herzi@gnome-de.org>
 *
 * Copyright (C) 2005 Sven Herzberg
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 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 General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser 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 "herzi-glade-dialog.h"

#include <gtk/gtklabel.h>
#include <gtk/gtkstock.h>
#include <gtk/gtkvbox.h>

#include "glib-helpers.h"

/* GType stuff */
G_DEFINE_ABSTRACT_TYPE(HerziGladeDialog, herzi_glade_dialog, GTK_TYPE_DIALOG);

static void
herzi_glade_dialog_init(HerziGladeDialog* self G_GNUC_UNUSED)
{}

// Gets these parameters:
// @new_parent: the new dialog
// if(!is_action_area) {
//	@old_parent: the vbox of the old dialog
// } else {
//	@old_parent: the old dialog
// }
static void
hgd_move_widgets(GtkContainer* old_parent, GtkDialog* new_parent, gboolean is_action_area) {
	GList* children;
	GList* child;

	g_return_if_fail(GTK_IS_DIALOG(new_parent));
	g_return_if_fail(!is_action_area || GTK_IS_DIALOG(old_parent));
	g_return_if_fail(is_action_area || GTK_IS_VBOX(old_parent));

	if(!is_action_area) {
		GtkBox* old_box = GTK_BOX(old_parent);
		GtkBox* new_box = GTK_BOX(new_parent->vbox);
		gboolean    expand, fill;
		guint       padding;
		GtkPackType packing;
		children = g_list_copy(gtk_container_get_children(old_parent));
		for(child = children; child; child = child->next) {
			GtkWidget * widget = GTK_WIDGET(child->data);
			gtk_box_query_child_packing(old_box, widget, &expand, &fill, &padding, &packing);
			gtk_widget_reparent(GTK_WIDGET(child->data), new_parent->vbox);
			gtk_box_set_child_packing(new_box, widget, expand, fill, padding, packing);
		}
		g_list_free(children);
	} else {
		GtkDialog* old_dialog = GTK_DIALOG(old_parent);
		GtkDialog* new_dialog = GTK_DIALOG(new_parent);

		old_parent = GTK_CONTAINER(old_dialog->action_area);
		children = g_list_copy_reversed(gtk_container_get_children(old_parent));
		for(child = children; child; child = child->next) {
			GtkWidget      * widget = GTK_WIDGET(child->data);
			GtkResponseType  response = gtk_dialog_get_response_for_widget(old_dialog, widget);
			g_object_ref(widget);
			gtk_container_remove(old_parent, widget);
			gtk_dialog_add_action_widget(new_dialog, widget, response);
			g_object_unref(widget);
		}
		g_list_free(children);
	}
}

static GtkWidget*
find_default_widget (GtkWidget* widget)
{
	if (GTK_WIDGET_RECEIVES_DEFAULT (widget)) {
		return widget;
	} else if (GTK_IS_CONTAINER (widget)) {
		GList* children = gtk_container_get_children (GTK_CONTAINER (widget));
		GList* child;
		GtkWidget* found = NULL;

		for (child = children; child; child = child->next) {
			found = find_default_widget (child->data);

			if (G_UNLIKELY (found)) {
				break;
			}
		}

		g_list_free (children);

		return found;
	} else {
		/* neither default nor container */
		return NULL;
	}
}

static GObject*
glade_dialog_constructor(GType type, guint n_properties, GObjectConstructParam* properties)
{
	GObject              * retval;
	HerziGladeDialog     * self;
	HerziGladeDialogClass* self_class;
	GtkWidget            * root_widget = NULL;
	GladeXML             * xml = NULL;

	retval     = G_OBJECT_CLASS(herzi_glade_dialog_parent_class)->constructor(type, n_properties, properties);
	self       = HERZI_GLADE_DIALOG(retval);
	self_class = HERZI_GLADE_DIALOG_GET_CLASS(self);

	g_return_val_if_fail(self_class->filename && self_class->root_widget, NULL);

	/* creating the glade xml object */
	if(self_class->filename && self_class->root_widget) {
		xml = glade_xml_new(self_class->filename, self_class->root_widget, NULL);
	}

	/* adding the dialog's content */
	if(xml && self_class->root_widget) {
		root_widget = glade_xml_get_widget(xml, self_class->root_widget);
	}

	if(!GLADE_IS_XML(xml) || !GTK_IS_DIALOG(root_widget)) {
		// FIXME: add a message and a close button if case of an empty button box
		/* add default widgets */
		GtkWidget* content = gtk_label_new(NULL);
#warning "FIXME: make translatable"
		gtk_label_set_markup(GTK_LABEL(content),
				     "<span weight='bold'>"
				       "This dialog could not be completely "
				       "constructed</span>"
				     "\n\n"
				     "<span style='italic'>"
				       "Either there was an error loading the "
				       "glade file or the provided root widget "
				       "was not a dialog.</span>");
		// FIXME: add i18n to the error message and display only the correct one
		gtk_widget_show(content);
		gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(self)->vbox), content);

		gtk_dialog_add_button(GTK_DIALOG(self), GTK_STOCK_CLOSE, GTK_RESPONSE_DELETE_EVENT);
	} else {
		/* move widgets */
		GtkContainer* old_parent = GTK_CONTAINER(GTK_DIALOG(root_widget)->vbox);
		GtkDialog   * new_parent = GTK_DIALOG(self);
		gboolean      is_action_area = FALSE;

		GtkWidget* default_w = find_default_widget (root_widget);

		hgd_move_widgets(old_parent, new_parent, is_action_area);

		old_parent = GTK_CONTAINER(root_widget);
		new_parent = GTK_DIALOG(self);
		is_action_area = TRUE;

		hgd_move_widgets(old_parent, new_parent, is_action_area);

		gtk_dialog_set_has_separator(new_parent,
					     gtk_dialog_get_has_separator(GTK_DIALOG(root_widget)));

		gtk_widget_grab_default (default_w);

		if(HERZI_GLADE_DIALOG_GET_CLASS(self)->connect_widgets) {
			HERZI_GLADE_DIALOG_GET_CLASS(self)->connect_widgets(self, xml);
		}

		g_object_unref(xml);
	}

	if(root_widget) {
		gtk_object_destroy(GTK_OBJECT(root_widget));
	}

	return retval;
}

static void
herzi_glade_dialog_class_init(HerziGladeDialogClass* self_class)
{
	GObjectClass* go_class = G_OBJECT_CLASS(self_class);

	/* GObjectClass */
	go_class->constructor = glade_dialog_constructor;
}

