/*
 * Network Explorer
 *
 * Copyright (C) 1998, Mark Spencer
 * 
 * Distributed under the terms of the GNU GPL
 *
 */

#include <gtk/gtk.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <string.h>
#include <netdb.h>
#include "cheops.h"

#define FLAG_DOMAIN 1

static char *get_dom(char *s)
{
	char *s2=s;
	while(s2 && !get_server(s2, 0)) {
		s2 = strchr(s2, '.');
		if (s2)
			s2++;
	}
	if (!s2)
		s2=s;
	return s2;
}

void place_object(struct net_object *no, int xp, int yp)
{
	struct link *l;
	struct net_page *np;
	np = (struct net_page *)gtk_object_get_user_data(GTK_OBJECT(no->eventbox->parent));
	gtk_widget_set_uposition(no->eventbox, xp, yp);
	gtk_widget_set_uposition(no->otherbox, xp, yp + np->icon_height - 15);
	l = no->links;
	while(l) {
		/* Check validity of other widget? */
		gtk_link_set_coords(GTK_LINK(l->linkw),
				    no->eventbox->allocation.x + no->eventbox->allocation.width/2,
				    no->eventbox->allocation.y + no->eventbox->allocation.height/2,
				    l->other->eventbox->allocation.x + l->other->eventbox->allocation.width / 2,
				    l->other->eventbox->allocation.y + l->other->eventbox->allocation.height / 2);
			l=l->next;
	}
}

#if (GTK_MINOR_VERSION> 0) || (GTK_MAJOR_VERSION > 1)
static void move_row(GtkWidget *list, struct net_object *no, int row)
{
	struct net_object *no2;
	int id;
	no2 = (struct net_object *)gtk_clist_get_row_data(GTK_CLIST(list), row);
	if (no != no2) {
		id = no->id;
		no->id = no2->id;
		no2->id = id;
		gtk_clist_swap_rows(GTK_CLIST(list), no->id, no2->id);
	}
}
#endif

void add_to_list(GtkWidget *list, struct net_object *no)
{
	char *argv[4];
	char *c, *cd;
	struct in_addr ia;
	struct pixmap_cache *tmp;
	argv[0]=no->hostname;
	ia.s_addr = no->ip_addr;
	argv[1]=inet_ntoa(ia);
	argv[2]=no->os;
	argv[3]=print_aliases(no, ' ');
	no->id=gtk_clist_append(GTK_CLIST(list), argv);
	gtk_clist_set_row_data(GTK_CLIST(list), no->id, no);
	gtk_clist_get_text(GTK_CLIST(list), no->id, 0, &c);
	cd = strdup(c);
	tmp = get_pixmap(get_pm_name(no->fn, "-tiny.xpm"));
	gtk_clist_set_pixtext(GTK_CLIST(list), no->id, 0, cd, 4, tmp->pixmap, tmp->mask);
	free(cd);
	
}

static void place(struct net_object **nos, int cnt, struct net_page *np, int flags)
{
	int x;
	int xp, yp;
	char *last=NULL;
	struct in_addr ia;
	xp = 20;
	yp = 20;
	gtk_clist_freeze(GTK_CLIST(np->list));
#if !(GTK_MINOR_VERSION > 0)
	gtk_clist_clear(GTK_CLIST(np->list));
#endif
	for (x=0;x<cnt;x++) {
		if (!gtk_notebook_current_page(GTK_NOTEBOOK(np->notebook))) {
			if (flags & FLAG_DOMAIN) {
				ia.s_addr = nos[x]->ip_addr;
				if (strcasecmp(nos[x]->hostname, inet_ntoa(ia))) {
					if (last) {
						if (strcasecmp(last, get_dom(nos[x]->hostname)) && (xp != 20)) {
							xp = 20;
							yp += np->icon_height;
							if (yp + np->icon_height > np->eventbox->allocation.height) {
								gtk_widget_set_usize(np->eventbox, 0, 
									np->eventbox->allocation.height + np->icon_height);
							}
						}
					}
					last = get_dom(nos[x]->hostname);
				} else last="";
			}
			place_object(nos[x], xp, yp);
			xp += np->icon_width;
			if (xp > (option_use_visible_area ? np->pane->allocation.width : FIXED_WIDTH) - np->icon_width) {
				xp = 20;
				yp += np->icon_height;
				if (yp + np->icon_height > np->eventbox->allocation.height) {
					gtk_widget_set_usize(np->eventbox, 0, np->eventbox->allocation.height + np->icon_height);
				}
				
			}
		} else 
#if (GTK_MINOR_VERSION > 0)
			move_row(np->list, nos[x], x);
#else 
			add_to_list(np->list, nos[x]);
#endif
			
	}
	np->lastx = xp;
	np->lasty = yp;
	gtk_widget_queue_draw(np->list);
	gtk_clist_thaw(GTK_CLIST(np->list));
}

