/* PureAdmin
 * Copyright (C) 2003 Isak Savo
 *
 *  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.
 *
 *  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.
 */

/*
 * Callback-functions for the main window GUI.
 *
 * Copyright (C) 2003- Isak Savo
 */

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>

#include "globals.h"
#include "gui_helper.h"
#include "mainwin.h"
#include "prereq_usrmanager.h"
#include "usr_manager.h"
#include "helper.h"
#include "prefwin.h"
#include "cfg.h"
#include "logfile.h"
#include "helpview.h"

popup_src_t popup_source;

gboolean usermanager_initialized = FALSE;

static void update_adv_info (void)
{
	static GtkWidget *tree_activities = NULL;
	static GtkTreeModel *model = NULL;
	static GtkWidget *adv_info = NULL;
	static GtkTreeSelection *sel;
	GtkTreeIter iter;
	gboolean visible = TRUE, selected;
	gint id;
	PActivity *act;

	if (G_UNLIKELY (!tree_activities))
	{
		tree_activities = MW("tree_activity");
		model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_activities));
		adv_info = MW("tbl_advanced_info");
		sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_activities));
	}

	g_object_get (adv_info,
		      "visible", &visible,
		      NULL);
	selected = gtk_tree_selection_get_selected (sel, &model, &iter);
	if (visible)
	{
		if (selected)
		{
			gtk_tree_model_get (model, &iter, 
					    COL_ACT_ID, &id,
					    -1);
			act = srv_get_activity_with_id (id);
			gui_update_info_frame (act);
			pactivity_free (act);

		}
		else
			gui_update_info_frame (NULL);  /* Clear advanced info labels */
	}
	
}


/* Gets the ID of the selected activity and stores it in the location pointed to by output_id.
 * Returns true if the id was found, otherwise false*/
static gboolean gui_tree_act_get_selected_id (guint *output_id)
{
	static GtkWidget *tree_activities = NULL;
	static GtkTreeModel *model = NULL;
	static GtkTreeSelection *sel;
	GtkTreeIter iter;
	gboolean selected;
	gint id;

	if (G_UNLIKELY (!tree_activities))
	{
		tree_activities = MW("tree_activity");
		model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_activities));
		sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_activities));
	}
	selected = gtk_tree_selection_get_selected (sel, &model, &iter);
	if (!selected) /* Nothing is selected! */
		return FALSE;
	gtk_tree_model_get (model, &iter, 
			    COL_ACT_ID, &id,
			    -1);
	*output_id = id;
	return TRUE;
}

static gboolean gui_tree_usr_get_selected_user (gchar **user, gchar **host)
{
	static GtkWidget *tree_users = NULL;
	static GtkTreeModel *model = NULL;
	static GtkTreeSelection *sel;
	GtkTreeIter iter;
	gboolean selected;

	if (G_UNLIKELY (!tree_users))
	{
		tree_users = MW("tree_users");
		model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_users));
		sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_users));
	}
	selected = gtk_tree_selection_get_selected (sel, &model, &iter);
	if (!selected) /* Nothing is selected! */
		return FALSE;
	gtk_tree_model_get (model, &iter, 
			    COL_USR_USER, user,
			    COL_USR_HOST, host,
			    -1);
	if (host && user)
		return TRUE;
	else
		return FALSE;
}

gboolean
trayicon_activate (EggStatusIcon *icon, gpointer user_data)
{
	gtk_window_present (GTK_WINDOW(MW("main_window")));
	g_object_unref (status_icon);
	status_icon = NULL;
	return FALSE;
}


gboolean
on_main_window_delete_event            (GtkWidget       *widget,
                                        GdkEvent        *event,
                                        gpointer         user_data)
{
	exit_program ();
	return FALSE;
}


void
on_main_window_destroy                 (GtkObject       *object,
                                        gpointer         user_data)
{
	gtk_main_quit();
}

gboolean on_mainwin_focus_in_event (GtkWidget *widget,
				    GdkEventFocus *event,
				    gpointer user_data)
{
	hide_status_icon();
	return FALSE;
}

