#include "geotrace.h"
GList *trace_linked_list,*host_strings;
pthread_t trace_thread;
int current_browse;
GdkColor *my_gdk_color,*tmp_gdk_color;
gdouble tmp_line_color[3];
GtkStyle *label_style;

gint delete_event( GtkWidget *widget, GdkEvent *event, gpointer data) {
	gtk_main_quit ();
	return FALSE;
}

void destroy (GtkWidget *widget, gpointer data) {
    gtk_main_quit();
}

void generic_destroy (GtkWidget *widget, gpointer data) {
    gtk_widget_destroy (widget);
}

void options_clicked () {
	if (debug_mode)
	        fprintf (stdout,"(callbacks.c) options_clicked\n");
	create_options_window();

	// set traceroute options
	gtk_entry_set_text(GTK_ENTRY(trace_path_entry),traceroute_path);
	gtk_spin_button_set_value (GTK_SPIN_BUTTON(max_ttl_spinbutton),maxttl);
	gtk_spin_button_set_value (GTK_SPIN_BUTTON(timeout_spinbutton),timeout);
	if (resolve)
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolve_checkbox),TRUE);
	else
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolve_checkbox),FALSE);
	// set maps options
	gtk_entry_set_text(GTK_ENTRY(map_dir_path_entry),maps_dir_path);
	gtk_combo_set_popdown_strings(GTK_COMBO(start_map_combo),map_strings);
	gtk_entry_set_text(GTK_ENTRY(start_map_entry),start_map);

	// display options
	tmp_line_color[0] = line_color[0];
	tmp_line_color[1] = line_color[1];
	tmp_line_color[2] = line_color[2];
	tmp_gdk_color->pixel = 0;
	tmp_gdk_color->red = (guint16)(tmp_line_color[0]*65535.0);
	tmp_gdk_color->green = (guint16)(tmp_line_color[1]*65535.0);
	tmp_gdk_color->blue = (guint16)(tmp_line_color[2]*65535.0);
	gdk_color_alloc (gtk_widget_get_colormap(drawing_area),tmp_gdk_color);

	label_style = gtk_style_new();
	label_style->bg[0] = *tmp_gdk_color;
	gtk_widget_set_style(GTK_WIDGET(display_color_label2),label_style);
	gtk_style_unref(label_style);

	gtk_spin_button_set_value (GTK_SPIN_BUTTON(line_width_spinbutton),line_width);

	gtk_widget_show(options_window);
}

void options_apply_button_clicked() {
	if (debug_mode)
	        fprintf (stdout,"(callbacks.c) options_apply_button_clicked\n");
	// get traceroute options
	strcpy (traceroute_path,gtk_entry_get_text(GTK_ENTRY(trace_path_entry)));
	maxttl = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(max_ttl_spinbutton));
	timeout = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(timeout_spinbutton));
	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolve_checkbox)) == TRUE)
		resolve = 1;
	else
		resolve = 0;
	// get maps options
	strcpy (maps_dir_path,gtk_entry_get_text(GTK_ENTRY(map_dir_path_entry)));
	strcpy (start_map,gtk_entry_get_text(GTK_ENTRY(start_map_entry)));

	// get display options
	line_color[0] = tmp_line_color[0];
	line_color[1] = tmp_line_color[1];
	line_color[2] = tmp_line_color[2];

	my_gdk_color->pixel = 0;
	my_gdk_color->red = (guint16)(line_color[0]*65535.0);
	my_gdk_color->green = (guint16)(line_color[1]*65535.0);
	my_gdk_color->blue = (guint16)(line_color[2]*65535.0);
	gdk_color_alloc (gtk_widget_get_colormap(drawing_area),my_gdk_color);

	line_width = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(line_width_spinbutton));

	gtk_widget_destroy(options_window);
	save_prefs_to_file();
}

void color_select_destroy() {
	gtk_widget_destroy(color_select_dialog);
}

void display_color_select_clicked() {
	create_color_select_dialog();
}

