/***************************************************************************
                          notebook.c  -  The main GUI notebook
                          ------------------------------------
    begin                : 2001
    copyright            : (C) 2001-2003 by Tim-Philipp Müller
    email                : t.i.m@orange.net
 ***************************************************************************/

/*
 *       functions to
 *         - create a notebook window
 *         - add a page to the notebook
 *
 */

/***************************************************************************
 *                                                                         *
 *   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 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include <time.h>

#include "global.h"
#include "core-conn.h"
#include "status_page.h"
#include "downloads-view.h"
#include "servers.h"
#include "options_page.h"
#include "search.h"
#include "search.h"
#include "shared_dirs.h"
#include "shared_files.h"
#include "shared_page.h"
#include "stats.h"
#include "uploads_page.h"
#include "options.h"
#include "notebook.h"
#include "colors.h"
#include "icons.h"
#include "misc.h"
#include "mainwindow.h"
#include "misc_strings.h"

#include <gtk/gtkhbox.h>
#include <gtk/gtknotebook.h>
#include <gtk/gtkimage.h>
#include <gtk/gtklabel.h>

/* local variables */

static GtkWidget      *notebook = NULL;

static GSList         *notebook_tab_labels = NULL; /* the text label widgets, so we can switch them on/off */

static GtkWidget      *servers_page = NULL;

static gboolean        servers_page_visible = TRUE;


/* local functions */

static void            notebook_add_page (GtkWidget *tabwidget, GtkWidget *pagewidget);

static void            notebook_page_switched ( GtkWidget       *widget,
                                                GtkNotebookPage *page,
                                                gint             page_num,
                                                gpointer         data );

static GtkWidget      *notebook_create_tab_content (gchar *tabtext, IconName icon);


/*******************************************************************************
 *
 *   notebook_show_hide_tab_label_text
 *
 *   show/hide tab text according to 'option_main_notebook_tabs_show_text'
 *
 ***/

void
notebook_show_hide_tab_label_text (void)
{
	GSList    *node;
	gboolean   hide_tab_txt_leftright;
	gboolean   notebook_tab_pos_is_leftright;
	guint      notebook_tab_pos, curpage;

	g_return_if_fail ( notebook != NULL );

	notebook_tab_pos              = opt_get_int(OPT_GUI_MAIN_NOTEBOOK_TAB_POS);
	hide_tab_txt_leftright        = opt_get_bool(OPT_GUI_MAIN_NOTEBOOK_HIDE_TAB_TEXT_LEFT_RIGHT);
	notebook_tab_pos_is_leftright = ( notebook_tab_pos == GTK_POS_LEFT || notebook_tab_pos == GTK_POS_RIGHT );

	for ( node = notebook_tab_labels;  node != NULL;  node = node->next )
	{
		GtkWidget *item = (GtkWidget*) node->data;

		if ( (!item) || !GTK_IS_WIDGET(item) )
			continue;

		if ( hide_tab_txt_leftright && notebook_tab_pos_is_leftright )
			gtk_widget_hide(item);
		else
			gtk_widget_show(item);

		if (item->parent)	/* parent is the hbox */
			gtk_container_check_resize(GTK_CONTAINER(item->parent));
	}

	/* make sure tabs are really re-sized - switch to last page and back */
	curpage = gtk_notebook_get_current_page (GTK_NOTEBOOK(notebook));
	gtk_notebook_set_current_page (GTK_NOTEBOOK(notebook),-1);
	gtk_notebook_set_current_page (GTK_NOTEBOOK(notebook),curpage);
}


/*******************************************************************************
 *
 *   notebook_page_switched
 *
 *   Event that occurs when a different page is now the focus.
 *
 *   Also called via notebook_switch_to_current_page() from
 *    main.c/general_update_timer() to update statusbar info
 *
 ***/

