/*
 * Copyright (C) Henning Prömpers 2008 <henning.proempers@uni-jena.de>
 *
 * In dieser Datei befinden sich die Methoden, die die einzelnen Aktionen für
   die Clients durchführen.
 */


/* wandelt den Path-Inhalt in die zugehörige Client-Nummer um. Dies wird in
   diesem Modul von allen Funktionen *_selected_clients benutzt, da diese
   herausfinden müssen, welche Clients markiert sind.
*/
int convert_path_content_to_client_no(GtkTreePath *path){
	// den Path-Inhalt in einen String umwandeln, der die Position des Clients darstellt: gtk_tree_path_to_string(path), NULL, 0)
	// String in int umwandeln:	int_position = g_ascii_strtoll(gtk_tree_path_to_string(path), NULL, 0);
	// client_nr suchen, die an der gegebenen Position gespeichert ist
	return GPOINTER_TO_INT(g_slist_nth_data(symbols, g_ascii_strtoll(gtk_tree_path_to_string(path), NULL, 0)));
}


/*
 bootet den angegebenen Client und ändert den Status
*/
void boot_client(int client_no){
	if (get_client_state_from_gconf(client_no) == state_on) return; // abbrechen, wenn Client schon an ist
	g_message(_("Waking up Client %i..."), client_no);
	// MAC aus gconf ermitteln
	GSList* macs;
	macs = gconf_client_get_list(gconf_client, "/apps/labcontrol/system_config/MACs", GCONF_VALUE_STRING, NULL);
	gchar* mac;
	mac = g_slist_nth_data(macs, client_no-1);
	g_message("%s", mac);
	// PC booten
	gnome_execute_shell(NULL, g_strdup_printf("wakeonlan -i %s %s", gconf_client_get_string(gconf_client, "/apps/labcontrol/system_config/network_broadcast_address", NULL), mac));
	// Client braucht durchschnittlich 1:20 zum hochfahren + 5 sec Reserve
//	client_update_wait[client_no-1] = gconf_client_get_int(gconf_client, "/apps/labcontrol/system_config/boot_state_update_wait", NULL); // erst nach 65 Sekunden Status wieder aktualisieren
//	client_update_lock[client_no-1] = TRUE; // Symbol darf nicht aktualisiert werden, falls grade der Status eingelesen wird
	// Status setzen
	set_client_state_to_gconf(client_no, state_booting);
}

/*
 bootet alle markierten Clients
*/
void boot_selected_clients(){
	int i=0;
	// eine Liste der markierten Clients abrufen (enthält je ein GtkTreePath)
	GList* selected_clients; selected_clients = gtk_icon_view_get_selected_items(icon_view);
	// die einzelnen Elemente aus der Liste extrahieren und
	GtkTreePath *path;
	do{
		path = g_list_nth_data(selected_clients, i);
		i++;
		if (path != NULL){
			boot_client(convert_path_content_to_client_no(path)); // boot aufrufen
		}
	} while (path != NULL);
}


/*
 startet zLeaf auf dem angegebenen Client und ändert den Status
*/
void start_zleaf_on_client(guint client_no){
	// Prüfen, ob bereits ein zLeaf läuft, dann Warnmeldung und evtl. abbruch
	if (get_current_client_state(client_no, TRUE) == state_zleaf_running){
		// Nachfragen, ob wirklich eine weitere Instanz gestartet werden soll
		GtkWidget *dialog;
		dialog = gtk_message_dialog_new (GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
			_("A process called zleaf.exe is still running at the selected client %i. Do you really want to start a new zLeaf instance on the client? If you are not sure, press NO."), client_no);
		if (gtk_dialog_run(GTK_DIALOG (dialog)) != GTK_RESPONSE_YES){
			gtk_widget_destroy (dialog);
			return; // wenn NEIN: Abbruch;
		}
		gtk_widget_destroy(dialog);
	}
	
	g_message(_("Starting zLeaf on Client %i..."), client_no);

	// zLeaf auf Client starten (über ssh)
	// Wenn Client-Nr einstellig, so wird durch den Ausdruck (client_no<10)?"0":"" noch eine 0 eingefügt
	// die aktuell verwendete Version wird aus gconf ausgelesen
	gnome_execute_shell(NULL, g_strdup_printf("ssh -i %s %s@%s DISPLAY=:0.0 /home/%s/start_zLeaf.sh %s", 
				get_publickey_path_user(), get_user_name_on_clients(), 
				get_hostname_of_client(client_no), get_user_name_on_clients(),
	            gconf_client_get_string(gconf_client, "/apps/labcontrol/temp/current_ztree_version", NULL)));
	// Status setzen
	set_client_state_to_gconf(client_no, state_zleaf_running);
}

