/*
 *  Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
 *
 *  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.
 */

#include "galeon-sidebar.h"
#include "galeon-dialog.h"
#include "galeon-marshal.h"

#include <string.h>
#include <gtk/gtklabel.h>
#include <gtk/gtkframe.h>
#include <gtk/gtkarrow.h>
#include <gtk/gtkhbox.h>
#include <gtk/gtkbutton.h>
#include <gtk/gtkimage.h>
#include <gtk/gtkmenuitem.h>
#include <gtk/gtkpaned.h>
#include <gtk/gtkstock.h>
#include <libgnomeui/gnome-uidefs.h>
#include <libgnome/gnome-config.h>

/* State gnome_config paths */
#define STATE_SIDEBAR_PAGE  "Sidebar/current_page"

static void
galeon_sidebar_class_init (GaleonSidebarClass *klass);
static void
galeon_sidebar_init (GaleonSidebar *window);
static void
galeon_sidebar_finalize (GObject *object);

typedef struct
{
	char *id;
	char *title;
	gboolean can_remove;
	GtkWidget *item;
} GaleonSidebarPage;

struct GaleonSidebarPrivate
{
	GtkWidget *content_frame;
	GtkWidget *title_frame;
	GtkWidget *title_menu;
	GtkWidget *title_button;
	GtkWidget *title_label;
	GtkWidget *title_hbox;
	GtkWidget *remove_button;
	GObject *content;
	GList *pages;
	GaleonSidebarPage *current;
};

enum
{
	PAGE_CHANGED,
	CLOSE_REQUESTED,
	REMOVE_REQUESTED,
	LAST_SIGNAL
};

static GObjectClass *parent_class = NULL;

static guint sidebar_signals[LAST_SIGNAL] = { 0 };

GType 
galeon_sidebar_get_type (void)
{
        static GType galeon_sidebar_type = 0;

        if (galeon_sidebar_type == 0)
        {
                static const GTypeInfo our_info =
                {
                        sizeof (GaleonSidebarClass),
                        NULL, /* base_init */
                        NULL, /* base_finalize */
                        (GClassInitFunc) galeon_sidebar_class_init,
                        NULL,
                        NULL, /* class_data */
                        sizeof (GaleonSidebar),
                        0, /* n_preallocs */
                        (GInstanceInitFunc) galeon_sidebar_init
                };

                galeon_sidebar_type = g_type_register_static (GTK_TYPE_VBOX,
                                                             "GaleonSidebar",
                                                             &our_info, 0);
        }

        return galeon_sidebar_type;
}

static void
galeon_sidebar_show (GtkWidget *widget)
{
	GaleonSidebar *sidebar = GALEON_SIDEBAR(widget);

	if (!sidebar->priv->current)
	{
		/* The setting of the initial page is in the sidebar as if 
		 * you create a gtkmozembed object without ever 'realize'ing
		 * it, when it is destoryed it will crash the program :(
		 */
		char * page = gnome_config_get_string (STATE_SIDEBAR_PAGE);
		if (page)
		{
			galeon_sidebar_select_page (sidebar, page);
			g_free (page);
		}
		else if (sidebar->priv->pages)
		{
			galeon_sidebar_select_page (sidebar, 
			     ((GaleonSidebarPage *)sidebar->priv->pages->data)->id);
		}
	}

	GTK_WIDGET_CLASS (parent_class)->show (widget);	
}

static void
galeon_sidebar_size_allocate (GtkWidget *widget,
                       	      GtkAllocation *allocation)
{
	int width;
	GtkAllocation child_allocation;
	GaleonSidebar *sidebar = GALEON_SIDEBAR(widget);
	GtkWidget *frame = sidebar->priv->title_frame;
	GtkWidget *hbox = sidebar->priv->title_hbox;
	GtkRequisition child_requisition;
	
	GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
	
	gtk_widget_get_child_requisition (hbox, &child_requisition);
	width = child_requisition.width;
	
	child_allocation = frame->allocation;
	child_allocation.width = MAX (width, frame->allocation.width);
	
	gtk_widget_size_allocate (frame, &child_allocation);
}

