/*
 *  gtksourcecalltipswindow.c
 *
 *  Copyright (C) 2004 Paolo Maggi 
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Library General Public License as published by
 *  the Free Software Foundation; either version 2 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 Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library 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 "gtksourcecalltipswindow.h"

#include <gtk/gtkwidget.h>
#include <gdk/gdk.h>

#define DATA_KEY "CallTipsWindowData"
#define MAX_TIPS 1

typedef struct _CallTipsWindowData CallTipsWindowData;

struct _CallTipsWindowData
{
	GSList    *tips;
	gint       num_of_tips;

	gint       position;

	GtkWidget *labels[MAX_TIPS];
	GtkWidget *up_arrow;
	GtkWidget *down_arrow;
};

static void update_tips 	(GtkSourceCallTipsWindow *window,
	     			 CallTipsWindowData      *data);

static void 
free_data (CallTipsWindowData *data)
{
	if (data->tips != NULL)
	{
		g_slist_foreach (data->tips, (GFunc)g_free, NULL);
		g_slist_free (data->tips);
	}

	g_free (data);
}

static gboolean 
down_arrow_pressed (GtkWidget	            *widget,
		    GdkEventButton          *event,
		    GtkSourceCallTipsWindow *window)
{
	CallTipsWindowData *data;

	data = (CallTipsWindowData *)g_object_get_data (G_OBJECT (window),
							DATA_KEY);
	g_return_val_if_fail (data != NULL, FALSE);

	if ((data->position + MAX_TIPS) < data->num_of_tips)
		++data->position;

	update_tips (window, data);
	
	return FALSE;
}

static gboolean 
up_arrow_pressed (GtkWidget	          *widget,
		  GdkEventButton          *event,
		  GtkSourceCallTipsWindow *window)
{
	CallTipsWindowData *data;

	data = (CallTipsWindowData *)g_object_get_data (G_OBJECT (window),
							DATA_KEY);
	g_return_val_if_fail (data != NULL, FALSE);

	if (data->position > 0)
		--data->position;

	update_tips (window, data);

	return FALSE;
}

static gboolean
paint_window (GtkWidget *widget)
{
	gtk_paint_flat_box (widget->style,
			    widget->window, GTK_STATE_NORMAL,
			    GTK_SHADOW_OUT, NULL,
			    widget, "tooltip",
			    0, 0, -1, -1);

	return FALSE;
}

GtkWidget *
gtk_source_call_tips_window_new (void)
{
	GtkWidget          *window;
	GtkWidget          *hbox;
	GtkWidget          *vbox;
	GtkWidget          *eventbox;
	CallTipsWindowData *data;
	gint                i;

	data = g_new0 (CallTipsWindowData, 1);

	window = gtk_window_new (GTK_WINDOW_POPUP);
	gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
	gtk_widget_set_name (window, "gtksourceviewcalltipswindow");
	gtk_widget_set_app_paintable (window, TRUE);

	/* FIXME: should be themable ? - Paolo (March 24, 2004) */
	gtk_container_set_border_width (GTK_CONTAINER (window), 4);

	hbox = gtk_hbox_new (FALSE, 2);
	gtk_container_add (GTK_CONTAINER (window), hbox);

	vbox = gtk_vbox_new (TRUE, 2);
	gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);

	for (i = 0; i < MAX_TIPS; ++i)
	{
		data->labels[i] = gtk_label_new ("<i>empty</i>");
  		gtk_box_pack_start (GTK_BOX (vbox), data->labels[i], FALSE, FALSE, 0);
  		gtk_label_set_use_markup (GTK_LABEL (data->labels[i]), TRUE);
  		gtk_label_set_justify (GTK_LABEL (data->labels[i]), GTK_JUSTIFY_LEFT);
  		gtk_misc_set_alignment (GTK_MISC (data->labels[i]), 0, 0.5);
	}
  
	vbox = gtk_vbox_new (FALSE, 0);
  	gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);

	eventbox = gtk_event_box_new ();
	gtk_event_box_set_visible_window (GTK_EVENT_BOX (eventbox), FALSE);
	gtk_box_pack_start (GTK_BOX (vbox), eventbox, FALSE, FALSE, 0);

	data->up_arrow = gtk_arrow_new (GTK_ARROW_UP, GTK_SHADOW_OUT);
  	gtk_container_add (GTK_CONTAINER (eventbox), data->up_arrow);
	gtk_misc_set_alignment (GTK_MISC (data->up_arrow), 0.5, 0.1);

	g_signal_connect (eventbox,
			  "button_press_event",
			  G_CALLBACK (up_arrow_pressed),
			  window);

	eventbox = gtk_event_box_new ();
	gtk_event_box_set_visible_window (GTK_EVENT_BOX (eventbox), FALSE);
	gtk_box_pack_end (GTK_BOX (vbox), eventbox, FALSE, FALSE, 0);

	data->down_arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT);
  	gtk_container_add (GTK_CONTAINER (eventbox), data->down_arrow);
	gtk_misc_set_alignment (GTK_MISC (data->down_arrow), 0.5, 0.9);

	g_signal_connect (eventbox,
			  "button_press_event",
			  G_CALLBACK (down_arrow_pressed),
			  window);

	g_signal_connect (window,
			  "expose_event",
			  G_CALLBACK (paint_window),
			  NULL);

	gtk_widget_show_all (hbox);

	for (i = 1; i < MAX_TIPS; ++i)
	{
		gtk_widget_hide (data->labels[i]);
	}

	gtk_widget_hide (data->up_arrow);
	gtk_widget_hide (data->down_arrow);

	g_object_set_data_full (G_OBJECT (window),
				DATA_KEY,
				data,
				(GDestroyNotify)free_data);

	
	return window;
}