void
show_hide_advanced_info_cb (GtkToggleButton *togglebutton, gpointer user_data)
{
	GtkWidget *adv_info = MW("tbl_advanced_info");
	cfg.show_advinfo = gtk_toggle_button_get_active (togglebutton);
	if (cfg.show_advinfo)
	{
		gtk_widget_show (adv_info);
		update_adv_info();
	}
	else
		gtk_widget_hide (adv_info);
}

void
on_tree_activity_cursor_changed        (GtkTreeView     *treeview,
                                        gpointer         user_data)
{
	guint id;
	update_adv_info ();
	
	
	if (gui_tree_act_get_selected_id(&id))
	{
		PActivity *act = srv_get_activity_with_id (id);
		g_return_if_fail (act != NULL);
		user_list_select_user(act->username, act->remote_addr);
		pactivity_free (act);
	}
}


void
on_btn_user_manager_clicked            (GtkButton       *button,
                                        gpointer         user_data)
{
	GtkWidget *dlg_usrman;
	GtkWidget *mainwin = MW("main_window");

	if (prereq_are_all_requirements_met() == FALSE)
	{
		gboolean success = prereq_show_dialog(GTK_WINDOW(mainwin));
		if (!success)
			return;
	}
	dlg_usrman = usr_init_usermanager_window (mainwin);
	
	gtk_window_present (GTK_WINDOW (dlg_usrman));
}


void
menu_quit_cb                              (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	exit_program ();
	gtk_main_quit ();
}


void
menu_preferences_cb (GtkMenuItem *menuitem, gpointer user_data)
{
	GtkWidget *prefwin = pref_init_prefwindow (MW("main_window"));
	
	gtk_window_present (GTK_WINDOW(prefwin));
}


void
menu_srv_startstop_cb (GtkMenuItem *menuitem, gpointer user_data)
{
	GError *err = NULL;
	int ret;
	gchar *msg, *title;
	gboolean running = ftp_runmode == RUNMODE_STANDALONE ? TRUE : FALSE;

	if (G_UNLIKELY (ftp_runmode == RUNMODE_INETD))
		/* This won't happen, but I'm paranoid! */
		return;
	if (!cfg.cmd_startstop)
	{
		gui_display_msgdialog (_("Startupscript Not Found"),
				       _("PureAdmin could not locate the script used to start and stop the server.\n"
					 "This file should be located in /etc/rc.d/init.d/ on RedHat (and similar) and "
					 "/etc/rc.d/ on Slackware (and similar)\n"
					 "Starting and stopping is disabled."),
				       MSGDLG_TYPE_ERROR, MW("main_window"));
		return;
	}
   
	if (running)
		ret = misc_stop_server (&err);
	else
		ret = misc_start_server (&err);

	if (G_UNLIKELY (ret == FALSE))
	{
		if (running)
		{
			title = g_strdup (_("Failure to start server"));
			msg = g_strdup_printf (_("PureAdmin was unable to start the server because the execution of \"%s\" failed.\n"
						 "Error reported was: %s"), cfg.cmd_startstop, err->message);
		}
		else
		{
			title = g_strdup (_("Failure to stop server"));
			msg = g_strdup_printf (_("PureAdmin was unable to stop the server because the execution of \"%s\" failed.\n"
						 "Error reported was: %s"), cfg.cmd_startstop, err->message);
		}
      
		gui_display_msgdialog (title, msg,
				       MSGDLG_TYPE_ERROR, MW("main_window"));
		g_free (title);
		g_free (msg);
		g_error_free (err);
		return;
	}
	if (running)
		ftp_runmode = RUNMODE_STOPPED;
	else
		ftp_runmode = RUNMODE_STANDALONE;

	gui_update_server_status ();
}