static void
galeon_sidebar_class_init (GaleonSidebarClass *klass)
{
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
	GtkWidgetClass *widget_class;
	
	parent_class = g_type_class_peek_parent (klass);
	widget_class = (GtkWidgetClass*) klass;
	
        object_class->finalize = galeon_sidebar_finalize;
	
	widget_class->size_allocate = galeon_sidebar_size_allocate;
	widget_class->show = galeon_sidebar_show;
	
	sidebar_signals[PAGE_CHANGED] =
                g_signal_new ("page_changed",
                              G_OBJECT_CLASS_TYPE (object_class),
                              G_SIGNAL_RUN_FIRST,
                              G_STRUCT_OFFSET (GaleonSidebarClass, page_changed),
                              NULL, NULL,
                              g_cclosure_marshal_VOID__STRING,
                              G_TYPE_NONE,
                              1,
			      G_TYPE_STRING);
	sidebar_signals[CLOSE_REQUESTED] =
                g_signal_new ("close_requested",
                              G_OBJECT_CLASS_TYPE (object_class),
                              G_SIGNAL_RUN_FIRST,
                              G_STRUCT_OFFSET (GaleonSidebarClass, close_requested),
                              NULL, NULL,
                              g_cclosure_marshal_VOID__VOID,
                              G_TYPE_NONE,
                              0);
	sidebar_signals[REMOVE_REQUESTED] =
                g_signal_new ("remove_requested",
                              G_OBJECT_CLASS_TYPE (object_class),
                              G_SIGNAL_RUN_FIRST,
                              G_STRUCT_OFFSET (GaleonSidebarClass, remove_requested),
                              NULL, NULL,
                              g_cclosure_marshal_VOID__STRING,
                              G_TYPE_NONE,
                              1,
			      G_TYPE_STRING);
}

static void
popup_position_func (GtkMenu *menu,
                    int *x, 
                    int *y,
                    gboolean *push_in,
                    gpointer user_data)
{
       GtkWidget *button;

       button = GTK_WIDGET (user_data);
       
       gdk_window_get_origin (button->parent->window, x, y);
       *x += button->allocation.x;
       *y += button->allocation.y + button->allocation.height;

       *push_in = FALSE;
}


static int
title_button_press_cb (GtkWidget *item, GdkEventButton *event, gpointer data)
{
       GaleonSidebar *sidebar;
       
       sidebar = GALEON_SIDEBAR (data);

       gtk_menu_popup (GTK_MENU (sidebar->priv->title_menu),
                       NULL, NULL,
                       popup_position_func, sidebar->priv->title_button, 
                       event->button, event->time);

       return TRUE;
}

static void
close_clicked_cb (GtkWidget *button, GaleonSidebar *sidebar)
{
	g_signal_emit (G_OBJECT (sidebar), sidebar_signals[CLOSE_REQUESTED], 0);
}

static void
remove_clicked_cb (GtkWidget *button, GaleonSidebar *sidebar)
{
	g_return_if_fail (sidebar->priv->current != NULL);
	
	g_signal_emit (G_OBJECT (sidebar), sidebar_signals[REMOVE_REQUESTED], 0,
		       sidebar->priv->current->id);
}

