/***************************************************************************
                                main..c
                                -------
    begin                : 2001
    copyright            : (C) 2001-2003 by Tim-Philipp Müller
    email                : t.i.m at orange dot 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.                                   *
 *                                                                         *
 ***************************************************************************/

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

#include <gnet.h>

#include "blacklist.h"
#include "colors.h"
#include "connect-dialog.h"
#include "core-conn.h"
#include "global.h"
#include "linkhandler.h"
#include "mainwindow.h"
#include "misc.h"
#include "misc_gtk.h"
#include "notebook.h"
#include "options.h"
#include "pipe.h"
#include "signal_handler.h"
#include "servers.h"
#include "status_page.h"
#include "statusbar.h"

/* standard stuff */

#ifdef G_OS_UNIX
# include <unistd.h>
# include <sys/stat.h>
# include <sys/types.h>
# include <sys/time.h>
# include <limits.h>
# include <signal.h>
#endif

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

#include <gtk/gtkmain.h>

#if defined(G_OS_UNIX) && defined(ENABLE_NLS)
# include <locale.h>
#endif

static gchar  *main_ed2k_link_passed_on_commandline = NULL;

static guint   flags_disable_pages;  /* 0 */

/* functions */

static void    print_helpscreen (const gchar *extramsg, gint exitcode);

static void    main_parse_commandline_args (gint argc, gchar **argv);

static void    main_parse_commandline_args (gint argc, gchar **argv);

static void    auto_connect (void);

static void    check_uid (void);

static void    auto_spawn (void);


/******************************************************************************
 *
 *   print_helpscreen
 *
 ******************************************************************************/

static void
print_helpscreen (const gchar *extramsg, gint exitcode)
{
	fprintf (stderr, "%s\n\n", extramsg);
	g_print ("%s %s %s\n", _("GUI for Overnet and eDonkey2000 (http://www.eDonkey2000.com) - build"), __DATE__, __TIME__);
	g_print ("(c) 2001-2003 Tim-Philipp Muller <tim@edonkey2000.com>\n\n");
	g_print ("%s\n\n", _("There are NO command line arguments you HAVE to specifiy."));
	g_print ("%s\n", _("Optional command line options:\n"));
	g_print ("%s\n", _("-p path\t\tspecifies the path which shall be used for the gui config files\n"));
	g_print (_("-n num\t\tspecifies 'instance' of GUI if you want to run multiple instances\n"
	           "\t\t\tof the GUI at the same time and keep separate config and stats files\n"
	           "\t\t\tfor them. e.g.: if num=2, then 'gui_options.2' is used\n"
		         "\t\t\t(filter+blacklist files will be shared unless you specify different dirs)\n\n"));

	exit(exitcode);
}


/******************************************************************************
 *
 *   main_parse_commandline_args
 *
 ******************************************************************************/

static void
main_parse_commandline_args (gint argc, gchar **argv)
{
	gchar *unrecognised = _("UNRECOGNISED COMMAND-LINE OPTION");
	guint i;

	/* any args at all? */
	if (argc<=1)
		return;

	i = 1;
	while (i < argc  &&  argv[1] != NULL  &&  *(argv[1]) != 0x00)
	{
		gchar *token = argv[i];

		if (token[0] == '-')
		{
			while (token[0] == '-') /* allow '-h' and '--help' for example */
				++token;

			switch (token[0])
			{
				case 'h':
					print_helpscreen("", 0);
				break;

				case 'c':
				case 's':
				case 'a':
				case 'i':
					g_printerr ("The '-%c' option is no longer supported.\n", token[0]);
				break;

				case 'p':	/* specify path where config files are stored */
				{
					if (token[1]==0x00)	/* -p /home/joe/ed2k/ variant */
					{
						if (argc>=(1+i+1))
						{
							opt_set_prefpath(argv[i+1]);

							i++;
						}
						else print_helpscreen (_("The '-p' option requires an extra parameter"),1);
					}
					else opt_set_prefpath(token+1);
				}
				break;

				case 'n':	/* specify 'instance' of GUI */
				{
					if (token[1]==0x00)	// case '-n 2'
					{
						if (argc>=(1+i+1))
						{
							option_gui_instance = atoi(argv[i+1]);
							i++;
						} else print_helpscreen (_("The '-n' option requires an extra parameter"),1);
					} else option_gui_instance = atoi(token+1);
				}
				break;

				case 'd':
				{
					guint flag = 0;

					if (strcmp(token, "disable-dl-page") == 0)
						flag = (1 << NOTEBOOK_PAGE_DOWNLOADS);
					else if (strcmp(token, "disable-ul-page") == 0)
						flag = (1 << NOTEBOOK_PAGE_UPLOADS);
					else if (strcmp(token, "disable-search-page") == 0)
						flag = (1 << NOTEBOOK_PAGE_SEARCH);
					else if (strcmp(token, "disable-shared-page") == 0)
						flag = (1 << NOTEBOOK_PAGE_SHARED);
					else if (strcmp(token, "disable-stats-page") == 0)
						flag = (1 << NOTEBOOK_PAGE_STATS);

					flags_disable_pages |= flag;
					
					if (flag != 0)
						break;	
				}
				/* fall through */
				
				default:
				{
					fprintf (stderr, "---> '%s' <--- ", token);
					print_helpscreen(unrecognised,1);
				}
				break;
			}
		}
		else
		{
			if (g_ascii_strncasecmp(token,"ed2k:",5) == 0)
			{
				main_ed2k_link_passed_on_commandline = g_strdup(token);
			}
			else
			{
				fprintf (stderr, "---> '%s' <--- ", token);
				print_helpscreen(unrecognised,1);
			}
		}

		++i;
	}
}