static void
notebook_page_switched (GtkWidget *widget, GtkNotebookPage *page, gint page_num, gpointer data)
{
	if (!gui_core_conn_is_alive(core))
		return;

	page_num += (guint) ( !servers_page_visible && page_num >= NOTEBOOK_PAGE_SERVERS );

	switch (page_num)
	{
		case NOTEBOOK_PAGE_DOWNLOADS:
			stats_print_download_stats_line();
		break;

		case NOTEBOOK_PAGE_UPLOADS:
			stats_print_upload_stats_line();
		break;

		case NOTEBOOK_PAGE_STATUS:
			status_page_print_clientID_info(NULL);
		break;

		case NOTEBOOK_PAGE_OPTIONS:
		{
			/* make sure that if fields are changed, but not
			 * confirmed with OK, the old values reappear */
			options_update_option_widgets();
		}
		break;

		case NOTEBOOK_PAGE_SERVERS:
			servers_show_dead_alive_stats();
		break;

		case NOTEBOOK_PAGE_SHARED:
		{
			shared_files_print_shared_stats_message();
		}
		break;

		default:
		break;
	}
}




/*******************************************************************************
 *
 *   notebook_add_page
 *
 *   Add a page to the main notebook
 *
 *   tabwidget:  the widget that is going to go into the tab (icon+text hbox usually)
 *   pagewidget: the widget that is going to go into the notebook page
 *
 ***/

static void
notebook_add_page (GtkWidget *tabwidget, GtkWidget *pagewidget)
{
	g_return_if_fail (notebook   != NULL);
	g_return_if_fail (tabwidget  != NULL);
	g_return_if_fail (pagewidget != NULL);

	if (!opt_get_bool(OPT_GUI_NO_GREEN))
	{
		gtk_widget_set_style (pagewidget, style_notebook_page);
		gtk_widget_set_style (notebook, style_notebook_page);
	}

	gtk_notebook_append_page (GTK_NOTEBOOK(notebook), pagewidget, tabwidget);
}



/*******************************************************************************
 *
 *   notebook_create_tab_content
 *
 *   Creates a hbox with an icon and a label
 *    and saves the label widget, so we can hide
 *    the labels when the tabs are on the side of
 *    the notebook.
 *
 ***/

static GtkWidget *
notebook_create_tab_content (gchar *tabtext, IconName icon)
{
	GtkWidget *hbox, *pix, *label;

	g_return_val_if_fail (tabtext!=NULL,NULL);

	pix = gtk_image_new_from_pixbuf (get_icon (icon));
	gtk_widget_show(pix);

	label = gtk_label_new (UTF8_SHORT_PRINTF("%s",tabtext));
	gtk_widget_show(label);

	hbox = gtk_hbox_new(FALSE,0);
	gtk_box_pack_start (GTK_BOX(hbox), pix,   FALSE, FALSE, 0);
	gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 0);

	/* We want to save the notebook tab label widgets so we can
	 *  switch them on or off when the notebook tabs are rotated */
	notebook_tab_labels = g_slist_append (notebook_tab_labels, (gpointer)label);

	return hbox;
}





/******************************************************************************
 *
 *   onOvernetStatus
 *
 *   removes servers page if it is part of the notebook
 *
 ******************************************************************************/

static void
onOvernetStatus (GuiCoreConn *conn, const gchar *idstr, const gchar *fwstatus, gpointer data)
{
	GtkWidget *page, *tab;

	g_return_if_fail ( notebook     != NULL );
	g_return_if_fail ( servers_page != NULL );

	if (!servers_page_visible)
		return;

	page = gtk_notebook_get_nth_page (GTK_NOTEBOOK(notebook), NOTEBOOK_PAGE_SERVERS);
	g_return_if_fail ( page != NULL );

	tab = gtk_notebook_get_tab_label (GTK_NOTEBOOK(notebook), page);
	g_return_if_fail ( tab != NULL );

	/* gtk_widget_unparent() will unref and destroy the page and all widgets in it */
	gtk_container_remove (GTK_CONTAINER(notebook), page);
	gtk_widget_unparent(GTK_WIDGET(page)); /* TODO: do we need this? */

	servers_page_visible = FALSE;
}

/******************************************************************************
 *
 *   onHybridStatus
 *
 *   removes servers page if it is part of the notebook
 *
 ******************************************************************************/

static void
onHybridStatus (GuiCoreConn *conn, const gchar *idstr, const gchar *fwstatus, gpointer data)
{
	if (servers_page_visible)
		return;
	
	notebook_set_overnet_mode(FALSE);
}

/******************************************************************************
 *
 *   onCoreConnStatus
 *
 ******************************************************************************/

