/* mainwindow.c
 *
 * part of ed2k-gtk-gui
 *
 * (c) 2001-2003 Tim-Philipp Muller <t.i.m@orange.net>
 *
 */

/***************************************************************************
 *                                                                         *
 *   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 "global.h"
#include "core-conn.h"
#include "connect-dialog.h"
#include "colors.h"
#include "options.h"
#include "icons.h"
#include "mainwindow.h"
#include "misc.h"
#include "misc_gtk.h"
#include "misc_strings.h"
#include "notebook.h"
#include "reconnect-dialog.h"
#include "statusbar.h"
#include "status_page.h"
#include "toolbar.h"
#include "systray.h"

#include "pipe.h"

#include <string.h>
#include <ctype.h>

#include <gtk/gtkmain.h>
#include <gtk/gtkvbox.h>


/* global variables */

GtkWidget *window = NULL;	/* main window widget */


/* local variables */

enum
{
 TARGET_STRING,
 TARGET_ROOTWIN,
 TARGET_URL
};

static GtkTargetEntry dragtypes[] =
{
  { "STRING",     0, TARGET_STRING },
  { "text/plain", 0, TARGET_STRING },
  { "text/uri-list", 0, TARGET_URL },
  { "application/x-rootwin-drop", 0, TARGET_ROOTWIN }
};


/* functions */

static void            mainwindow_set_title (const gchar *networkname);

static gboolean        onConfigureEvent (GtkWidget *window, GdkEventConfigure *cevent, gpointer data);

static void            mainwindow_set_title (const gchar *networkname);

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

static void            onHybridStatus (GuiCoreConn *conn, const gchar *idstr, const gchar *fwstatus, gpointer data);

static void            onCoreConnStatus (GuiCoreConn *conn, guint status, gpointer data);

/*******************************************************************************
 *
 *   onConfigureEvent
 *
 *   Called when the window position or size changes
 *
 *******************************************************************************/

static gboolean
onConfigureEvent (GtkWidget *window, GdkEventConfigure *cevent, gpointer data)
{
	if ((window) && (window->window))
	{
		GdkRectangle frame_extents;
		gint         x, y;

		gdk_window_get_frame_extents (window->window, &frame_extents);

		x = cevent->x;
		y = cevent->y;

		x -= (cevent->x - frame_extents.x);
		y -= (cevent->y - frame_extents.y);

		opt_set_int (OPT_GUI_WINDOW_POS_X,  x);
		opt_set_int (OPT_GUI_WINDOW_POS_Y,  y);
		opt_set_int (OPT_GUI_WINDOW_WIDTH,  cevent->width);
		opt_set_int (OPT_GUI_WINDOW_HEIGHT, cevent->height);
	}

	return FALSE; /* propagate further */
}


/*******************************************************************************
 *
 *   mainwindow_okay_to_exit
 *
 *   returns TRUE if it's okay to quit
 *
 *******************************************************************************/

gboolean
mainwindow_okay_to_exit (void)
{
	if (opt_get_bool(OPT_GUI_VERIFY_EXIT))
	{
		const gchar  *msg;
		GtkWidget    *dialog;
		gint          ret;

		msg = UTF8_SHORT_PRINTF (_("Do you really want to quit?\n\nCore will be %s\n"),
			  (opt_get_bool(OPT_GUI_SHUTDOWN_CORE_ON_EXIT)) ? _("shutdown.") : _("kept running."));

		dialog = gtk_message_dialog_new ( GTK_WINDOW(window),
		                                  GTK_DIALOG_DESTROY_WITH_PARENT,
		                                  GTK_MESSAGE_WARNING,
		                                  GTK_BUTTONS_YES_NO,
		                                  msg );

		ret = gtk_dialog_run (GTK_DIALOG(dialog));

		gtk_widget_destroy(dialog);

		if (ret != GTK_RESPONSE_YES)
			return FALSE;
	}

	return TRUE;
}


/*******************************************************************************
 *
 *   onDeleteEvent
 *
 *******************************************************************************/

static gboolean
onDeleteEvent (GtkWidget *widget, GdkEvent *event, gpointer data)
{
	if (mainwindow_okay_to_exit() == TRUE)
	{
		gtk_main_quit();
	}

	return TRUE; /* do not destroy window */
}