static void
galeon_sidebar_init (GaleonSidebar *sidebar)
{
	GtkWidget *frame;
	GtkWidget *frame_hbox;
	GtkWidget *button_hbox;
	GtkWidget *close_button;
	GtkWidget *close_image;
	GtkWidget *remove_image;
	GtkWidget *remove_button;
	GtkWidget *arrow;
	
        sidebar->priv = g_new0 (GaleonSidebarPrivate, 1);
	sidebar->priv->content = NULL;
	sidebar->priv->pages = NULL;
	sidebar->priv->current = NULL;
		
	frame_hbox = gtk_hbox_new (FALSE, 0);
	
        sidebar->priv->title_button = gtk_button_new ();
        gtk_button_set_relief (GTK_BUTTON (sidebar->priv->title_button),
                               GTK_RELIEF_NONE);

	g_signal_connect (sidebar->priv->title_button, "button_press_event",
                          G_CALLBACK (title_button_press_cb),
                          sidebar);
       
        button_hbox = gtk_hbox_new (FALSE, 0);
        gtk_container_set_border_width (GTK_CONTAINER (button_hbox), 0);
       
        sidebar->priv->title_label = gtk_label_new ("");
       
        /* FIXME: Temp */
        gtk_widget_show (sidebar->priv->title_label);

        gtk_box_pack_start (GTK_BOX (button_hbox), 
                            sidebar->priv->title_label,
                            FALSE, FALSE, 0);
       
        arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_ETCHED_IN);
        gtk_widget_show (arrow);
        gtk_box_pack_end (GTK_BOX (button_hbox), arrow, FALSE, FALSE, 0);
       
        gtk_widget_show (button_hbox);
       
        gtk_container_add (GTK_CONTAINER (sidebar->priv->title_button),
                           button_hbox);

        sidebar->priv->title_menu = gtk_menu_new ();
        gtk_widget_show (sidebar->priv->title_button);
        gtk_widget_show (sidebar->priv->title_menu);

        gtk_box_pack_start (GTK_BOX (frame_hbox), 
                            sidebar->priv->title_button,
                            FALSE, FALSE, 0);

	/* Remove sidebar button */
	remove_image = gtk_image_new_from_stock (GTK_STOCK_DELETE, 
                                                 GTK_ICON_SIZE_SMALL_TOOLBAR);
        gtk_widget_show (remove_image);

	remove_button = gtk_button_new ();

	gtk_button_set_relief (GTK_BUTTON (remove_button), GTK_RELIEF_NONE);
	gtk_container_add (GTK_CONTAINER (remove_button), remove_image);

	g_signal_connect (remove_button, "clicked",
                          G_CALLBACK (remove_clicked_cb), 
                          sidebar);

        gtk_widget_show (remove_button);

	sidebar->priv->remove_button = remove_button;
	
	/* Close button */
        close_image = gtk_image_new_from_stock (GTK_STOCK_CLOSE, 
                                                GTK_ICON_SIZE_SMALL_TOOLBAR);
        gtk_widget_show (close_image);

	close_button = gtk_button_new ();

	gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE);
	gtk_container_add (GTK_CONTAINER (close_button), close_image);

	g_signal_connect (close_button, "clicked",
                          G_CALLBACK (close_clicked_cb), 
                          sidebar);

        gtk_widget_show (close_button); 
       
        gtk_box_pack_end (GTK_BOX (frame_hbox), close_button,
                          FALSE, FALSE, 0);
	gtk_box_pack_end (GTK_BOX (frame_hbox), remove_button,
                          FALSE, FALSE, 0);
	sidebar->priv->title_hbox = frame_hbox;

        frame = gtk_frame_new (NULL);
        gtk_frame_set_shadow_type (GTK_FRAME (frame), 
				   GTK_SHADOW_ETCHED_IN);
        gtk_widget_show (frame);
	sidebar->priv->title_frame = frame;
 
        gtk_container_add (GTK_CONTAINER (frame), 
			   frame_hbox);

        gtk_widget_show (frame_hbox);

	gtk_box_pack_start (GTK_BOX (sidebar), frame,
                            FALSE, FALSE, 2);

        sidebar->priv->content_frame = gtk_vbox_new (FALSE, 0);
	gtk_widget_show (sidebar->priv->content_frame);
		
        gtk_box_pack_start (GTK_BOX (sidebar), sidebar->priv->content_frame,
                            TRUE, TRUE, 0);
}