/**************************************************************************
 *
 *   auto_connect
 *
 *   Auto-connects to the core on start-up if option is set
 *
 **************************************************************************/

static void
auto_connect (void)
{
	if (!opt_get_bool(OPT_GUI_AUTO_CONNECT_TO_CORE_ON_STARTUP))
		return;

	/* The core connection callback will handle the rest */
	if (opt_get_bool (OPT_GUI_DEFAULT_REMOTE_CONNECT))
	{
		status_warning (_("Auto-connecting to %s:%u ...\n"), 
		                opt_get_str(OPT_GUI_DEFAULT_CORE_HOST), 
		                opt_get_int(OPT_GUI_DEFAULT_CORE_PORT));

		gui_core_conn_connect (core, opt_get_str(OPT_GUI_DEFAULT_CORE_HOST),
		                             opt_get_int(OPT_GUI_DEFAULT_CORE_PORT),
		                             opt_get_str(OPT_GUI_DEFAULT_CORE_USER),
		                             opt_get_str(OPT_GUI_DEFAULT_CORE_PASS));
	}
	else
	{
		guint  port = 0;
		gchar *cookie = NULL;

		if (connect_dialog_local_core_running (&port, &cookie))
		{
			status_warning (_("Auto-connecting to %s:%u ...\n"), "127.0.0.1", port);
			gui_core_conn_connect (core, "127.0.0.1", port, "local_cookie", cookie);
		}
		else
		{
			status_warning (_("Can't auto-connect - no local core version >= 1.0 running it seems.\n"));
		}
	}
}


/******************************************************************************
 *
 *   check_uid
 *
 *   Checks if anyone is running us as root
 *    and aborts after showing a dialog if so
 *
 ******************************************************************************/

static void
check_uid (void)
{
#ifdef G_OS_UNIX
	if (geteuid() != (uid_t) 0)
		return;

	/* Using g_strconcat() to take advantage of already
	 *  translated first part of the message before new
	 *  release (TODO: merge into one later) */
	if (1)
	{
		gchar *msg;

		msg = g_strconcat(
		    _("You are running this GUI as user 'root'.\n\n"
		      "You really should not do this!\n"),
		    _("\nI will close the GUI now.\n\n"
		      "Use the --noob-wants-to-run-as-root\n"
					"command line switch to override this\n"
					"check if you think you really must do so.\n\n"),
				NULL);

		misc_gtk_ok_dialog (GTK_MESSAGE_WARNING, msg);

		g_free(msg);
	}

	/* abort */
	g_error(_("Running ed2k-gtk-gui as root is a very bad idea.\n"));
#endif

	return;
}


/******************************************************************************
 *
 *   auto_spawn
 *
 *	If GUI option is set so, try to spawn a local
 *    donkey or overnet core (if none is running)
 *
 ******************************************************************************/

