/*
 * 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"


static void do_title(GtkWidget *w);
static void delete_edit(GtkWidget *w)
{
	struct pageedit *pe;
	pe = (struct pageedit *)gtk_object_get_user_data(GTK_OBJECT(w));
	if (!pe)
		return;
	if (valid_np(pe->np)) {
		do_title(w);
		pe->np->pe = NULL;
	}
	gtk_widget_destroy(pe->window);
	g_free(pe);
}

int append_network(struct pageedit *pe, struct network *n)
{

	char *ptrs[2];
	char host[256];
	char netmask[256];
	struct in_addr ia;
	int p;
	
	if (!pe)
		return -1;
	ptrs[0] = host;
	ptrs[1] = netmask;
	ia.s_addr = n->net_mask;
	strncpy(netmask, inet_ntoa(ia), sizeof(netmask));
	ia.s_addr = n->net_addr;
	strncpy(host, inet_ntoa(ia), sizeof(host));
	if (!strcmp(netmask, "255.255.255.255") && option_reverse_dns) {
		struct hostent *hp;
		hp = gethostbyaddr((char *)&ia, sizeof(ia), AF_INET);
		if (hp) 
			strncpy(host, hp->h_name, sizeof(host));
	}
	p= gtk_clist_append(GTK_CLIST(pe->networks), ptrs);
	gtk_clist_set_row_data(GTK_CLIST(pe->networks), p, n);
	return p;
}

int append_domain(struct pageedit *pe, struct domain *d)
{
	char *ptrs[2];
	int p;
	if (!pe)
		return -1;
	ptrs[0]=d->domain;
	p=gtk_clist_append(GTK_CLIST(pe->domains), ptrs);
	gtk_clist_set_row_data(GTK_CLIST(pe->domains), p, d);
	return p;
}

static void populate_networks(struct net_page *np, struct pageedit *pe)
{
	int p;
	struct network *n;
	
	n = np->ncontents;
	while(n) {
		p = append_network(pe, n);
		n = n->next;
	}
}

static void populate_domains(struct net_page *np, struct pageedit *pe)
{
	int p;
	struct domain *d;
	d = np->dcontents;
	while(d) {
		p = append_domain(pe, d);
		d = d->next;
	}
}

static void do_network_wrapper(GtkWidget *w, int d)
{
	struct pageedit *pe;
	struct net_page *np;
	pe = (struct pageedit *)gtk_object_get_user_data(GTK_OBJECT(w));
	/* Temporarily munge current_page */
	if (!valid_np(pe->np))
		return;
	np = current_page;
	current_page = pe->np;
	do_network(w, d);
	current_page = np;
}

static void remove_network(GtkWidget *w)
{
	struct pageedit *pe;
	struct network *n;
	struct network *tn, *last;
	int r;
	GList *l;

	pe = (struct pageedit *)gtk_object_get_user_data(GTK_OBJECT(w));
	l = g_list_first(GTK_CLIST(pe->networks)->selection);
	if (!l)
		return;
	if (!valid_np(pe->np))
		return;
	r = GPOINTER_TO_INT(l->data);
	if (r < 0)
		return; 
	n = (struct network *)gtk_clist_get_row_data(GTK_CLIST(pe->networks), r);
	tn = pe->np->ncontents;
	last=NULL;
	while(tn) {
		if (tn == n) {
			if (last) {
				last->next = tn->next;
			} else {
				pe->np->ncontents=tn->next;
			}
			g_free(tn);
			break;
		}
		last=tn;
		tn=tn->next;
	}
	gtk_clist_remove(GTK_CLIST(pe->networks), r);
}

static void remove_domain(GtkWidget *w)
{
	struct pageedit *pe;
	struct domain *d;
	int r;
	GList *l;
	struct domain *td, *last;

	pe = (struct pageedit *)gtk_object_get_user_data(GTK_OBJECT(w));
	l = g_list_first(GTK_CLIST(pe->domains)->selection);
	if (!l)
		return;
	if (!valid_np(pe->np))
		return;
	r = GPOINTER_TO_INT(l->data);
	if (r < 0)
		return; 
	d = (struct domain *)gtk_clist_get_row_data(GTK_CLIST(pe->domains), r);
	td = pe->np->dcontents;
	last=NULL;
	while(td) {
		if (td == d) {
			if (last) {
				last->next = td->next;
			} else {
				pe->np->dcontents=td->next;
			}
			g_free(td);
			break;
		}
		last=td;
		td = td->next;
	}
	gtk_clist_remove(GTK_CLIST(pe->domains), r);
}