void
menu_user_manager_cb (GtkMenuItem *menuitem, gpointer user_data)
{
	GtkWidget *dlg_usrman;
	
	if (!prereq_are_all_requirements_met())
		if (!prereq_show_dialog(GTK_WINDOW(MW("main_window"))))
			return;	
	dlg_usrman = usr_init_usermanager_window (MW("main_window"));
	gtk_window_present (GTK_WINDOW (dlg_usrman));
}

void
menu_connections_cb (GtkMenuItem *menuitem, gpointer user_data)
{
	GtkTreeView *act_tree = GTK_TREE_VIEW (MW("tree_activity"));
	GtkTreeSelection *sel = gtk_tree_view_get_selection (act_tree);
	GtkTreeIter iter;
	GtkTreeModel *model = NULL;
	
       	gtk_widget_set_sensitive (MW("mi_close_all"), srv_has_activities ());

	gboolean selected = gtk_tree_selection_get_selected (sel, NULL, NULL);
	gtk_widget_set_sensitive (MW("mi_close_tx"), selected);
	gtk_widget_set_sensitive (MW("mi_notify"), selected);


	gchar *text;
	sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (MW("tree_users")));
	selected = gtk_tree_selection_get_selected (sel, &model, &iter);
	gtk_widget_set_sensitive (MW("mi_disconnect"), selected);
	if (selected)
	{
		gchar *username = NULL;
		gtk_tree_model_get (model, &iter,
				    COL_USR_USER, &username,
				    -1);
		text  = g_strconcat (_("Disconnect user"), " ", username, NULL);
	}
	else
		text = g_strdup (_("Disconnect user"));
	GtkWidget *label = gtk_bin_get_child (GTK_BIN(MW("mi_disconnect")));
	gtk_label_set_text (GTK_LABEL(label), text);
	g_free (text);
}

void
menu_close_tx_cb (GtkMenuItem *menuitem, gpointer user_data)
{
	show_not_yet_implemented (GTK_WINDOW(MW("main_window")));
}

void
menu_disconnect_user_cb (GtkMenuItem *menuitem, gpointer user_data)
{
	show_not_yet_implemented (GTK_WINDOW(MW("main_window")));
}

void
menu_close_connections_cb (GtkMenuItem *menuitem, gpointer user_data)
{
	GList *act_list, *head;
	PActivity *activity;
	gint ret;

	head = act_list = srv_get_activities ();
	while (act_list)
	{
		activity = (PActivity *) act_list->data;
		g_print ("Closing connection with pid: %d...", activity->pid);
		ret = misc_close_connection (activity->pid);
		if (ret)
			g_print ("success\n");
		else
			g_print ("failure\n");
		act_list = act_list->next;
	}
	free_activity_list (head);
}

void
menu_notify_cb  (GtkMenuItem *menuitem, gpointer user_data)
{
	show_not_yet_implemented (GTK_WINDOW(MW("main_window")));
}

void
menu_about_cb (GtkMenuItem *menuitem, gpointer user_data)
{
	GtkWidget *about, *title;
	about = DW("dlg_about");
   
	title = DW("lbl_title");
	/* Make the About-text reflect the actual version */
	gtk_label_set_text (GTK_LABEL (title),
			    "<span weight=\"bold\" size=\"x-large\">" 
			    "PureAdmin v" VERSION 
			    "</span>");
	gtk_label_set_use_markup (GTK_LABEL (title), TRUE);

	gtk_dialog_run (GTK_DIALOG (about));
	gtk_widget_hide (about);
}


void
menu_help_cb (GtkMenuItem *menuitem, gpointer user_data)
{
	hlp_show_help (HLP_ITEM_INDEX);
}


