/*
 *  Copyright (C) 2002 Jorn Baayen
 *  Copyright (C) 2003 Philip Langdale (Egg port)
 *
 *  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.
 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "statusbar.h"
#include "pixbuf-cache.h"
#include "hig-alert.h"
#include "galeon-shell.h"
#include "page-info-dialog.h"

#include <string.h>
#include <time.h>
#include <gtk/gtkprogressbar.h>
#include <gtk/gtkimage.h>
#include <gtk/gtkframe.h>
#include <gtk/gtktooltips.h>
#include <glib/gi18n.h>
#include <gtk/gtkbutton.h>
#include <libgnomevfs/gnome-vfs-uri.h>

static void statusbar_class_init (StatusbarClass *klass);
static void statusbar_init (Statusbar *t);
static void statusbar_finalize (GObject *object);

static void
popup_icon_clicked_cb (GtkWidget *widget, Statusbar *s);

static void
security_icon_clicked_cb (GtkWidget *widget, Statusbar *s);

static GObjectClass *parent_class = NULL;
static GtkTooltips *_statusbar_tooltips = NULL;

struct StatusbarPrivate
{
	gboolean visibility;

	GtkToggleAction *offline_action;
	GtkWidget *offline_button;
	GtkWidget *offline_icon;

	GtkWidget *security_button;
	GtkWidget *security_icon;

	GtkWidget *progress;

	GtkWidget *popupblock_frame;
	GtkWidget *popupblock_button;
	char *popup_uri;
};

enum {
	REQUEST,	/* request a security info page (and anything we add ...) */
	LAST_SIGNAL
};

static guint signals[LAST_SIGNAL] = { 0 };

GType 
statusbar_get_type (void)
{
        static GType statusbar_type = 0;

        if (statusbar_type == 0)
        {
                static const GTypeInfo our_info =
                {
                        sizeof (StatusbarClass),
                        NULL, /* base_init */
                        NULL, /* base_finalize */
                        (GClassInitFunc) statusbar_class_init,
                        NULL,
                        NULL, /* class_data */
                        sizeof (Statusbar),
                        0, /* n_preallocs */
                        (GInstanceInitFunc) statusbar_init
                };

                statusbar_type = g_type_register_static (GTK_TYPE_STATUSBAR,
						         "Statusbar",
						         &our_info, 0);
        }

        return statusbar_type;

}

static void
statusbar_class_init (StatusbarClass *klass)
{
        GObjectClass *object_class = G_OBJECT_CLASS (klass);

        parent_class = g_type_class_peek_parent (klass);

        object_class->finalize = statusbar_finalize;

	signals[REQUEST] =
		g_signal_new ("request",
			G_OBJECT_CLASS_TYPE (klass),
			G_SIGNAL_RUN_FIRST,
			G_STRUCT_OFFSET (StatusbarClass, request),
			NULL, NULL,
			g_cclosure_marshal_VOID__UINT,
			G_TYPE_NONE, 1,
			G_TYPE_UINT);
}

static GtkWidget *
create_compact_image_button (const char *stock_id)
{
	GtkWidget      *button;
	GtkRcStyle     *rcstyle;
	GtkWidget      *image;
	GtkRequisition  size;

	/* create a button suitable for packing in a statusbar */
	button = gtk_button_new ();
	gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
	GTK_WIDGET_UNSET_FLAGS(button, GTK_CAN_FOCUS);

	/* minimize the amount of white space around the image, +2 is to avoid
	 * weird cropping (where does that come from?) */
	rcstyle = gtk_rc_style_new ();
	rcstyle->xthickness = rcstyle->ythickness = 0;
	gtk_widget_modify_style (button, rcstyle);
	gtk_rc_style_unref (rcstyle);

	image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU);
	gtk_widget_size_request (image, &size);
	gtk_widget_set_size_request (button, size.width + 2, size.height);
	gtk_container_add (GTK_CONTAINER (button), image);

	return button;
}

static void
update_offline_icon (Statusbar *t)
{
	const char *tooltips[] = {
		N_("Galeon is currently online. Click to work offline."),
		N_("Galeon is currently offline. Click to work online.")
	};
	gboolean offline;
	
	offline = gtk_toggle_action_get_active (t->priv->offline_action);

	gtk_image_set_from_stock (GTK_IMAGE (t->priv->offline_icon),
				  offline ? STOCK_DISCONNECT
					  : STOCK_CONNECT,
				  GTK_ICON_SIZE_MENU);
	gtk_tooltips_set_tip (_statusbar_tooltips, t->priv->offline_button, 
			      _(tooltips[!!offline]), NULL);
}