static void do_title(GtkWidget *w)
{
	struct pageedit *pe;
	char buf[256], *s;
	pe = (struct pageedit *)gtk_object_get_user_data(GTK_OBJECT(w));
	if (!valid_np(pe->np)) 
		return;
	gtk_label_get(GTK_LABEL(pe->np->label), &s);
	if (strcmp(gtk_entry_get_text(GTK_ENTRY(pe->entry)), s)) {
		gtk_label_set(GTK_LABEL(pe->np->label), 
			      gtk_entry_get_text(GTK_ENTRY(pe->entry)));
		snprintf(buf, sizeof(buf), "Page '%s'",
			 gtk_entry_get_text(GTK_ENTRY(pe->entry)));
		gtk_window_set_title(GTK_WINDOW(pe->window), buf);
	}
}

static void do_update(GtkWidget *w)
{
	struct pageedit *pe;
	struct net_page *np;
	do_title(w);
	pe = (struct pageedit *)gtk_object_get_user_data(GTK_OBJECT(w));
	if (!valid_np(pe->np)) 
		return;
	np = current_page;
	current_page = pe->np;
	reload_page();
	current_page = np;
}

void show_edit(struct net_page *np)
{
	struct pageedit *pe;
	GtkWidget *bbox;
	GtkWidget *bbox2;
	GtkWidget *vbox;
	GtkWidget *hbox;
	GtkWidget *label;
	GtkWidget *close;
	GtkWidget *add2;
	GtkWidget *remove2;
	GtkWidget *add;
	GtkWidget *remove;
	GtkWidget *update;
#if (GTK_MINOR_VERSION > 2) || ((GTK_MICRO_VERSION > 4)	&& (GTK_MINOR_VERSION > 0))
	GtkWidget *sw1;
	GtkWidget *sw2;
#endif
	char buf[256], *s;
	static char *titles_net[] = { "Network", "Netmask", NULL };
	static char *titles_dom[] = { "Domain", NULL };
	if (np->pe) {
		gtk_widget_show(np->pe->window);
		return;
	}
	gtk_label_get(GTK_LABEL(np->label), &s);
	snprintf(buf, sizeof(buf), "Page '%s'", s);
	np->pe = pe = g_new(struct pageedit, 1);
	pe->np = np;
	pe->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	gtk_widget_realize(pe->window);
	fix_icon(pe->window->window);
	pe->networks = gtk_clist_new_with_titles(2, titles_net);
	
#if ((GTK_MINOR_VERSION > 0) && (GTK_MICRO_VERSION > 2))  || (GTK_MAJOR_VERSION > 1)
	gtk_clist_set_column_auto_resize(GTK_CLIST(pe->networks), 0, TRUE);
	gtk_clist_set_column_auto_resize(GTK_CLIST(pe->networks), 1, TRUE);
#else
	gtk_clist_set_column_width(GTK_CLIST(pe->networks), 0, 100);
	gtk_clist_set_column_width(GTK_CLIST(pe->networks), 1, 100);
#endif
	pe->domains = gtk_clist_new_with_titles(1, titles_dom);
	vbox = gtk_vbox_new(FALSE, 5);
	bbox = gtk_hbox_new(FALSE, 5);
	bbox2 = gtk_hbox_new(FALSE, 5);
	
	update = gtk_button_new_with_label("Update");
	close = gtk_button_new_with_label("Close");
	add = gtk_button_new_with_label("Add domain");
	add2 = gtk_button_new_with_label("Add host/network");
	remove = gtk_button_new_with_label("Remove domain");
	remove2 = gtk_button_new_with_label("Remove host/network");
	
	pe->entry = gtk_entry_new();
	label = gtk_label_new("Name:");
	hbox = gtk_hbox_new(FALSE, 5);

	gtk_entry_set_text(GTK_ENTRY(pe->entry), s);
	gtk_object_set_user_data(GTK_OBJECT(pe->entry), pe);
	gtk_signal_connect(GTK_OBJECT(pe->entry), "activate", GTK_SIGNAL_FUNC(do_title), NULL);

	gtk_widget_show(pe->entry);
	gtk_widget_show(hbox);
	gtk_widget_show(label);
	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5);
	gtk_box_pack_start(GTK_BOX(hbox), pe->entry, TRUE, TRUE, 5);
	
	gtk_box_pack_end(GTK_BOX(bbox2), remove2, FALSE, FALSE, 5);
	gtk_box_pack_end(GTK_BOX(bbox2), add2, FALSE, FALSE, 5);

	gtk_box_pack_end(GTK_BOX(bbox), close, FALSE, FALSE, 5);
	gtk_box_pack_end(GTK_BOX(bbox), update, FALSE, FALSE, 5);
	gtk_box_pack_end(GTK_BOX(bbox), remove, FALSE, FALSE, 5);
	gtk_box_pack_end(GTK_BOX(bbox), add, FALSE, FALSE, 5);

	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);