void color_select_ok_clicked() {
	gtk_color_selection_get_color((gpointer)GTK_COLOR_SELECTION_DIALOG(color_select_dialog)->colorsel,tmp_line_color);
	tmp_gdk_color->pixel = 0;
	tmp_gdk_color->red = (guint16)(tmp_line_color[0]*65535.0);
	tmp_gdk_color->green = (guint16)(tmp_line_color[1]*65535.0);
	tmp_gdk_color->blue = (guint16)(tmp_line_color[2]*65535.0);
	gdk_color_alloc (gtk_widget_get_colormap(drawing_area),tmp_gdk_color);

	label_style = gtk_style_new();
	label_style->bg[0] = *tmp_gdk_color;
	gtk_widget_set_style(GTK_WIDGET(display_color_label2),label_style);
	gtk_style_unref(label_style);

	gtk_widget_destroy(color_select_dialog);	
}

void options_cancel_button_clicked() {
	gtk_widget_destroy(options_window);
}

void about_clicked () {
	create_about_window();
	gtk_widget_show (about_window);
}

void browse_cancel_button_clicked () {
	gtk_widget_destroy(trace_selection_dialog);
}

void browse_ok_button_clicked () {
	if (current_browse == TRACEROUTE_BROWSE) 
		gtk_entry_set_text(GTK_ENTRY(trace_path_entry),gtk_file_selection_get_filename
		(GTK_FILE_SELECTION(trace_selection_dialog)));
	else 
		gtk_entry_set_text(GTK_ENTRY(map_dir_path_entry),gtk_file_selection_get_filename
		(GTK_FILE_SELECTION(trace_selection_dialog)));
	gtk_widget_destroy(trace_selection_dialog);
}

void trace_browse_button_clicked () {
	current_browse = TRACEROUTE_BROWSE;
	create_trace_select_dialog();
	gtk_widget_show (trace_selection_dialog);
}

void maps_browse_button_clicked () {
	current_browse = MAPS_DIR_BROWSE;
	create_trace_select_dialog();
	gtk_widget_show (trace_selection_dialog);
}

void trace_button_clicked () {
	if (debug_mode)
	        fprintf (stdout,"(callbacks.c) trace_button_clicked\n");
	if (gethostbyname(gtk_entry_get_text(GTK_ENTRY(host_entry))) == NULL) {
		sprintf (popup_msg,"Invalid host/ip");
		create_popup_window();
		gtk_widget_show (popup_window);
	} else {
		set_map_from_file(curmap);
		g_list_free (trace_linked_list);
		trace_linked_list = NULL;
		pthread_create (&trace_thread,NULL,trace_button_clicked_thread,NULL);
		pthread_detach (trace_thread);
	}
}

void *trace_button_clicked_thread() {
	FILE *ptr;
	char tmpstr[100],*cmdline=NULL,checkdns[3];
	int i=0;

	if (debug_mode)
	        fprintf (stdout,"(callbacks.c) trace_button_clicked_thread\n");
	gdk_threads_enter();
	gtk_statusbar_push (GTK_STATUSBAR(status_bar),GPOINTER_TO_INT(&statusbar_msg),"Performing Trace");
	gtk_widget_set_sensitive (trace_button,FALSE); 
	if (g_list_find_custom(host_strings,gtk_entry_get_text(GTK_ENTRY(host_entry)),(GCompareFunc)strcasecmp) == NULL) {
		host_strings = g_list_prepend(host_strings,g_strdup_printf("%s",gtk_entry_get_text(GTK_ENTRY(host_entry))));
		gtk_combo_set_popdown_strings(GTK_COMBO(host_combo),host_strings);
	}
	gtk_clist_clear((GtkCList *) trace_list);
	gtk_clist_freeze(GTK_CLIST(trace_list));
	cmdline = malloc (100);
	if (resolve == 0) {
		strcpy (checkdns,"-n ");
	} else {
		strcpy (checkdns,"");
	}
	sprintf (cmdline,"%s %s-q 1 -m %d -w %d %s",traceroute_path,checkdns,
		maxttl,timeout,gtk_entry_get_text(GTK_ENTRY(host_entry)));
	gdk_threads_leave();

	ptr = popen(cmdline,"r");
	fflush(ptr);
        while (!feof(ptr)) {
                fscanf(ptr,"%[^\n]\n",tmpstr);
		add_trace_to_list (tmpstr);
		add_info_to_list (i);
		i++;
        }
	pclose(ptr);
	free (cmdline);
	
	gdk_threads_enter();
	gtk_statusbar_push (GTK_STATUSBAR(status_bar),GPOINTER_TO_INT(&statusbar_msg),"Getting Coordinates");
	gdk_threads_leave();
	get_hop_locations();
	gdk_threads_enter();
	update_clist_with_location();
	draw_trace_on_map();
	gtk_clist_thaw(GTK_CLIST(trace_list));
	gtk_widget_set_sensitive (trace_button,TRUE); 
	gtk_statusbar_push (GTK_STATUSBAR(status_bar),GPOINTER_TO_INT(&statusbar_msg),"Done.");
	gdk_threads_leave();

	pthread_exit(0);
}