static void
create_statusbar_offline_icon (Statusbar *s, GtkToggleAction *action)
{
	GtkWidget *button;

	button = create_compact_image_button (STOCK_CONNECT);
	s->priv->offline_action = g_object_ref (action);
	s->priv->offline_icon = GTK_BIN(button)->child;
	s->priv->offline_button = button;

	g_signal_connect_swapped(s->priv->offline_action, "toggled",
				 G_CALLBACK(update_offline_icon), s);
	g_signal_connect_swapped(s->priv->offline_button, "clicked",
				 G_CALLBACK(gtk_action_activate), action);

	gtk_box_pack_start (GTK_BOX(s), button, FALSE, FALSE, 0);
	gtk_box_reorder_child (GTK_BOX(s), button, 0);

	update_offline_icon (s);

	gtk_widget_show_all (button);
}

static void
create_statusbar_security_icon (Statusbar *s)
{
	GtkWidget *button, *frame;

	frame = gtk_frame_new (NULL);
        gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);

	button = create_compact_image_button (GALEON_STOCK_INSECURE);
        s->priv->security_icon   = GTK_BIN(button)->child;
        s->priv->security_button = button;

        gtk_container_add (GTK_CONTAINER (frame), 
                           GTK_WIDGET (s->priv->security_button));
	g_signal_connect(G_OBJECT(s->priv->security_button),
			 "clicked",
			 G_CALLBACK(security_icon_clicked_cb), s);

	gtk_box_pack_end (GTK_BOX(s), frame, FALSE, FALSE, 0);
	
	statusbar_set_security_state (s, FALSE, NULL);
	
        gtk_widget_show_all (frame);
}

static void
create_statusbar_progress (Statusbar *s)
{
	s->priv->progress = gtk_progress_bar_new ();

	gtk_box_pack_end(GTK_BOX(s), s->priv->progress,
			 FALSE, FALSE, 0);

	gtk_widget_show_all (s->priv->progress);
}

static void
create_statusbar_popupblock_icon(Statusbar *s)
{
	GtkWidget *button;

	s->priv->popupblock_frame = gtk_frame_new(NULL);
	gtk_frame_set_shadow_type(GTK_FRAME(s->priv->popupblock_frame), 
				  GTK_SHADOW_IN);

	button = create_compact_image_button (GALEON_STOCK_POPUP_BLOCKED);
	s->priv->popupblock_button = button;

	gtk_container_add(GTK_CONTAINER(s->priv->popupblock_frame), 
			  GTK_WIDGET(s->priv->popupblock_button));
	g_signal_connect(G_OBJECT(s->priv->popupblock_button),
			 "clicked",
			 G_CALLBACK(popup_icon_clicked_cb), s);

	gtk_box_pack_end(GTK_BOX(s), s->priv->popupblock_frame,
			 FALSE, FALSE, 0);
	
	statusbar_set_popup_block(s, FALSE, NULL);
}

static void
statusbar_init (Statusbar *t)
{
	if (!_statusbar_tooltips)
	{
		_statusbar_tooltips = gtk_tooltips_new ();
		g_object_add_weak_pointer (G_OBJECT (_statusbar_tooltips),
					   (gpointer)&_statusbar_tooltips);
	}

	g_object_ref (_statusbar_tooltips);
	gtk_object_sink (GTK_OBJECT (_statusbar_tooltips));

        t->priv = g_new0 (StatusbarPrivate, 1);
	t->priv->visibility = TRUE;
}

static void
statusbar_finalize (GObject *object)
{
	Statusbar *s;

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

	s = STATUSBAR (object);

        g_return_if_fail (s->priv != NULL);

	g_object_unref (s->priv->offline_action);
	
	g_free (s->priv->popup_uri);
        g_free (s->priv);

	g_object_unref (_statusbar_tooltips);

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

GtkWidget *
statusbar_new (GtkToggleAction *offline_action)
{
	Statusbar *s;

	s = STATUSBAR (g_object_new (STATUSBAR_TYPE, NULL));

	create_statusbar_offline_icon (s, offline_action);
	create_statusbar_security_icon (s);
	create_statusbar_popupblock_icon(s);
	create_statusbar_progress (s);
	gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(s),
					  FALSE);

	g_return_val_if_fail (s->priv != NULL, NULL);

	return GTK_WIDGET(s);
}

void
statusbar_set_visibility (Statusbar *t, 
			  gboolean visibility)
{
	if (visibility == t->priv->visibility) return;
	
	t->priv->visibility = visibility;

	if (visibility)
		gtk_widget_show(GTK_WIDGET(t));
	else
		gtk_widget_hide(GTK_WIDGET(t));
}