static void open_in_browser (const gchar *url)
{
	gchar *browser = misc_find_webbrowser();
	GError *err = NULL;
	if (!browser) {
		gchar *msg = g_strdup_printf (_("The default browser could not be located. You can solve this "
					      "by either:\n"
					      "  \342\200\242 Setting the environment variable <i>$BROWSER</i> to the name of your web browser.\n"
					      "  \342\200\242 Open \"Preferred Applications\" in the GNOME control panel and set "
					      "the browser there.\n\n"
					      "The requested page is:\n"
					      "<u>%s</u>"), url);
		gui_display_msgdialog (_("Couldn't launch browser"), msg, MSGDLG_TYPE_WARNING, MW("main_window"));
		g_free (msg);
		return;
	}
	gchar *quoted_url = g_shell_quote (url);
	gchar *cmd = g_strdup_printf (browser, quoted_url);
	pur_log_dbg ("Running: %s", cmd);
	gboolean success;
	
	success = g_spawn_command_line_async (cmd, &err);
	//success = FALSE;
	g_free (quoted_url);
	g_free (cmd);
	if (!success) {
		gchar *msg = g_strdup_printf (_("The web browser could not be started because of a system error. Try again and "
						"if the error remains, report this bug in the support forums.\n\n"
						"The reported error was: %s"), err->message);
		gui_display_msgdialog (_("Couldn't launch browser"), msg, MSGDLG_TYPE_ERROR, MW("main_window"));
		g_free (msg);
	}
}

void menu_online_support_cb (GtkMenuItem *menuitem, gpointer user_data)
{
	const char *url = "http://purify.sourceforge.net/forums/";

	open_in_browser (url);
}

void menu_online_documentation_cb (GtkMenuItem *menuitem, gpointer user_data)
{
	const char *url = "http://purify.sourceforge.net/index.php?page=documentation";

	open_in_browser (url);
}

gboolean
on_tree_activity_popup_menu            (GtkWidget       *widget,
                                        gpointer         user_data)
{
	popup_source = POPUP_FROM_ACTTREE;
	gui_display_activity_popup (popup_source);
	return TRUE;
}


gboolean
on_tree_activity_button_press_event    (GtkWidget       *widget,
                                        GdkEventButton  *event,
                                        gpointer         user_data)
{
	GdkEventButton *event_button;

	if (event->type == GDK_BUTTON_PRESS)
	{
		event_button = (GdkEventButton *) event;
		if (event_button->button == 3)
		{
			popup_source = POPUP_FROM_ACTTREE;
			gui_display_activity_popup (popup_source);
			return TRUE;
		}
	}
	return FALSE;
}


gboolean
on_tree_users_popup_menu               (GtkWidget       *widget,
                                        gpointer         user_data)
{
	popup_source = POPUP_FROM_USRTREE;
	gui_display_activity_popup (popup_source);
	return FALSE;
}


gboolean
on_tree_users_button_press_event       (GtkWidget       *widget,
                                        GdkEventButton  *event,
                                        gpointer         user_data)
{
	GdkEventButton *event_button;

	if (event->type == GDK_BUTTON_PRESS)
	{
		event_button = (GdkEventButton *) event;
		if (event_button->button == 3)
		{
			popup_source = POPUP_FROM_USRTREE;
			gui_display_activity_popup (popup_source);
			return TRUE;
		}
	}
	return FALSE;
}

void
on_popup_close_tx                      (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	guint id;
	PActivity *act;

	if (popup_source == POPUP_FROM_ACTTREE)
	{
		if (!gui_tree_act_get_selected_id (&id))
		{
			pur_log_wrn ("Unable to fetch information about selected activity");
			return;
		}
		act = srv_get_activity_with_id (id);
		pur_log_dbg ("Closing connection for user %s (pid: %d)", act->username, act->pid);
		misc_close_connection (act->pid);
		pactivity_free (act);
	}
	else
	{
		/* This should _never_ happen! */
		pur_log_err ("Close transfer for user NOT possible!");
	}
}