/*
 startet zLeaf auf allen markierten Clients
*/
void start_zleaf_on_all_selected_clients(){
	// Prüfen, ob lokal ein zTree-Server läuft, dann Warnmeldung und evtl. abbruch
	if (!ztree_running()){
		// Nachfragen, ob wirklich ein Client, der sich nicht verbinden kann, gestartet werden soll
		GtkWidget *dialog;
		dialog = gtk_message_dialog_new (GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
			_("No zTree is running on this server. Do you really want to start zLeafs, even though they will fail to connect the server? If you are not sure, press NO."));
		if (gtk_dialog_run(GTK_DIALOG (dialog)) != GTK_RESPONSE_YES){
			gtk_widget_destroy (dialog);
			return; // wenn NEIN: Abbruch;
		}
		gtk_widget_destroy(dialog);
	}

	int i=0, client_no;
	// eine Liste der markierten Clients abrufen (enthält je ein GtkTreePath)
	GList* selected_clients; selected_clients = gtk_icon_view_get_selected_items(icon_view);

	// die einzelnen Elemente aus der Liste extrahieren und
	GtkTreePath *path;
	do{
		path = g_list_nth_data(selected_clients, i);
		i++;
		if (path != NULL){
			client_no = convert_path_content_to_client_no(path);
			if (get_client_state_from_gconf(client_no) != state_off){
				start_zleaf_on_client (client_no);
			}
		}
	} while (path != NULL);
}


/*
 killt zLeaf auf dem angegebenen Client und ändert den Status
*/
void kill_zleaf_on_client(int client_no_typeless){
	int client_no = GPOINTER_TO_UINT(client_no_typeless); // gpointer in int casten
	// zLeaf auf Client beenden (ssh), dabei Befehl so oft ausführen, bis der Status nicht mehr zleaf_running ist (setzt implizit am Ende den richtigen Status)
	do{
		g_message(_("Try to kill zLeaf on Client %i"), client_no);
		gnome_execute_shell(NULL, g_strdup_printf("ssh -i %s %s@%s killall zleaf.exe",
					get_publickey_path_user(), get_user_name_on_clients(),
		            get_hostname_of_client(client_no)));
	// Prüfen, ob noch ein zLeaf-Prozess auf dem Client läuft
	} while(get_current_client_state(client_no, TRUE) == state_zleaf_running); // am Ende hat das Symbol schon den richtigen Status, dieser muss nicht mehr explizit gesetzt werden
	g_message(_("Kill zLeaf on Client %i finished."), client_no);
}

/*
 killt zLeaf auf allen markierten Clients
*/
void kill_zleaf_on_all_selected_clients(){
	int i=0, client_no;
	// eine Liste der markierten Clients abrufen (enthält je ein GtkTreePath)
	GList* selected_clients; selected_clients = gtk_icon_view_get_selected_items(icon_view);
	// die einzelnen Elemente aus der Liste extrahieren und
	GtkTreePath *path;
	do{
		path = g_list_nth_data(selected_clients, i);
		i++;
		if (path != NULL){
			client_no = convert_path_content_to_client_no(path);
			if (get_client_state_from_gconf(client_no) != state_off){
				g_thread_pool_push(zleaf_kill_threads, GUINT_TO_POINTER(client_no), NULL); // // kill_zleaf als eigenen Thread aufrufen
			}
		}
	} while (path != NULL);
}