static void
onCoreConnStatus (GuiCoreConn *conn, guint status, gpointer data)
{
	static guint laststatus = G_MAXUINT;

	switch (status)
	{
		case CONN_STATUS_COMMUNICATING:
			if (laststatus != status)
				notebook_set_page(NOTEBOOK_PAGE_DOWNLOADS);
			break;

		/* Show server page again (will be hidden
		 *  again later if it's an overnet core  */
		case CONN_STATUS_AUTHENTICATING:
		{
			if (servers_page_visible == FALSE)
			{
				GtkWidget *tab;

				/* XXX - does the previous tab get destroyed/unrefed when we remove the page? */
				tab  = notebook_create_tab_content (_(" Servers "), ICON_TAB_SERVERS);

				gtk_notebook_insert_page (GTK_NOTEBOOK(notebook), servers_page, tab, NOTEBOOK_PAGE_SERVERS);
				notebook_show_hide_tab_label_text();

				servers_page_visible = TRUE;
			}
		}
		break;

		default:
			notebook_set_page(NOTEBOOK_PAGE_STATUS);
			break;
	}

	laststatus = status;
}


/*******************************************************************************
 *
 *  onTimeoutUpdateStatusBar
 *
 *******************************************************************************/

static gboolean
onTimeoutUpdateStatusBar (gpointer foo)
{
	if (gui_core_conn_is_alive(core))
	{
		/* update info in the statusbar (=switch to current page) */
		notebook_set_page(-1);
	}
	return TRUE; /* call again */
}

/*******************************************************************************
 *
 *   notebook_create_disabled_page
 *
 *******************************************************************************/

static GtkWidget *
notebook_create_disabled_page (void)
{
	GtkWidget *w;
	w = gtk_label_new("\n\nThis page has been disabled from the command line.\n");
	gtk_widget_show(w);
	return w;
}


/*******************************************************************************
 *
 *   notebook_create
 *
 *   Create a new notebook and add pages to it.
 *
 *   Returns the newly-created notebook widget
 *
 ***/

GtkWidget *
notebook_create (GtkPositionType pos, guint flags_disable_pages)
{
	GtkWidget	*tab, *page;

	notebook = gtk_notebook_new();

	gtk_notebook_set_scrollable (GTK_NOTEBOOK(notebook),TRUE);

	g_signal_connect (G_OBJECT (notebook), "switch_page",
	                  G_CALLBACK(notebook_page_switched), NULL);

	gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), pos);

	gtk_container_set_border_width (GTK_CONTAINER (notebook), 2);

	/* fill notebook with pages */
	if ((flags_disable_pages & (1 << NOTEBOOK_PAGE_DOWNLOADS)))
		page = notebook_create_disabled_page();
	else
		page = downloads_view_page_create();
	tab  = notebook_create_tab_content (_(" Downloads "), ICON_TAB_DOWNLOADS);
	notebook_add_page (tab, page);

	if ((flags_disable_pages & (1 << NOTEBOOK_PAGE_UPLOADS)))
		page = notebook_create_disabled_page();
	else
		page = uploads_page_create();
	tab  = notebook_create_tab_content (_(" Uploads "), ICON_TAB_UPLOADS);
	notebook_add_page (tab, page);

	if ((flags_disable_pages & (1 << NOTEBOOK_PAGE_SEARCH)))
		page = notebook_create_disabled_page();
	else
		page = search_create_page();
	tab  = notebook_create_tab_content (_(" Search "), ICON_TAB_SEARCH);
	notebook_add_page (tab, page);

	if ((flags_disable_pages & (1 << NOTEBOOK_PAGE_SERVERS)))
		servers_page = notebook_create_disabled_page();
	else
		servers_page = servers_page_create();
	/* one ref for us so the page doesn't get destroyed when we
	 * remove it from the notebook when in overnet mode */
	g_object_ref(G_OBJECT(servers_page));
	tab  = notebook_create_tab_content (_(" Servers "), ICON_TAB_SERVERS);
	notebook_add_page (tab, servers_page);
	/* make sure that the servers page is destroyed when the notebook
	 * is destroyed (i.e. our referenced is removed then) */
	g_object_set_data_full (G_OBJECT(notebook), "foo92", G_OBJECT(servers_page), g_object_unref);

	page = status_page_create();
	tab  = notebook_create_tab_content (_(" Status "), ICON_TAB_STATUS);
	notebook_add_page (tab, page);

	page = options_page_create();
	tab  = notebook_create_tab_content (_(" Options "), ICON_TAB_OPTIONS);
	notebook_add_page (tab, page);

	if ((flags_disable_pages & (1 << NOTEBOOK_PAGE_SHARED)))
		page = notebook_create_disabled_page();
	else
		page = shared_page_create();
	tab  = notebook_create_tab_content (_(" Shared "), ICON_TAB_SHARED);
	notebook_add_page (tab, page);

	if ((flags_disable_pages & (1 << NOTEBOOK_PAGE_STATS)))
		page = notebook_create_disabled_page();
	else
		page = stats_create_page();
	tab  = notebook_create_tab_content (_(" Statistics "), ICON_TAB_STATS);
	notebook_add_page (tab, page);

	notebook_show_hide_tab_label_text();

	// shortly switch to status page once in order to avoid gdkwindow assertion
	// 	failure on first ed2k-link write to it (don't ask me why), then switch
	//	back to first page
	gtk_notebook_set_current_page (GTK_NOTEBOOK(notebook), NOTEBOOK_PAGE_STATUS);
	gtk_notebook_set_current_page (GTK_NOTEBOOK(notebook), 0);

	gtk_widget_show(notebook);

	g_signal_connect(core, "overnet-status",   (GCallback) onOvernetStatus,  NULL);
	g_signal_connect(core, "hybrid-status",   (GCallback) onHybridStatus,  NULL);
	g_signal_connect(core, "core-conn-status", (GCallback) onCoreConnStatus, NULL);

	g_timeout_add(60*1000, (GSourceFunc) onTimeoutUpdateStatusBar, NULL);

	return notebook;
}