static void
galeon_sidebar_finalize (GObject *object)
{
        GaleonSidebar *sidebar;

        g_return_if_fail (object != NULL);
        g_return_if_fail (IS_GALEON_SIDEBAR (object));

        sidebar = GALEON_SIDEBAR (object);

        g_return_if_fail (sidebar->priv != NULL);

	/* FIXME free pages list */

        g_free (sidebar->priv);

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

GtkWidget *
galeon_sidebar_new (void)
{
	return GTK_WIDGET (g_object_new (GALEON_SIDEBAR_TYPE, NULL));
}

static void
select_page (GaleonSidebar *sidebar, GaleonSidebarPage *page)
{
	sidebar->priv->current = page;

	gtk_label_set_text (GTK_LABEL (sidebar->priv->title_label),
                            page->title);
	gtk_widget_set_sensitive (GTK_WIDGET(sidebar->priv->remove_button),
				  page->can_remove);
	
	gnome_config_set_string (STATE_SIDEBAR_PAGE, page->id);

	g_signal_emit (G_OBJECT (sidebar), sidebar_signals[PAGE_CHANGED], 0, 
		       page->id);
}

static void
title_menu_item_activated_cb (GtkWidget *item, GaleonSidebar *sidebar)
{
	GaleonSidebarPage *page;

	page = (GaleonSidebarPage *) g_object_get_data (G_OBJECT(item), "page");

	select_page (sidebar, page);
}

void
galeon_sidebar_add_page	(GaleonSidebar *sidebar,
			 const char *title,
			 const char *page_id,
			 gboolean can_remove)
{
	GtkWidget *item;
	GaleonSidebarPage *page;

	page = g_new0 (GaleonSidebarPage, 1);	
	page->id = g_strdup (page_id);
	page->title = g_strdup (title);
	page->can_remove = can_remove;
	
        item = gtk_menu_item_new_with_label (title); 
	g_object_set_data (G_OBJECT(item), "page", (gpointer)page);
	g_signal_connect (G_OBJECT(item), "activate",
			  G_CALLBACK (title_menu_item_activated_cb),
			  sidebar);	
	gtk_menu_shell_append (GTK_MENU_SHELL(sidebar->priv->title_menu),
                               item);
        gtk_widget_show (item);

	page->item = item;
	
	sidebar->priv->pages = g_list_append (sidebar->priv->pages,
		       			      (gpointer)page);
}

static gint 
page_compare_func (gconstpointer  a,
                   gconstpointer  b)
{
	GaleonSidebarPage *page = (GaleonSidebarPage *)a;

	return strcmp (page->id, (char*) b);
}

static GaleonSidebarPage *
galeon_sidebar_find_page_by_id (GaleonSidebar *sidebar,
				const char *page_id)
{
	GList *l;
	
	l = g_list_find_custom (sidebar->priv->pages, page_id,
				page_compare_func);
	if (!l) return NULL;
	
	return (GaleonSidebarPage *)l->data;
}

gboolean 
galeon_sidebar_remove_page (GaleonSidebar *sidebar,
			    const char *page_id)
{
	GaleonSidebarPage *page, *new_page;
	GList *l;

	page = galeon_sidebar_find_page_by_id (sidebar, page_id);
	g_return_val_if_fail (page != NULL, FALSE);

	sidebar->priv->pages = g_list_remove (sidebar->priv->pages,
		       			      (gpointer)page);
	
	l = sidebar->priv->pages;
	new_page = (GaleonSidebarPage *)l->data ?
	           (GaleonSidebarPage *)l->data : NULL;

	if (page)
	{
		galeon_sidebar_select_page (sidebar, new_page->id);
	}

	gtk_widget_destroy (page->item);
	
	return TRUE;
}

gboolean 
galeon_sidebar_select_page (GaleonSidebar *sidebar,
			    const char *page_id)
{
	GaleonSidebarPage *page;

	page = galeon_sidebar_find_page_by_id (sidebar, page_id);
	g_return_val_if_fail (page != NULL, FALSE);
	
	select_page (sidebar, page);
	
	return FALSE;
}

void 
galeon_sidebar_set_content (GaleonSidebar *sidebar,
			    GObject *content)
{
	
	if (GTK_IS_WIDGET(sidebar->priv->content))
	{
		gtk_container_remove(GTK_CONTAINER(sidebar->priv->content_frame),
				     GTK_WIDGET(sidebar->priv->content));
	}
	else if (IS_GALEON_DIALOG(sidebar->priv->content))
	{
		galeon_dialog_remove_embedded (GALEON_DIALOG(sidebar->priv->content));
	}

	sidebar->priv->content = content;

	if (GTK_IS_WIDGET(content))
	{
		gtk_container_add (GTK_CONTAINER(sidebar->priv->content_frame),
				   GTK_WIDGET(content));
	}
	else if (IS_GALEON_DIALOG(content))
	{
		galeon_dialog_show_embedded (GALEON_DIALOG(content),
					     sidebar->priv->content_frame);
	}
}