//
// Drag'n'Drop stuff
//

/*** the next two routines are taken straight from gnome-libs so that the
     gtk-only version can receive drag and drops as well ***/

/**
 * gnome_uri_list_extract_uris:
 * @uri_list: an uri-list in the standard format.
 *
 * Returns a GList containing strings allocated with g_malloc
 * that have been splitted from @uri-list.
 */
static GList*
gnome_uri_list_extract_uris (const gchar* uri_list)
{
	const gchar *p, *q;
	gchar *retval;
	GList *result = NULL;

	g_return_val_if_fail(uri_list != NULL, NULL);

	p = uri_list;

	/* We don't actually try to validate the URI according to RFC
	 * 2396, or even check for allowed characters - we just ignore
	 * comments and trim whitespace off the ends.  We also
	 * allow LF delimination as well as the specified CRLF.
	 */
	while (p) {
		if (*p != '#') {
			while (isspace((int)(*p)))
				p++;

			q = p;
			while (*q && (*q != '\n') && (*q != '\r'))
				q++;

			if (q > p) {
			        q--;
				while (q > p && isspace((int)(*q)))
					q--;

				retval = (char *)g_malloc(q - p + 2);
				strncpy (retval, p, q - p + 1);
				retval[q - p + 1] = '\0';

				result = g_list_prepend(result, retval);
			}
		}
		p = strchr(p, '\n');
		if (p)
			p++;
	}

	return g_list_reverse(result);
}


/**
 * gnome_uri_list_extract_filenames:
 * @uri_list: an uri-list in the standard format
 *
 * Returns a GList containing strings allocated with g_malloc
 * that contain the filenames in the uri-list.
 *
 * Note that unlike gnome_uri_list_extract_uris() function, this
 * will discard any non-file uri from the result value.
 */
static GList*
gnome_uri_list_extract_filenames (const gchar* uri_list)
{
	GList *tmp_list, *node, *result;

	g_return_val_if_fail (uri_list != NULL, NULL);

	result = gnome_uri_list_extract_uris (uri_list);

	tmp_list = result;
	while (tmp_list) {
		gchar *s = (char *)tmp_list->data;

		node = tmp_list;
		tmp_list = tmp_list->next;

//		if (!strncmp (s, "file:", 5)) {
			node->data = g_strdup (s);
//		} else {
//			result = g_list_remove_link(result, node);
//			g_list_free_1 (node);
//		}
		g_free (s);
	}
	return result;
}

// this comes from gnotepad+
//
void win_drag_data_recv(GtkWidget *wgt, GdkDragContext *context, int x, int y,
		   GtkSelectionData *seldata, guint info, guint time,
		   gpointer cbdata)
{
	GList *fnames, *fnp;
	guint count;
	char *buf = NULL;
	unsigned int bufsize = 0, len;

	fnames = gnome_uri_list_extract_filenames((char *)seldata->data);
	count = g_list_length(fnames);
	if (count > 0)
	{
		status_msg (_("GUI: received drag'n'drop.\n"));

		for (fnp = fnames; fnp; fnp = fnp->next, count--)
		{
			len = strlen((char *)(fnp->data));
			buf = g_realloc (buf, bufsize+len+1);
			strcpy (buf+bufsize,(char *)(fnp->data));
			bufsize += len;
		}
		buf[bufsize]=0x00;
		pipe_parse_message (buf);
		G_FREE(buf);
	}
	// Releases all of the resources allocated by @list.
	g_list_foreach (fnames, (GFunc)g_free, NULL);
	g_list_free (fnames);

} /* win_drag_data_recv */


/******************************************************************************
 *
 *   mainwindow_set_title
 *
 ******************************************************************************/

static void
mainwindow_set_title (const gchar *networkname)
{
	gchar *wintitle;

	g_return_if_fail (networkname!=NULL);

	wintitle = g_strdup_printf ("%s (%u)", networkname, option_gui_instance);

	if (option_gui_instance<=0)
	{
		gchar *space = strchr(wintitle, ' ');

		if (space)
			*space = 0x00;
	}

	gtk_window_set_title (GTK_WINDOW (window), wintitle);

	g_free(wintitle);
}

/******************************************************************************
 *
 *   onOvernetStatus
 *
 ******************************************************************************/