/******************************************************************************
 *
 *   notebook_set_page
 *
 *   if pagenum < 0, then it switches to the current page (ie. just updates
 *    the statusbar info; used from main.c/general_update_timer()).
 *
 ***/

void
notebook_set_page (gint pagenum)
{
	guint delta;

	g_return_if_fail ( pagenum < NOTEBOOK_PAGE_LAST );

	if (!notebook)
		return;

	if ( pagenum >= 0 )
	{
		delta = (guint) ( !servers_page_visible && pagenum >= NOTEBOOK_PAGE_SERVERS );
		gtk_notebook_set_current_page (GTK_NOTEBOOK(notebook), pagenum - delta);
		return;
	}

	if (!gui_core_conn_is_alive(core))
		return;

	/* Don't 'switch' to options page if we are already there, because that would mean that all
	 *  the options widgets are reset to the current setting. This could interfere with changes
	 *  that the user has already made, but not yet confirmed with OK... (see bug #739501) */
	delta = (guint) (!servers_page_visible);

	if ( gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook))+delta != NOTEBOOK_PAGE_OPTIONS )
		notebook_page_switched (notebook, NULL, gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)), NULL);
}


/******************************************************************************
 *
 *   notebook_set_tab_pos
 *
 ***/

void
notebook_set_tab_pos (GtkPositionType pos)
{
	if (!notebook)
		return;

	gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), pos);
}

/******************************************************************************
 *
 *   notebook_set_overnet_mode
 *
 *   removes/re-adds servers page
 *
 ***/

void
notebook_set_overnet_mode (gboolean overnet)
{
	GtkWidget *page, *tab;

	g_return_if_fail ( notebook     != NULL );
	g_return_if_fail ( servers_page != NULL );

	if ( !overnet == servers_page_visible )
		return;

	page = gtk_notebook_get_nth_page (GTK_NOTEBOOK(notebook), NOTEBOOK_PAGE_SERVERS);
	g_return_if_fail ( page != NULL );

	tab = gtk_notebook_get_tab_label (GTK_NOTEBOOK(notebook), page);
	g_return_if_fail ( tab != NULL );

	if (overnet)
	{
		gtk_container_remove (GTK_CONTAINER(notebook), page);
		gtk_widget_unparent(GTK_WIDGET(page));
	}
	else
	{
		GtkWidget *tab;

		/* XXX - does the previous tab get destroyed/unrefed when we remove the page? */
		tab  = notebook_create_tab_content (_(" Servers "), ICON_TAB_SERVERS);

		gtk_notebook_insert_page (GTK_NOTEBOOK(notebook), servers_page, tab, NOTEBOOK_PAGE_SERVERS);
		notebook_show_hide_tab_label_text();
	}

	servers_page_visible = !overnet;
}