void
statusbar_set_security_state (Statusbar *t, 
			      gboolean state,
			      const char *tooltip)
{
        gtk_image_set_from_stock (GTK_IMAGE (t->priv->security_icon),
				  state ? GALEON_STOCK_SECURE : GALEON_STOCK_INSECURE,
				  GTK_ICON_SIZE_MENU);

	gtk_tooltips_set_tip (_statusbar_tooltips, t->priv->security_button, 
			      tooltip, NULL);
}

void
statusbar_set_progress (Statusbar *t, 
			int progress)
{
	if (progress == -1)
	{
		gtk_progress_bar_pulse (GTK_PROGRESS_BAR(t->priv->progress));
	}
	else
	{
		gdouble tmp;
		tmp = ((gdouble) progress) / 100;
		if (tmp > 1)
		{
			tmp = 1;
		}
		if (tmp < 0)
		{
			tmp = 0;
		}
		gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(t->priv->progress),
					       tmp);
	}
}

void
statusbar_set_message (Statusbar *s,
		       const char *message)
{
	g_return_if_fail (message != NULL);

	gtk_statusbar_pop(GTK_STATUSBAR(s), 0);
	gtk_statusbar_push(GTK_STATUSBAR(s), 0, message);
}

void
statusbar_set_popup_block(Statusbar *s, 
			  gboolean state,
			  const char *uri)
{
	char *tooltip = NULL;

	state ? gtk_widget_show_all(s->priv->popupblock_frame) :
		gtk_widget_hide_all(s->priv->popupblock_frame);

	g_free (s->priv->popup_uri);

	if (!uri)
	{
		s->priv->popup_uri = NULL;
	}
	else 
	{
		s->priv->popup_uri = gnome_vfs_uri_make_full_from_relative (uri, "/");
	}	

	if (s->priv->popup_uri)
		tooltip = g_strdup_printf (_("A popup from %s was blocked. "
					     "Click to allow popups from this site."),
					   s->priv->popup_uri);

	gtk_tooltips_set_tip(_statusbar_tooltips, s->priv->popupblock_button, 
			     tooltip, NULL);
	g_free(tooltip);
}


static void
popup_dialog_response_cb (GtkWidget *dialog, int response, 
			  const char *popup_uri)
{
	if (response == 1)
	{
		GaleonEmbedShell *embed_shell;

		embed_shell = galeon_shell_get_embed_shell (galeon_shell);
		g_return_if_fail (embed_shell != NULL);

		galeon_embed_shell_set_permission(embed_shell,
						  popup_uri,
						  POPUPS_PERMISSION, TRUE);
	}
	gtk_widget_destroy (dialog);
}


static void
popup_icon_clicked_cb (GtkWidget *widget, Statusbar *s)
{
	GtkWidget *dialog;
	GtkWidget *window;
	char *tt_uri;

	if (!s->priv->popup_uri) return;

	window = gtk_widget_get_toplevel (GTK_WIDGET (s));
	dialog = hig_alert_new (GTK_WINDOW (window),
				GTK_DIALOG_DESTROY_WITH_PARENT,
				HIG_ALERT_CONFIRMATION,
				NULL,
				NULL,
				GTK_STOCK_CANCEL,
				GTK_RESPONSE_CANCEL,
				_("_Allow Popups"),
				1,
				NULL);
	gtk_dialog_set_default_response (GTK_DIALOG (dialog), 1);
	
	tt_uri = g_strdup_printf( "\"<tt>%s</tt>\"", s->priv->popup_uri);

	hig_alert_set_primary_printf (HIG_ALERT (dialog),
				      _("Allow popups from %s?"), s->priv->popup_uri);

	hig_alert_set_secondary_printf (HIG_ALERT (dialog),
					_("A popup from %s was blocked. You can allow popups from "
					  "this site to be shown in the future."),
					tt_uri);
	g_free (tt_uri);

	g_signal_connect_data (G_OBJECT(dialog),
			       "response",
			       G_CALLBACK(popup_dialog_response_cb),
			       g_strdup (s->priv->popup_uri),
			       (GClosureNotify)g_free,
			       (GConnectFlags)0);

	gtk_widget_show (dialog);
}


static void
security_icon_clicked_cb (GtkWidget *widget, Statusbar *self)
{
	g_signal_emit (G_OBJECT(self), signals[REQUEST], 0, STATUSBAR_SHOW_SECURITY_INFO);
}