#if (GTK_MINOR_VERSION > 2) || ((GTK_MICRO_VERSION > 4)	&& (GTK_MINOR_VERSION > 0))
	sw1 = gtk_scrolled_window_new(NULL, NULL);
	sw2 = gtk_scrolled_window_new(NULL, NULL);
	gtk_widget_show(sw1);
	gtk_widget_show(sw2);
	gtk_widget_set_usize(sw1, 0, 100);
	gtk_widget_set_usize(sw2, 0, 100);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw1), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw2), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
	gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw1), pe->networks);
	gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw2), pe->domains);

	gtk_box_pack_start(GTK_BOX(vbox), sw1, TRUE, TRUE, 5);
	gtk_box_pack_start(GTK_BOX(vbox), bbox2, FALSE, FALSE, 5);
	gtk_box_pack_start(GTK_BOX(vbox), sw2, TRUE, TRUE, 5);
	gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 5);

#else
	gtk_widget_set_usize(pe->networks, 0, 100);
	gtk_widget_set_usize(pe->domains, 0, 100);
	gtk_clist_set_policy(GTK_CLIST(pe->networks), GTK_POLICY_ALWAYS, GTK_POLICY_AUTOMATIC);
	gtk_clist_set_policy(GTK_CLIST(pe->domains), GTK_POLICY_ALWAYS, GTK_POLICY_AUTOMATIC);
	gtk_box_pack_start(GTK_BOX(vbox), pe->networks, TRUE, TRUE, 5);
	gtk_box_pack_start(GTK_BOX(vbox), bbox2, FALSE, FALSE, 5);
	gtk_box_pack_start(GTK_BOX(vbox), pe->domains, TRUE, TRUE, 5);
	gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 5);
#endif
	
	gtk_container_add(GTK_CONTAINER(pe->window), vbox);
	
	gtk_widget_show(vbox);
	gtk_widget_show(bbox);
	gtk_widget_show(bbox2);
	gtk_widget_show(update);
	gtk_widget_show(pe->networks);
	gtk_widget_show(pe->domains);
	
	populate_networks(np, pe);
	populate_domains(np, pe);
	
	gtk_object_set_user_data(GTK_OBJECT(update), pe);
	gtk_signal_connect(GTK_OBJECT(update), "clicked", GTK_SIGNAL_FUNC(do_update), NULL);
	gtk_object_set_user_data(GTK_OBJECT(add), pe);
	gtk_signal_connect(GTK_OBJECT(add), "clicked", GTK_SIGNAL_FUNC(do_network_wrapper), (void *)2);
	gtk_object_set_user_data(GTK_OBJECT(add2), pe);
	gtk_signal_connect(GTK_OBJECT(add2), "clicked", GTK_SIGNAL_FUNC(do_network_wrapper), (void *)1);

	gtk_object_set_user_data(GTK_OBJECT(remove2), pe);
	gtk_signal_connect(GTK_OBJECT(remove2), "clicked", GTK_SIGNAL_FUNC(remove_network), NULL);
	gtk_object_set_user_data(GTK_OBJECT(remove), pe);
	gtk_signal_connect(GTK_OBJECT(remove), "clicked", GTK_SIGNAL_FUNC(remove_domain), NULL);


	gtk_widget_show(close);
	gtk_widget_show(add);
	gtk_widget_show(remove);
	gtk_widget_show(add2);
	gtk_widget_show(remove2);

	gtk_object_set_user_data(GTK_OBJECT(add), pe);
	gtk_object_set_user_data(GTK_OBJECT(add2), pe);
	gtk_object_set_user_data(GTK_OBJECT(remove), pe);
	gtk_object_set_user_data(GTK_OBJECT(remove2), pe);

	gtk_object_set_user_data(GTK_OBJECT(close), pe);
	gtk_signal_connect(GTK_OBJECT(close), "clicked", GTK_SIGNAL_FUNC(delete_edit), pe);
	gtk_object_set_user_data(GTK_OBJECT(pe->window), pe);
	gtk_signal_connect(GTK_OBJECT(pe->window), "delete_event", GTK_SIGNAL_FUNC(delete_edit), pe);
	gtk_widget_grab_focus(close);
	gtk_window_set_title(GTK_WINDOW(pe->window),  buf);
	gtk_widget_show(pe->window);
}