void add_trace_to_list (char *ret_string) {
	struct trace_node *new_node;
	int hop;
	char *ip,*name;
	float rtt;

	if (debug_mode)
	        fprintf (stdout,"(callbacks.c) add_trace_to_list\n");
	new_node = malloc (sizeof(struct trace_node));
	ip = malloc (18);
	name = malloc (40);
	if (strchr(ret_string,'*') == NULL) {
		if (resolve)
			sscanf (ret_string,"%d %s %s %f",&hop,name,ip,&rtt);
		else
			sscanf (ret_string,"%d %s %f",&hop,ip,&rtt);
		new_node->timed_out = 0;
		new_node->ip = malloc (strlen(ip)+1);
		sprintf (new_node->ip,"%s",strtok(ip,"()"));
		if (resolve) {
			new_node->name = malloc (strlen(name)+1);
			sprintf (new_node->name,"%s",name);
		} else {
			new_node->name = malloc (strlen(new_node->ip)+1);
			sprintf (new_node->name,"%s",new_node->ip);
		}
		new_node->rtt = rtt;
	} else {
		sscanf (ret_string,"%d",&hop);
		new_node->timed_out = 1;
		new_node->ip = malloc (strlen("Timed Out")+1);
		sprintf (new_node->ip,"Timed Out");
	}
	new_node->hop = hop;
	gdk_threads_enter();
	trace_linked_list = g_list_append (trace_linked_list,new_node);
	gdk_threads_leave();
	free (ip);
	free (name);
}

void add_info_to_list (int pos) {
	char *data[5];
	struct trace_node *info_node;
	info_node = malloc (sizeof(struct trace_node));
	gdk_threads_enter();
	info_node = (struct trace_node *)g_list_nth_data(trace_linked_list,pos);
	gdk_threads_leave();

	if (debug_mode)
	        fprintf (stdout,"(callbacks.c) add_info_to_list\n");
	data[0] = malloc (5);
	if (info_node->timed_out) {
		data[1] = malloc (strlen("Timed Out")+1);
		data[2] = malloc (1);
		data[3] = malloc (1);
		data[4] = malloc (1);
	} else {
		data[1] = malloc (strlen(info_node->ip)+1);
		data[2] = malloc (strlen(info_node->name)+1);
		data[3] = malloc (1);
		data[4] = malloc (12);
	}

	sprintf (data[0],"%d",info_node->hop);
	if (info_node->timed_out) {
		sprintf (data[1],"%s","Timed Out");
		sprintf (data[2],"%s","");
		sprintf (data[3],"%s","");
		sprintf (data[4],"%s","");
	} else {
		sprintf (data[1],"%s",info_node->ip);
		sprintf (data[2],"%s",info_node->name);
		sprintf (data[3],"%s","");
		sprintf (data[4],"%7.3f",info_node->rtt);
	}

	gdk_threads_enter();
	gtk_clist_append ((GtkCList *)trace_list,data);
	gdk_threads_leave();
	free (data[0]);
	free (data[1]);
	free (data[2]);
	free (data[3]);
	free (data[4]);
}

void map_combo_entry_changed() {
	set_map_from_file (gtk_entry_get_text(GTK_ENTRY(map_combo_entry)));
}