static void
onOvernetStatus (GuiCoreConn *conn, const gchar *idstr, const gchar *fwstatus, gpointer data)
{
	mainwindow_set_title ("overnet");
}

/******************************************************************************
 *
 *   onHybridStatus
 *
 ******************************************************************************/

static void
onHybridStatus (GuiCoreConn *conn, const gchar *idstr, const gchar *fwstatus, gpointer data)
{
	mainwindow_set_title ("hybrid");
}

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

static void
onCoreConnStatus (GuiCoreConn *conn, guint status, gpointer data)
{
	/* Set back to donkey mode until we know that it's an overnet core */
	if (status == CONN_STATUS_AUTHENTICATING)
		mainwindow_set_title ("eDonkey2000");
}


/******************************************************************************
 *
 *  mainwindow_create
 *
 *  Creates the main window which is going to contain the notebook and the logo
 *
 ******************************************************************************/

void
mainwindow_create (guint flags_disable_pages)
{
	GtkWidget *vbox, *notebook;
	GList     *icon_list = NULL;

	icons_init();

	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
	g_assert (window!=NULL);

	g_signal_connect(window, "configure-event", (GCallback) onConfigureEvent, NULL);

	mainwindow_set_title ("eDonkey2000");

	/* delete and resize events */
	g_signal_connect (G_OBJECT (window), "delete_event",
	                  G_CALLBACK(onDeleteEvent), NULL);

	g_object_set_data_full(G_OBJECT(window), "my-nullify-window-ptr",
	                       &window, (GDestroyNotify) g_nullify_pointer);


	/* make sure pointer 'window' is set to NULL when the window is destroyed */

	g_object_set_data_full (G_OBJECT(window), "foo1",
	                        &window, (GDestroyNotify)g_nullify_pointer);


	/* set up drag'n'drop */

	gtk_drag_dest_set( window, GTK_DEST_DEFAULT_ALL, dragtypes, 3,
	                   GDK_ACTION_COPY | GDK_ACTION_MOVE);

	g_signal_connect(G_OBJECT(window), "drag_data_received",
	                  G_CALLBACK(win_drag_data_recv), NULL);

	/* set position and size as read in from options file */

	if (opt_get_bool (OPT_GUI_WINDOW_SAVE_POS_AND_SIZE))
	{
		gtk_window_set_default_size (GTK_WINDOW (window),
		                             opt_get_int(OPT_GUI_WINDOW_WIDTH),
		                             opt_get_int(OPT_GUI_WINDOW_HEIGHT));

		gtk_window_move (GTK_WINDOW (window),
		                 opt_get_int (OPT_GUI_WINDOW_POS_X),
		                 opt_get_int (OPT_GUI_WINDOW_POS_Y));
	}
	else
	{
		gtk_window_set_default_size (GTK_WINDOW (window),
		                             (gdk_screen_width ()*4)/5,
		                             (gdk_screen_height ()*3)/4);
	}

	gtk_widget_show (window);


	(void) gui_systray_init(window);

	/* create vbox to hold toolbar, notebook and statusbar */
	vbox = gtk_vbox_new (FALSE, 0);
	gtk_widget_show (vbox);
	gtk_container_add (GTK_CONTAINER (window), vbox);

	gtk_box_pack_start (GTK_BOX (vbox), toolbar_create(window), FALSE, FALSE, 0);

	/* create the window's notebook */
	notebook = notebook_create (opt_get_int(OPT_GUI_MAIN_NOTEBOOK_TAB_POS),
	                            flags_disable_pages);
	gtk_box_pack_start (GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
	gtk_box_pack_start (GTK_BOX(vbox), statusbar_create(), FALSE, FALSE, 0);

	if (!opt_get_bool(OPT_GUI_NO_GREEN))
	{
		gtk_widget_set_style (window, style_dark_green_background);
		statusbar_set_styles();
		toolbar_set_styles();
	}

	if ( !opt_get_bool(OPT_GUI_NO_APP_ICON) )
	{
		icon_list = g_list_append (icon_list, get_icon(ICON_ED2K_GTK_GUI));

		gtk_window_set_icon_list (GTK_WINDOW(window), icon_list);
	}

	connect_dialog_create(window);
	reconnect_dialog_create(window);

	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);
}