static void 
update_tips (GtkSourceCallTipsWindow *window,
	     CallTipsWindowData      *data)
{
	GSList *tips;
	gint    i;

	if (data == NULL)
	{
		data = (CallTipsWindowData *)g_object_get_data (G_OBJECT (window),
							DATA_KEY);
		g_return_if_fail (data != NULL);
	}

	if (data->position == 0)
		gtk_widget_hide (data->up_arrow);
	else
		gtk_widget_show (data->up_arrow);

	
	if ((data->position + MAX_TIPS) > (data->num_of_tips - 1))
		gtk_widget_hide (data->down_arrow);
	else
		gtk_widget_show (data->down_arrow);

	tips = g_slist_nth (data->tips, data->position);

	i = 0;
	while (i < MAX_TIPS)
	{
		if (tips != NULL)
		{
			gchar *tip = (gchar *)tips->data;
			g_return_if_fail (tip != NULL);

			gtk_label_set_markup (GTK_LABEL (data->labels[i]), tip);
			gtk_widget_show (data->labels[i]);
			
			tips = g_slist_next (tips);
		}
		else
		{
			gtk_widget_hide (data->labels[i]);
		}

		++i;
	}
}

void
gtk_source_call_tips_window_set_tips (GtkSourceCallTipsWindow *window,
				      GSList                  *tips,
				      gboolean                 force_reset_position)
{
	CallTipsWindowData *data;
	gint                len;

	g_return_if_fail (window != NULL);
	g_return_if_fail (tips != NULL);
	g_return_if_fail (g_slist_length (tips) >= 1);

	data = (CallTipsWindowData *)g_object_get_data (G_OBJECT (window),
							DATA_KEY);
	g_return_if_fail (data != NULL);
	
	/* Copy tips to data->tips */

	if (data->tips != NULL)
	{
		g_slist_foreach (data->tips, (GFunc)g_free, NULL);
		g_slist_free (data->tips);
		data->tips = NULL;
	}

	len = 0;
	while (tips != NULL)
	{
		g_return_if_fail (tips->data != NULL);
		data->tips = g_slist_prepend (data->tips,
					      g_strdup (tips->data));
		tips = g_slist_next (tips);
		++len;
	}
	data->tips = g_slist_reverse (data->tips);

	if (force_reset_position || (len != data->num_of_tips) || (len <= MAX_TIPS))
	{
		data->position = 0;
	}

	data->num_of_tips = len;

	update_tips (window, data);

	return;
}