static void
auto_spawn (void)
{
	const gchar *corepath, *base;
	GError      *err = NULL;

	if (!opt_get_bool(OPT_GUI_SPAWN_CORE_ON_STARTUP_IF_NEEDED))
		return;

	if (connect_dialog_local_core_running (NULL, NULL))
	{
		status_msg (_("GUI: auto-spawn: local core already running.\n"));
		return;
	}

	status_msg (_("GUI: auto-spawn: no local core running, we need to spawn one.\n"));

	corepath = opt_get_str (OPT_GUI_DEFAULT_CORE_BINARY_PATH);
	
	if (corepath == NULL || *corepath == 0x00)
	{
		status_msg (_("GUI: auto-spawn: no path to core binary available.\n"));
		return;
	}
	
	base = strrchr (corepath, G_DIR_SEPARATOR);
	if (base && !strstr(base, "1."))
	{
		status_msg (_("GUI: auto-spawn: core binary needs to be version 1.0 or newer.\n"));
		return;
	}
	
	if (!connect_dialog_spawn_core (corepath, &err))
	{
		status_msg (_("GUI: auto-spawn failed: %s\n"), err->message);
		g_error_free (err);
		return;
	}

	/* give the core some time to open the GUI port (for auto-connect) */
	g_usleep (3*G_USEC_PER_SEC);
}


#if defined(G_OS_WIN32)
static void
win32_print_function(const gchar *str)
{
	return; /* do nothing */
}

static void
win32_log_function(const gchar *log_domain, GLogLevelFlags ll, const gchar *msg, gpointer data)
{
	return; /* do nothing */
}
#endif /* G_OS_WIN32 */

/******************************************************************************
 *
 *   main
 *
 ******************************************************************************/

int
main (int argc, char **argv)
{
	g_assert (sizeof(gfloat) == 4);

	/* set our own error handler, so that
	 * we can use g_printerr() our way */
	g_set_printerr_handler ((GPrintFunc) gui_print_error_function);

#if defined(G_OS_WIN32)
	/* set our own handlers, so nothing
	 * will go to the stdout */
	g_set_print_handler((GPrintFunc)win32_print_function);
	g_log_set_handler(NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, win32_log_function, NULL );
	g_log_set_handler("Gtk", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, win32_log_function, NULL );
	g_log_set_handler("Glib", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, win32_log_function, NULL );
	g_log_set_handler("Gdk", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, win32_log_function, NULL );
	g_log_set_handler("GdkPixbuf", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, win32_log_function, NULL );
	g_log_set_handler("GNet", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, win32_log_function, NULL );
#endif

	/* init gettext:
	 *
	 * Set locale according to environment variables
	 * Set $LANG before executing the GUI to set your preferred language,
	 *   e.g. with "export LANG=fr" (sh)(if it is not already set that is)
	 *
	 */
#if defined(ENABLE_NLS)
	(void) setlocale (LC_ALL, "");
	(void) bindtextdomain (PACKAGE, LOCALEPATH);
	(void) textdomain (PACKAGE);
#endif

	/* signal handling
	 *
	 * by Mario Sergio Fujikawa Ferreira <lioux@FreeBSD.org>
	 *
	 * XXX - [Tim:] Does SIGCHLD interfere with libgnet in any way?
	 * XXX - [Tim:] should we block SIGTRAP? (I get this sometimes when doing http fetch while running GUI in gdb)
	 *
	 */
#ifdef G_OS_UNIX
	signal(SIGCHLD, sig_chld_handler);       	/* Prevents zombies */
	signal(SIGPIPE, sig_pipe_ignore_handler);	/* Handles post mortem conversations */
	/*sig_pipe_block(); */                   	/* Blocks signals from post morten conversations */
#endif

	gnet_init();  /* needs to be called _before_ gtk_init() */

	gtk_rc_add_default_file(opt_get_opt_filename_without_instance("custom.gtkrc-2.0"));
	gtk_rc_add_default_file(opt_get_opt_filename_without_instance("font.gtkrc-2.0"));

	gtk_init (&argc, &argv);

	if (!(argc > 1  &&  strcmp(argv[1], "--noob-wants-to-run-as-root") == 0))
		check_uid();

	gui_core_connection_init();

	main_parse_commandline_args(argc, argv);

	create_default_styles ();	/* create some styles */

	opt_read_from_disk();

	/* if we have been passed an ed2k-link as argument,
	 *  the linkhandler window might take over and not
	 *  the normal main GUI window.
	 */
	if (linkhandler_main(main_ed2k_link_passed_on_commandline))
	{
		g_free(main_ed2k_link_passed_on_commandline);
		exit(0);
	}

	(void) pipe_create();           	/* create named pipe   */

	check_if_blacklistfile_changed ();	/* read blacklist file */

	mainwindow_create(flags_disable_pages);

	auto_spawn();   /* auto-spawn core on start-up if option is set and none is running */
	auto_connect(); /* auto-connect to core on start-up if option is set                */

	gtk_main();

	opt_write_to_disk();

	G_FREE(main_ed2k_link_passed_on_commandline);

	return(0);
}