gint on_mouse_move (GtkWidget *widget,GdkEventMotion *event) {
	int x, y;
	char *pos;
	GdkModifierType state;

	pos = malloc (8);
	if (event->is_hint) {
		gdk_window_get_pointer (event->window, &x, &y, &state);
	} else {
		x = event->x;
		y = event->y;
		state = event->state;
	}
	gtk_label_set_text (GTK_LABEL(latlon_label),point_to_lat_lon(x,y));
	return FALSE;
}

void get_hop_locations () {
	int i,numreq=0;
	char *netgeo_request;
	struct trace_node *new_node;

	if (debug_mode)
	        fprintf (stdout,"(callbacks.c) get_hop_locations\n");
	gdk_threads_enter();
	netgeo_request = calloc (1,1);
	for (i=0;i<g_list_length(trace_linked_list);i++) {
		new_node = g_list_nth_data (trace_linked_list,i);
		new_node->location = malloc (40);
		if (new_node->timed_out) {
			// hop timed out
		} else if (check_private_networks(new_node->ip)) {
			new_node->private = 1;
			sprintf (new_node->location,"Private Network");
			gtk_clist_set_text(GTK_CLIST(trace_list),i,3,new_node->location);
		} else {
			new_node->private = 0;
			new_node->timed_out = 0;
			numreq++;
			netgeo_request = realloc (netgeo_request,strlen(netgeo_request)+strlen(new_node->ip)+2);
			if (numreq>1)
				strcat (netgeo_request,",");
			strcat (netgeo_request,new_node->ip);
//	gtk_clist_set_text(GTK_CLIST(trace_list),i,3,new_node->location);
		}
	}
	gdk_threads_leave();
	if (numreq != 0)
		get_netgeo_info(netgeo_request);
	free (netgeo_request);
}

int check_private_networks (char *ip) {
	int byte[2];
	sscanf(ip,"%d.%d",&byte[0],&byte[1]);
	return (byte[0]==10 || (byte[0]==172 && byte[1]>=16 && byte[1] <=31)
		|| (byte[0]==192 && byte[1]==168));
}

void update_clist_with_location() {
	int i;

	if (debug_mode)
	        fprintf (stdout,"(callbacks.c) update_clist_with_location\n");
	for (i=0;i<g_list_length(trace_linked_list);i++) {
		if ((!((struct trace_node *)g_list_nth_data(trace_linked_list,
		i))->timed_out) &&(!((struct trace_node
		*)g_list_nth_data(trace_linked_list,i))->private)) {
			gtk_clist_set_text(GTK_CLIST(trace_list),i,3,((struct
				trace_node *)g_list_nth_data(trace_linked_list,i))->location);
		}
	}
}

void draw_trace_on_map() {
	float lastlon,lastlat,lat,lon;
	int i,set=0;
	GdkGC* my_gc;

	my_gc = gdk_gc_new(drawing_area->window);
	gdk_gc_ref (my_gc);
	gdk_gc_set_foreground(my_gc,my_gdk_color);
	gdk_gc_set_background(my_gc,&(drawing_area->style->white));
	gdk_gc_set_line_attributes(my_gc,line_width,GDK_LINE_SOLID,GDK_CAP_BUTT,GDK_JOIN_MITER);

	if (debug_mode)
	        fprintf (stdout,"(callbacks.c) draw_trace_on_map\n");
	for (i=0;i<g_list_length(trace_linked_list);i++) {
		if ((!((struct trace_node *)g_list_nth_data(trace_linked_list,
		i))->timed_out) &&(!((struct trace_node
		*)g_list_nth_data(trace_linked_list,i))->private)) {
			lat = ((struct trace_node *)g_list_nth_data(trace_linked_list,i))->lat;
			lon = ((struct trace_node *)g_list_nth_data(trace_linked_list,i))->lon;
			if (set && (lon!=lastlon) && (lat!=lastlat)) {
				gdk_draw_line(pixmap,
				my_gc,
				lat_lon_to_x(lastlat,lastlon),lat_lon_to_y(lastlat,lastlon),
				lat_lon_to_x(lat,lon),lat_lon_to_y(lat,lon));
			}
			set = 1;
			lastlat = lat;
			lastlon = lon;
		}
	}
	gdk_gc_unref (my_gc);
	gdk_gc_destroy(my_gc);
	expose_event();
}


syntax highlighted by Code2HTML, v. 0.9.1