/*
 fährt den angegebenen Client herunter und ändert den Status
*/
void shutdown_client(int client_no){
	if (get_client_state_from_gconf(client_no) == state_off) return; // abbrechen, wenn Client schon aus ist
	g_message(_("Shut down Client %i..."), client_no);
	// Client herunterfahren (über ssh)
	gnome_execute_shell(NULL, g_strdup_printf("ssh -i %s root@%s halt",
				get_publickey_path_root(), get_hostname_of_client(client_no)));
	// Client braucht durchschnittlich 20s zum runterfahren + 5 sec Reserve
//	client_update_wait[client_no-1] = gconf_client_get_int(gconf_client, "/apps/labcontrol/system_config/halt_state_update_wait", NULL); // erst nach 25 Sekunden Status wieder aktualisieren
//	client_update_lock[client_no-1] = TRUE; // Symbol darf nicht aktualisiert werden, falls grade der Status eingelesen wird
	// Status setzen
	set_client_state_to_gconf(client_no, state_shutdowning);

}

/*
 fährt alle markierten Clients herunter
*/
void shutdown_selected_clients(){
	int i=0;
	// eine Liste der markierten Clients abrufen (enthält je ein GtkTreePath)
	GList* selected_clients; selected_clients = gtk_icon_view_get_selected_items(icon_view);
	// die einzelnen Elemente aus der Liste extrahieren und
	GtkTreePath *path;
	do{
		path = g_list_nth_data(selected_clients, i);
		i++;
		if (path != NULL){
			shutdown_client(convert_path_content_to_client_no(path)); // shutdown aufrufen
		}
	} while (path != NULL);
}


/*
 startet den VNC-Client für den gegebenen Client
*/
void show_desktop_over_vnc(int client_no){
	g_message(_("Start VPN-client for client %i..."), client_no);
	// Als VNC-Viewer wird Vinagre genutzt. Damit dieser skaliert, müssen die Client-Bookmarks aus /opt/labcontrol/vinagre-bookmarks.xml in den eigenen Vinagre-Bookmarks vorhanden sein. Hat man keine eigenen, kann mit
	// mkdir -p ~/.local/share/vinagre ; ln -s /opt/labcontrol/vinagre-bookmarks.xml ~/.local/share/vinagre/
	// ein symbolischer Link darauf angelegt werden.
	gnome_execute_shell(NULL, g_strdup_printf("%s %s",
				gconf_client_get_string(gconf_client, "/apps/labcontrol/user_config/VNC_viewer", NULL),
				get_hostname_of_client(client_no)));
}

/*
 startet für alle markierten Clients einen VNC-Client
*/
void show_selected_client_desktops(){
	int i=0;
	// eine Liste der markierten Clients abrufen (enthält je ein GtkTreePath)
	GList* selected_clients; selected_clients = gtk_icon_view_get_selected_items(icon_view);
	// Bei mehr als 3 selektierten Elementen fragen, ob wirklich mehrere VNC-Clients gestartet werden sollen
	if (g_list_length(selected_clients) > 3 ){
		GtkWidget *dialog;
		dialog = gtk_message_dialog_new (GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
			_("%i clients are selected. Do you really want to start a VNC-session for each selected client? If you are not sure, press NO."), g_list_length(selected_clients));
		if (gtk_dialog_run(GTK_DIALOG (dialog)) != GTK_RESPONSE_YES){
			gtk_widget_destroy (dialog);
			return; // wenn NEIN: Abbruch;
		}
		gtk_widget_destroy(dialog);
	}
	// die einzelnen Elemente aus der Liste extrahieren und
	GtkTreePath *path;
	do{
		path = g_list_nth_data(selected_clients, i);
		i++;
		if (path != NULL){
			show_desktop_over_vnc(convert_path_content_to_client_no(path)); // show_desktop_over_vnc aufrufen
		}		
	} while (path != NULL);
}