static int compare_ip(const void *a_d, const void *b_d)
{
	struct net_object **a, **b;
	unsigned int aa, ab;
	a = (struct net_object **)a_d;
	b = (struct net_object **)b_d;
	aa=ntohl((*a)->ip_addr);
	ab=ntohl((*b)->ip_addr);
	if (aa<ab) return -1; else
	if (aa>ab) return 1; else
	return 0;
}

static int compare_os(const void *a_d, const void *b_d)
{
	int res;
	struct net_object **a, **b;
	a = (struct net_object **)a_d;
	b = (struct net_object **)b_d;
	res = strcasecmp((*a)->fn, (*b)->fn);
	if (!res)
		res = strcasecmp((*a)->hostname, (*b)->hostname);
	return res;
}

static int compare_name(const void *a_d, const void *b_d)
{
	struct net_object **a, **b;
	a = (struct net_object **)a_d;
	b = (struct net_object **)b_d;
	return strcasecmp((*a)->hostname, (*b)->hostname);
}

static int compare_domain(const void *a_d, const void *b_d)
{
	struct net_object **a, **b;
	int res;
	struct in_addr ia;
	char *da, *db;
	a = (struct net_object **)a_d;
	b = (struct net_object **)b_d;
	ia.s_addr = (*a)->ip_addr;
	if (!strcmp((*a)->hostname, inet_ntoa(ia))) 
		return strcasecmp((*a)->hostname, (*b)->hostname);
	ia.s_addr = (*b)->ip_addr;
	if (!strcmp((*b)->hostname, inet_ntoa(ia))) 
		return strcasecmp((*a)->hostname, (*b)->hostname);
	da = get_dom((*a)->hostname);
	db = get_dom((*b)->hostname);
	res = strcasecmp(da, db);
	if (!res)
		res = strcasecmp((*a)->hostname, (*b)->hostname);
	return res;
}


void arrange(struct net_page *np, int how)
{
	int cnt=0;
	int x=0;
	struct net_object *no;
	struct net_object **sorter;
	immediate_setcursor(GDK_WATCH);
	for (no = np->objs; no; no=no->next)
		cnt++;
	if (!cnt)
		return;
	sorter = g_new(struct net_object *, cnt);
	for (no = np->objs; no; no=no->next) {
		sorter[x]=no;
		x++;
	}
	switch(how) {
	case BY_OS:
		qsort(sorter, cnt, sizeof(struct net_object *), compare_os);
		place(sorter, cnt, np, 0);
		break;
	case BY_NAME:
		qsort(sorter, cnt, sizeof(struct net_object *), compare_name);
		place(sorter, cnt, np, 0);
		break;
	case BY_ADDR:
		qsort(sorter, cnt, sizeof(struct net_object *), compare_ip);
		place(sorter, cnt, np, 0);
		break;
	case BY_DOMAIN:
		qsort(sorter, cnt, sizeof(struct net_object *), compare_domain);
		place(sorter, cnt, np, FLAG_DOMAIN);
		break;
	default:
		fprintf(stderr, "Don't know how to arrange by %d\n", how);
	}
	g_free(sorter);
	gdk_window_set_cursor(main_window.window->window, NULL);
}