void
on_popup_close_all_conns               (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	gchar *user, *host;
	guint id;
	gboolean success;
	PActivity *act;
	GList *conns, *head;

	if (popup_source == POPUP_FROM_ACTTREE)
	{
		if (!gui_tree_act_get_selected_id (&id))
		{
			pur_log_wrn ("Unable to fetch information about selected activity\n");
			return;
		}
		act = srv_get_activity_with_id (id);
		pur_log_dbg ("Closing all connection for user %s (pid: %d)\n", act->username, act->pid);
		conns = srv_get_pids_for_user_host (act->username, act->remote_addr);
		while (conns)
		{
			pur_log_dbg ("Killing process %d\n", GPOINTER_TO_INT (conns->data));
			success = misc_close_connection (GPOINTER_TO_INT (conns->data));
			if (!success)
				pur_log_err ("Failed to kill process %d\n", GPOINTER_TO_INT (conns->data));
			conns = g_list_next (conns);
		}
		pactivity_free (act);
		g_list_free (conns);
	}
	else
	{
		if (!gui_tree_usr_get_selected_user (&user, &host))
		{
			pur_log_wrn ("Unable to fetch information about selected user");
			return;
		}
		pur_log_dbg ("Closing all connection for user %s (host: %s)\n", user, host);
		head = conns = srv_get_pids_for_user_host (user, host);
		while (conns)
		{
			pur_log_dbg ("Killing process %d\n", GPOINTER_TO_INT (conns->data));
			success = misc_close_connection (GPOINTER_TO_INT (conns->data));
			if (!success)
				pur_log_wrn ("Failed to kill process %d\n", GPOINTER_TO_INT (conns->data));
			conns = g_list_next (conns);
		}
		g_list_free (head);
	}
}


void on_popup_show_userinfo (GtkMenuItem *menuitem, gpointer user_data)
{
	guint id;
	gchar *user, *host;
	PActivity *act;
	GtkWidget *dlg_usrman;
	
	if (popup_source == POPUP_FROM_ACTTREE)
	{
		if (!gui_tree_act_get_selected_id (&id))
		{
			pur_log_wrn ("Unable to fetch information about selected activity\n");
			return;
		}
		act = srv_get_activity_with_id (id);
		user = act->username;
		pactivity_free (act);
	}
	else
	{
		if (!gui_tree_usr_get_selected_user (&user, &host))
		{
			pur_log_wrn ("Unable to fetch information about selected user\n");
			return;
		}
	}
	pur_log_dbg ("Showing userinfo for %s\n", user);
   
	if (!prereq_are_all_requirements_met())
		if(!prereq_show_dialog(GTK_WINDOW(MW("main_window"))))
			return;

	dlg_usrman = usr_init_usermanager_window (MW("main_window"));
	gtk_window_set_transient_for (GTK_WINDOW(dlg_usrman), GTK_WINDOW (MW("main_window")));

	usr_select_user (user);
	gtk_widget_show (dlg_usrman);
	gtk_window_present (GTK_WINDOW (dlg_usrman));

}


void
menu_debug_console_cb (GtkMenuItem *menuitem, gpointer user_data)
{
	gtk_window_present (GTK_WINDOW (MW("dlg_debug")));
}


/* Handles keyboard press events for the main window. Used to grab
 * hard-coded global keyboard shortcuts */
gboolean
mainwin_keypress                       (GtkWidget       *widget,
                                        GdkEventKey     *event,
                                        gpointer         user_data)
{
	guint modifier = event->state;
	static GtkWidget *notebook = NULL;

#define PUR_CTRL_OR_SHIFT (modifier & (GDK_CONTROL_MASK | GDK_SHIFT_MASK))

	if (G_UNLIKELY(!notebook))
		notebook = MW("notebook1");
	/* Alt+<key> shortcuts (ugly way, only check for ctrl/shift)*/
	if (modifier & GDK_MOD1_MASK && !(PUR_CTRL_OR_SHIFT))
	{
		switch (event->keyval){
			case GDK_1:
			  gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 0);
			  break;
			case GDK_2:
			  gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 1);
			  break;
		}
	}
	return FALSE;
}


void
on_btn_logview_clear_clicked           (GtkButton       *button,
                                        gpointer         user_data)
{
	log_clear_logview ();
}


void
on_btn_logview_reread_clicked          (GtkButton       *button,
                                        gpointer         user_data)
{
	close_logfile ();
	init_logfile ();
}


syntax highlighted by Code2HTML, v. 0.9.1