/*
 *	wanstatus.c
 *
 *	HNMS User Interface
 *	HNMS 2.0
 *
 *	February 1994
 *
 *	Leslie Schlecht
 *	Computer Sciences Corporation
 *	Numerical Aerodynamic Simulation Systems Division
 *	NASA Ames Research Center
 *
 *	Copyright (c) 1994 Leslie Schlecht
 *
 *	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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */
 
#include	<stdio.h>
#include	<string.h>
#include	<math.h>
#include	<ctype.h>

#include	<X11/StringDefs.h>
#include	<X11/Intrinsic.h>
#include	<Xm/Xm.h>
#include	<Xm/DrawingA.h>
#include	<Xm/Form.h>
#include	<Xm/Text.h>
#include	<Xm/ToggleB.h>

#include	"defines.h"
#include	"externs.h"
#include	"viewpanel.h"
#include	"view.h"
#include	"xsupport.h"
#include	"wanstatus.h"

#define		RADIUS		7
#define		CIRCLE		1
#define		LINE		2
#define		DOT		3
#define		ARROW		4
#define		CLOUD		5
#define		NUM_ARRANGES	5

typedef		struct reptype	{
		int		class, color;
		float		x0, y0, r;
		float		x1, y1;
		caddr_t		wtobj;
		} REPTYPE;

typedef		struct clustype	{
		double		xc, yc;
		float		explode;
		double		xmin, ymin, xmax, ymax;
		double		exp_xmin, exp_ymin, exp_xmax, exp_ymax;
		int		flag;
		} CLUSTYPE;

typedef		struct nodetype	{
		double		xorg, yorg;
		double		x, y;
		float		r, c;
		int		flag;
		caddr_t		site;
		CLUSTYPE	*cluster;
		} NODETYPE;

typedef		struct channeltype	{
		NODETYPE	*n0, *n1;
		float		x0, y0, x1, y1;
		int		d;
		unsigned int	mask;
		} CHANNELTYPE;
		
typedef		struct wantype	{
		caddr_t		obj;
		REPTYPE		*rep;
		NODETYPE	*node;
		int		class;
		struct wantype	*ipparent;
		struct wantype	*physparent;
		caddr_t		childlist;
		int		nchild;
		int		status;
		int		ifnumber;
		char		*name;
		} WANTYPE;
		
typedef		struct wandata	{
		caddr_t		objlist;
		caddr_t		nodelist;
		caddr_t		replist;
		caddr_t		clusterlist;
		caddr_t		routevar;
		char		*routedest;
		Widget		da, route_text, object_text, route_onoff;
		int		background, project;
		Pixmap		background_pixmap;
		float		xmin, xmax, ymin, ymax;
		float		xscale, yscale, xscreen, yscreen;
		float		lat, lon, dist;
		int		width, height;
		int		show_route;
		WANTYPE		*selected;
		} WANDATA;

static int	expose=False;
static caddr_t	reachvar, locvar, indexvar;
static int	objcnt[NUM_OBJCLASSES];
static char	*routestr = "ipRouteIfIndex.";
static caddr_t	help_text;
static int	totalcount=0, totaldown=0;

char*
WANTYPEName(wtobj)
WANTYPE	*wtobj;
	{
	return(wtobj->name);
	}

int
WANTYPEStatus(wtobj)
WANTYPE	*wtobj;
	{
	return(wtobj->status);
	}

void
InitializeWANStatus()
	{
	CreateVariable("hnmsObjReachStatus.0", &reachvar);
	CreateVariable("hnmsSiteLocation.0", &locvar);
	CreateVariable("hnmsIpaddrIfIndex.0", &indexvar);
	}

void
DestroyWANTYPE(wt)
WANTYPE	*wt;
	{
	if (wt->childlist)
		RemoveEntryList(wt->childlist, NULL);
	free(wt);
	}


void
ClearWANStatus(view)
VIEW	*view;
	{
	WANDATA		*wa;
	caddr_t		oe;
	WANTYPE		*wt;

	wa = (WANDATA*)(view->panel->wa);
	oe = wa->objlist;
	while (NextEntry(&oe, &wt))
		RemoveViewFromObject(wt->obj, view);
	RemoveEntryList(wa->objlist, DestroyWANTYPE);
	wa->objlist = NULL;
	RemoveEntryList(wa->nodelist, free);
	wa->nodelist = NULL;
	RemoveEntryList(wa->replist, free);
	wa->replist = NULL;
	expose = True;
	ExposeWANStatus(NULL, view->panel, NULL);
	}


void
LoadWANStatus(view)
VIEW	*view;
	{
	VIEWPANEL	*panel;
	WANDATA	*wa;
	char	*bname;
	Widget	b;
	XmString	xs;
	
	panel = view->panel;
	wa = (WANDATA*)myalloc(NULL, 1, sizeof(WANDATA));
	wa->da = XtVaCreateManagedWidget("wanstatus",
		xmDrawingAreaWidgetClass,
		panel->viewform,
		XmNtopAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_FORM,
		XmNleftAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_FORM,
		XmNbackground, GetColor(BLACK),
		XmNresizePolicy, XmRESIZE_ANY,
		NULL);
	XtAddCallback(wa->da, XmNresizeCallback, ResizeWANStatus, panel);
	XtAddCallback(wa->da, XmNexposeCallback, ExposeWANStatus, panel);
	XtAddCallback(wa->da, XmNinputCallback, InputWANStatus, wa);
	b = XtVaCreateManagedWidget("form",
		xmFormWidgetClass,
		panel->extraform,
		XmNtopAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_FORM,
		XmNleftAttachment, XmATTACH_NONE,
		XmNrightAttachment, XmATTACH_FORM,
		NULL);
	wa->object_text = labeled_text("text", b, 16, "Objects:");
	b = XtVaCreateManagedWidget("form",
		xmFormWidgetClass,
		panel->extraform,
		XmNtopAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_FORM,
		XmNleftAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_WIDGET,
		XmNrightWidget, b,
		XmNrightOffset, 10,
		NULL);
	wa->route_onoff = XtVaCreateManagedWidget("toggle",
		xmToggleButtonWidgetClass,
		b,
		XmNtopAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_FORM,
		XmNleftAttachment, XmATTACH_NONE,
		XmNrightAttachment, XmATTACH_FORM,
		XmNlabelString, (xs=X_STR("on/off")),
		NULL);
	XmStringFree(xs);
	wa->route_text = labeled_text("route", b, 16, "Route Dest:");
	XtVaSetValues(wa->route_text,
		XmNeditable, True,
		XmNcursorPositionVisible, True,
		XmNrightAttachment, XmATTACH_WIDGET,
		XmNrightWidget, wa->route_onoff,
		NULL);
	XtAddCallback(wa->route_text, XmNactivateCallback,
		SetWANStatusRouteDest, view);
	XmToggleButtonSetState(wa->route_onoff, 0, False);
	XtAddCallback(wa->route_onoff, XmNvalueChangedCallback,
		SetWANStatusRouteOnOff, view->panel);
	wa->background = view->background;
	GetBackgroundParms(wa->background, &(wa->project), &(wa->xmin),
		&(wa->ymin), &(wa->xmax), &(wa->ymax), &(wa->lat), &(wa->lon),
		&(wa->dist));
	panel->wa = (caddr_t)wa;
	wa->xscale = ScreenWidth()/(wa->xmax-wa->xmin);
	wa->yscale = ScreenHeight()/(wa->ymax-wa->ymin);
	view->recvonly = 0;
	view->varlist[OBJ_processor] = (caddr_t*)myalloc(NULL, 2,
		sizeof(caddr_t));
	view->varcnt[OBJ_processor] = 1;
	view->varlist[OBJ_processor][0] = reachvar;
	view->varlist[OBJ_subnet] = (caddr_t*)myalloc(NULL, 1,
		sizeof(caddr_t));
	view->varcnt[OBJ_subnet] = 1;
	view->varlist[OBJ_subnet][0] = reachvar;
	view->varlist[OBJ_site] = (caddr_t*)myalloc(NULL, 1,
		sizeof(caddr_t));
	view->varcnt[OBJ_site] = 1;
	view->varlist[OBJ_site][0] = locvar;
	view->varlist[OBJ_ipaddr] = (caddr_t*)myalloc(NULL, 1,
		sizeof(caddr_t));
	view->varcnt[OBJ_ipaddr] = 1;
	view->varlist[OBJ_ipaddr][0] = indexvar;
	view->announce[OBJ_processor] = 1;
	GetHelp(view->panel, 10, 1);
	AddRemoveButton(view, view->panel);
	}

	
	
void
DestroyWANStatus(panel)
VIEWPANEL	*panel;
	{
	WANDATA	*wa;
	
	wa = (WANDATA*)panel->wa;
	RemoveEntryList(wa->objlist, free);
	RemoveEntryList(wa->nodelist, free);
	RemoveEntryList(wa->replist, free);
	if (wa->routedest) XtFree(wa->routedest);
	if (wa->background_pixmap) FreePixmap(wa->background_pixmap);
	XtDestroyWidget(wa->da);
	free(wa);
	}


void
ResizeWANStatus(widg, panel, call_data)
Widget	widg;
VIEWPANEL	*panel;
caddr_t	call_data;
	{
	Dimension	w, h;
	WANDATA		*wa;
	
	wa = (WANDATA*)(panel->wa);
	XtVaGetValues(wa->da,
		XmNwidth, &w,
		XmNheight, &h,
		NULL);
	if ((w != wa->width) || (h != wa->height)) {
		wa->width = w;
		wa->height = h;
		wa->xscreen = ((float)wa->width)/ScreenWidth();
		wa->yscreen = ((float)wa->height)/ScreenHeight();
		if (wa->background) {
			if (wa->background_pixmap)
				FreePixmap(wa->background_pixmap);
			wa->background_pixmap = CreateBitmap(wa->width,
				wa->height);
			FillBackgroundPixmap(wa->background,
				wa->background_pixmap,
				wa->width,
				wa->height);
			}
		}
	}


void
ExposeWANStatus(widg, panel, call_data)
Widget		widg;
VIEWPANEL	*panel;
XmDrawingAreaCallbackStruct	*call_data;
	{
	WANDATA	*wa;

	if (!call_data && !expose) return;
	if (!XtIsRealized(panel->shell)) return;
	wa = (WANDATA*)panel->wa;
	SetColor(GREY);
	SetBackgroundColor(BLACK);
	CopyBitmap(wa->da, wa->background_pixmap, wa->width, wa->height);
	DrawWANStatus(wa);
	expose = False;
	}


void
InputWANStatus(widg, wa, call_data)
Widget	widg;
WANDATA	*wa;
XmDrawingAreaCallbackStruct	*call_data;
	{
	XEvent	*e;
	caddr_t	n;
	REPTYPE	*rt;
	int	in;
	
	e = call_data->event;
	if (e->xbutton.button != Button1) return;
	if (e->type == ButtonPress) {
		/* a processor or site was selected */
		n = wa->replist;
		while (NextEntry(&n, &rt)) {
			if ((rt->class == LINE) || (rt->class == CLOUD))
				continue;
			in = InsideWANStatus(wa, rt, e->xbutton.x,
				e->xbutton.y);
			if (in) wa->selected = (WANTYPE*)(rt->wtobj);
			}
		if (wa->selected) {
			SetCurrentObject(wa->selected->obj);
			SelectWANStatusObject(wa, wa->selected);
			return;
			}
		/* a subnet was selected */
		n = wa->replist;
		while (NextEntry(&n, &rt)) {
			if ((rt->class == DOT) || (rt->class == CIRCLE))
				continue;
			in = InsideWANStatus(wa, rt, e->xbutton.x,
				e->xbutton.y);
			if (in) wa->selected = (WANTYPE*)(rt->wtobj);
			}
		if (wa->selected) {
			SetCurrentObject(wa->selected->obj);
			SelectWANStatusObject(wa, wa->selected);
			}
		}
	else if (e->type == ButtonRelease) {
		if (wa->selected) {
			DrawWANStatusObject(wa, wa->selected);
			wa->selected = NULL;
			}
		}
	}
	
int
CompareWANObj(data, obj, a2)
WANTYPE	*data;
caddr_t	obj;
caddr_t	a2;
	{
	if (data->obj == obj)
		return(0);
	else
		return(-1);
	}


void
RemoveWANStatusObject(panel, obj)
VIEWPANEL	*panel;
caddr_t		obj;
	{
	WANDATA	*wa;
	WANTYPE	*wt;
	
	wa = (WANDATA*)panel->wa;
	if (!FindEntry(wa->objlist, CompareWANObj, obj, NULL, &wt))
		return;
	RemoveWANTYPE(wa, wt);
	}
	


void
AddWANStatusObject(view, obj, class, name)
VIEW		*view;
caddr_t		obj;
int		class;
char		*name;
	{
	WANDATA	*wa;
	WANTYPE	*wt;
	caddr_t	var;
	VIEWPANEL	*panel;
	char	buf[BUFSIZ], *p;
	
	panel = view->panel;
	wa = (WANDATA*)panel->wa;
	if (FindEntry(wa->objlist, CompareWANObj, obj, NULL, &wt))
		return;
	wt = (WANTYPE*)myalloc(NULL, 1, sizeof(WANTYPE));
	wt->class = class;
	wt->name = name;
	wt->obj = obj;
	wt->status = STATUS_UNKNOWN;
	AddEntry(&(wa->objlist), wt, NULL, 0);
	switch (class) {
	case OBJ_site:
		Q_RequestObjectVariable(obj, view, locvar);
		break;
	case OBJ_processor:
		if (wa->routevar)
			Q_RequestObjectVariable(obj, view, wa->routevar);
		AddObjectParentToView(obj, view, PHYSPARENT);
		AddObjectChildToView(obj, view, OBJ_ipaddr, PHYSPARENT);
		Q_RequestObjectVariable(obj, view, reachvar);
		break;
	case OBJ_subnet:
	/*
	printf("AddWAN %s\n", name);
	*/
		Q_RequestObjectVariable(obj, view, reachvar);
		break;
	case OBJ_ipaddr:
	/*
	printf("AddWAN %s\n", name);
	*/
		AddObjectParentToView(obj, view, IPPARENT);
		Q_RequestObjectVariable(obj, view, indexvar);
		break;
	default:;
		}
	}


void
UpdateWANStatusParent(view, obj, parent, rel)
VIEW		*view;
caddr_t		obj, parent;
int		rel;
	{
	WANDATA	*wa;
	WANTYPE	*wtobj, *wtparent;
	VIEWPANEL	*panel;
	
	panel = view->panel;
	wa = (WANDATA*)panel->wa;
	if (!FindEntry(wa->objlist, CompareWANObj, obj, NULL, &wtobj)) return;
	if (!FindEntry(wa->objlist, CompareWANObj, parent, NULL, &wtparent))
		wtparent = NULL;
	switch (wtobj->class) {
	case OBJ_processor:
		if (!wtparent) {
			AddObjectParentToView(obj, view, PHYSPARENT);
			return;
			}
		if (wtobj->physparent == wtparent) break;
		RemoveWANTYPEChild(wtobj->physparent, wtobj);
		wtobj->physparent = wtparent;
		AddWANTYPEChild(wtparent, wtobj);
		RenderWANStatusSites(wa, wtparent, NULL);
		RenderWANStatusSubnets(wa);
		ExposeWANStatus(NULL, view->panel, NULL);
		break;
	case OBJ_ipaddr:
		if (rel == IPPARENT) {
			if (!wtparent) {
				AddObjectParentToView(obj, view, IPPARENT);
				return;
				}
		/*
		printf("WANSTATUS updateparent ipaddr\n");
		*/
			if (wtobj->ipparent == wtparent) break;
	/*
	printf("WANSTATUS updateparent obj %s parent %s\n",wtobj->name, wtparent->name);
	*/
			RemoveWANTYPEChild(wtobj->ipparent, wtobj);
			RenderWANStatusSubnet(wa, wtobj->ipparent);
			wtobj->ipparent = wtparent;
			AddWANTYPEChild(wtparent, wtobj);
			RenderWANStatusSubnet(wa, wtparent);
			ExposeWANStatus(NULL, view->panel, NULL);
			}
		else if (rel == PHYSPARENT) {
			if (wtobj->physparent == wtparent) break;
			RemoveWANTYPEChild(wtobj->physparent, wtobj);
			wtobj->physparent = wtparent;
			if (!wtparent)
				RemoveWANTYPE(wa, wtobj);
			else
				AddWANTYPEChild(wtparent, wtobj);
			RenderWANStatusSubnets(wa);
			ExposeWANStatus(NULL, view->panel, NULL);
			if (wa->routevar && wtobj->physparent)
				Q_RequestObjectVariable(wtobj->physparent->obj,
					view, wa->routevar);
			}
		break;
	default:;
		}
	}


void
RemoveWANTYPEChild(wtparent, wtchild)
WANTYPE	*wtparent, *wtchild;
	{
	if (!wtparent) return;
	if (RemoveEntry(&(wtparent->childlist), wtchild, NULL)) {
		wtparent->nchild --;
		if (wtchild->node) expose = True;
		}
	}


void
AddWANTYPEChild(wtparent, wtchild)
WANTYPE	*wtparent, *wtchild;
	{
	if (!wtparent) return;
	if (AddEntry(&(wtparent->childlist), wtchild, NULL, 0)) {
		wtparent->nchild ++;
		if (wtchild->physparent) {
			wtchild->node = wtchild->physparent->node;
			if (wtchild->node) expose = True;
			}
		}
	}


void
RemoveWANTYPE(wa, wtobj)
WANDATA	*wa;
WANTYPE	*wtobj;
	{
	if (wtobj->physparent) {
		if (RemoveEntry(&(wtobj->physparent->childlist), wtobj, NULL))
			wtobj->physparent->nchild --;
		}
	if (wtobj->ipparent) {
		if (RemoveEntry(&(wtobj->ipparent->childlist), wtobj, NULL))
			wtobj->ipparent->nchild --;
		}
	if (wtobj->node) expose = True;
	RemoveEntry(&(wa->objlist), wtobj, DestroyWANTYPE);
	}


void
UpdateWANStatusObject(view, obj, var, value, tsc)
VIEW		*view;
caddr_t		obj;
caddr_t		var;
caddr_t		value;
unsigned int	tsc;
	{
	WANDATA	*wa;
	WANTYPE	*wtobj, *child;
	VIEWPANEL	*panel;
	caddr_t	n;
	
	panel = (VIEWPANEL*)view->panel;
	wa = (WANDATA*)panel->wa;
	if (!((var==reachvar) || (var==locvar) || (var==indexvar) ||
	      (var==wa->routevar))) return;
	if (!FindEntry(wa->objlist, CompareWANObj, obj, NULL, &wtobj)) return;
	switch (wtobj->class) {
	case OBJ_site:
		RenderWANStatusSites(wa, wtobj, value);
		RenderWANStatusSubnets(wa);
		ExposeWANStatus(NULL, panel, NULL);
		break;
	case OBJ_processor:
		if (var == reachvar) {
			wtobj->status = (unsigned int)value;
			if (wtobj->status == STATUS_NOSTATUS)
				wtobj->status = STATUS_UNKNOWN;
			if (XtIsRealized(panel))
				DrawWANStatusProcessor(wa, wtobj);
			}
		else {
			wtobj->ifnumber = (unsigned int)value;
			if (!wtobj->ifnumber) break;
			n = wtobj->childlist;
			while (NextEntry(&n, &child)) {
				if (child->ifnumber == wtobj->ifnumber) {
					if (child->rep)
						child->rep->class = ARROW;
					}
				else {
					if (child->rep)
						child->rep->class = NULL;
					}
				}
			if (wa->show_route) {
				expose = True;
				ExposeWANStatus(NULL, panel, NULL);
				}
			}
		break;
	case OBJ_subnet:
		wtobj->status = (unsigned int)value;
		if (wtobj->status == STATUS_NOSTATUS)
			wtobj->status = STATUS_UNKNOWN;
		if (XtIsRealized(panel))
			DrawWANStatusSubnet(wa, wtobj);
		break;
	case OBJ_ipaddr:
		wtobj->ifnumber = (unsigned int)value;
		if (wa->routevar && wtobj->physparent)
			Q_RequestObjectVariable(wtobj->physparent->obj, view,
				wa->routevar);
		break;
	default:;
		}
	}


void
RenderWANStatusSites(wa, site, location)
WANDATA	*wa;
WANTYPE	*site;
char	*location;
	{
	double	x, y;
	caddr_t	n;
	WANTYPE	*wtchild;

	if (location) {
		if (!ParseLocation(wa, location, &x, &y)) return;
		/*
		printf("location: %s %f %f\n", location, x, y);
		*/
		if (!site->node) {
			/*
			printf("new node\n");
			*/
			site->node = (NODETYPE*)myalloc(NULL, 1,
				sizeof(NODETYPE));
			n = site->childlist;
			while (NextEntry(&n, &wtchild))
				wtchild->node = site->node;
			AddEntry(&(wa->nodelist), site->node, NULL, 0);
			bcopy(&site, &(site->node->site), sizeof(WANTYPE*));
			}
		site->node->xorg = x;
		site->node->yorg = y;
		}
	else if (!site->node)
		return;
	site->node->x = site->node->xorg;
	site->node->y = site->node->yorg;
	if (site->nchild < 2) {
		site->node->c = 0.0;
		site->node->r = RADIUS+1;
		}
	else if (site->nchild == 2) {
		site->node->c = RADIUS;
		site->node->r = RADIUS*2.0+2;
		}
	else {
		site->node->c = RADIUS/sin((double)(M_PI/site->nchild));
		site->node->r = site->node->c+RADIUS+1;
		}
	if (!site->rep) {
		site->rep = (REPTYPE*)myalloc(NULL, 1, sizeof(REPTYPE));
		site->rep->class = CIRCLE;
		site->rep->wtobj = (caddr_t)site;
		site->rep->color = WHITE;
		AddEntry(&(wa->replist), site->rep, NULL, 0);
		}
	ArrangeWANStatusNodes(wa);
	}


void
ArrangeWANStatusNodes(wa)
WANDATA	*wa;
	{
	double		mindif=2.0, xdif, ydif, xoff, yoff, angle, a;
	caddr_t		n1, n2;
	NODETYPE	*node1, *node2, *maxr;
	int		count, nbig, nsmall, overlap, arranging;
	CLUSTYPE	*cluster1, *cluster2;
	register	i;

	/* Are there any nodes to draw? */	
	if (!wa->nodelist) return;

	/* Determine the minimum difference between locations of
	   nodes.  We will use this value to move nodes that are at
	   exactly the same location. Mindif is initialized to 2.0
	   pixels.
	*/
	n1 = wa->nodelist;
	while (NextEntry(&n1, &node1)) {
		node1->x = node1->xorg;
		node1->y = node1->yorg;
		}
	n1 = wa->nodelist;
	while (NextEntry(&n1, &node1)) {
		n2 = wa->nodelist;
		while (NextEntry(&n2, &node2)) {
			if (node1 == node2) continue;
			/* determine the difference in location */
			xdif = fabs(node1->x-node2->x);
			ydif = fabs(node1->y-node2->y);
			if (xdif < 1.0) xdif = ydif;
			if (ydif < 1.0) ydif = xdif;
			/* doesn't count if they are in the same location */
			if ((xdif < 1.0) && (ydif < 1.0)) continue;
			mindif = MINIMUM(mindif, MINIMUM(xdif, ydif));
			}
		}
	mindif *= 0.5;
	/*
	printf("mindif %f\n", mindif);
	*/

	/* Move any nodes that are at the same location by a small amount.
	   These nodes are placed in a circle with the location as the
	   center.  If there is only one node with a bigger radius than
	   rest, it is placed in the center of the group.  Otherwise, all
	   are placed equally. */	
	n1 = wa->nodelist;
	while (NextEntry(&n1, &node1)) {
		count = 1;		/* number of nodes at same location */
		nsmall = 0;		/* number of nodes with biggest radius*/
		maxr = node1;		/* node with biggest radius */
		n2 = wa->nodelist;
		while (NextEntry(&n2, &node2)) {
			if (node1 == node2) continue;
			/*
			printf("x1 %f y1 %f, x2 %f y2 %f\n", node1->x, node1->y, node2->x, node2->y);
			*/
			xdif = fabs(node1->xorg-node2->xorg);
			ydif = fabs(node1->yorg-node2->yorg);
			if ((xdif < 1.0) && (ydif < 1.0)) {
				/*
				printf("SAME LOCATION %s %s\n", WANTYPEName(node1->site), WANTYPEName(node2->site));
				*/
				count ++;
				node1->flag = 1;
				node2->flag = 1;
				if (node2->r > maxr->r) {
					nsmall = count-1;
					maxr = node2;
					}
				else if (node2->r < maxr->r)
					nsmall ++;
				}
			}
		nbig = count-nsmall;
		/*
		printf("count = %d nbig = %d\n", count, nbig);
		printf("mindif %f\n", mindif);
		*/
		if (count == 1) continue;
		if (nbig == 1) {
			count --;
			maxr->flag = 0;
			}
		a = 2*M_PI/count;
		angle = 0;
		n2 = wa->nodelist;
		while (NextEntry(&n2, &node2)) {
			if (!node2->flag) continue;
			xoff = cos(angle)*mindif;
			yoff = sin(angle)*mindif;
			angle += a;
			node2->x = node2->xorg+xoff;
			node2->y = node2->yorg+yoff;
			node2->flag = 0;
			}
		
		}
	
	arranging = True;
	for (i=0; i<NUM_ARRANGES; i++) {
		if (!arranging) break;
		arranging = False;
		/* Put nodes in clusters.
		   Overlapping nodes are grouped together. */
		n1 = wa->nodelist;
		while (NextEntry(&n1, &node1)) {
			if (node1->cluster) continue;
			cluster1 = node1->cluster = (CLUSTYPE*)myalloc(NULL, 1,
				sizeof(CLUSTYPE));
			AddEntry(&(wa->clusterlist), cluster1, NULL, 0);
			cluster1->xc = node1->x;
			cluster1->yc = node1->y;
			cluster1->xmin = node1->x-node1->r;
			cluster1->xmax = node1->x+node1->r;
			cluster1->ymin = node1->y-node1->r;
			cluster1->ymax = node1->y+node1->r;
			overlap = True;
			while (overlap) {
				overlap = False;
				n2 = wa->nodelist;
				while (NextEntry(&n2, &node2)) {
					if (node2->cluster) continue;
					if (NodeInEnvelope(node2, cluster1)) {
						node2->cluster = cluster1;
						NewEnvelope(wa, cluster1);
						overlap = True;
						}
					}
				}
			}

		/*
		   All nodes are assigned to clusters at this point.
		   Explode clusters so nodes don't overlap.
		*/
		n1 = wa->clusterlist;
		while (NextEntry(&n1, &cluster1))
			if (ExplodeEnvelope(wa, cluster1))
				arranging = True;
		n1 = wa->nodelist;
		while (NextEntry(&n1, &node1)) {
			cluster1 = node1->cluster;
		/*
		printf("%s %f %f %f %f\n", WANTYPEName(node1->site), cluster1->xc, node1->xorg, node1->x, cluster1->explode);
		*/
			node1->x = cluster1->xc-(cluster1->xc-node1->x)*
				cluster1->explode;
			node1->y = cluster1->yc-(cluster1->yc-node1->y)*
				cluster1->explode;
			node1->cluster = NULL;
			}
		RemoveEntryList(wa->clusterlist, free);
		wa->clusterlist = NULL;
		}
	
	/* Now all nodes should be placed nicely (we hope). Set their
	   representative's coordinates.
	*/
	n1 = wa->nodelist;
	while (NextEntry(&n1, &node1))
		SetNodeRep(wa, node1, node1->site);
	expose = True;
	}


void
SetNodeRep(wa, node, site)
WANDATA		*wa;
NODETYPE	*node;
WANTYPE		*site;
	{
	caddr_t	n;
	WANTYPE	*proc;
	double	a, angle;

	site->rep->x0 = node->x;
	site->rep->y0 = node->y;
	site->rep->r = node->r;

	a = 2*M_PI/site->nchild;
	angle = 0;
	n = site->childlist;
	while (NextEntry(&n, &proc)) {
		if (!proc->rep) {
			proc->rep = (REPTYPE*)myalloc(NULL, 1, sizeof(REPTYPE));
			proc->rep->class = DOT;
			proc->rep->wtobj = (caddr_t)proc;
			AddEntry(&(wa->replist), proc->rep, NULL, 0);
			}
		proc->rep->x0 = node->x+node->c*cos(angle);
		proc->rep->y0 = node->y+node->c*sin(angle);
		proc->rep->r = RADIUS;
		proc->rep->color = StatusColor(proc->status);
		angle += a;
		}
	/*
	printf("Set Rep for %s %f %f %f %d\n", site->name, site->rep->x0, site->rep->y0, site->rep->r, site->nchild);
	*/
	}
	

void
NewEnvelope(wa, cluster)
WANDATA		*wa;
CLUSTYPE	*cluster;
	{
	caddr_t	n;
	NODETYPE	*node;
	double		xmin, xmax, ymin, ymax;
	
	xmin = cluster->xmin;
	ymin = cluster->ymin;
	xmax = cluster->xmax;
	ymax = cluster->ymax;
	n = wa->nodelist;
	while (NextEntry(&n, &node)) {
		if (node->cluster != cluster) continue;
		xmin = MINIMUM(node->x-node->r, xmin);
		xmax = MAXIMUM(node->x+node->r, xmax);
		ymin = MINIMUM(node->y-node->r, ymin);
		ymax = MAXIMUM(node->y+node->r, ymax);
		}
	cluster->xmin = xmin;
	cluster->xmax = xmax;
	cluster->ymin = ymin;
	cluster->ymax = ymax;
	}
	
int
NodeInEnvelope(node, cluster)
NODETYPE	*node;
CLUSTYPE	*cluster;
	{
	double	x0, y0, x1, y1;
	
	x0 = node->x-node->r;
	x1 = node->x+node->r;
	y0 = node->y-node->r;
	y1 = node->y+node->r;
	
	if (x1 < cluster->xmin) return(0);
	if (y1 < cluster->ymin) return(0);
	if (x0 > cluster->xmax) return(0);
	if (y0 > cluster->ymax) return(0);
	return(1);
	}
	

int
ExplodeEnvelope(wa, cluster)
WANDATA		*wa;
CLUSTYPE	*cluster;
	{
	caddr_t		n1, n2;
	NODETYPE	*node1, *node2;
	float		explode, w, h;
	int		overlap;
	
	explode = 1.0;
	cluster->explode = 1.0;
	n1 = wa->nodelist;
	overlap = False;
	while (NextEntry(&n1, &node1)) {
		if (node1->cluster != cluster) continue;
		n2 = wa->nodelist;
		while (NextEntry(&n2, &node2)) {
			if (node2->cluster != cluster) continue;
			if (NodesOverlap(node1, node2, &explode)) {
				overlap = True;
				cluster->explode = MAXIMUM(explode,
					cluster->explode);
				/*
				printf("%s %s OVERLAP %f\n", WANTYPEName(node1->site), WANTYPEName(node2->site), cluster->explode);
				*/
				}
			}
		}
	w = cluster->xmax-cluster->xmin;
	h = cluster->ymax-cluster->ymin;
	cluster->xc = cluster->xmin+w/2;
	cluster->yc = cluster->ymin+h/2;
	cluster->exp_xmin = cluster->xc-w*cluster->explode/2;
	cluster->exp_xmax = cluster->xc+w*cluster->explode/2;
	cluster->exp_ymin = cluster->yc-h*cluster->explode/2;
	cluster->exp_ymax = cluster->yc+h*cluster->explode/2;
	return(overlap);
	}


/*
 *	Find out if two nodes overlap and what scale factor is needed
 *	to separate them.
 */
int
NodesOverlap(node1, node2, explode)
NODETYPE	*node1, *node2;
float		*explode;
	{
	double	xmin1, xmax1, xmin2, xmax2;
	double	ymin1, ymax1, ymin2, ymax2;
	double	xd, yd, dist, realdist;

	if (node1 == node2) return(0);
	xmin1 = node1->x-node1->r;
	xmin2 = node2->x-node2->r;
	ymin1 = node1->y-node1->r;
	ymin2 = node2->y-node2->r;
	xmax1 = node1->x+node1->r;
	xmax2 = node2->x+node2->r;
	ymax1 = node1->y+node1->r;
	ymax2 = node2->y+node2->r;

	if (xmax1 < xmin2) return(0);
	if (ymax1 < ymin2) return(0);
	if (xmin1 > xmax2) return(0);
	if (ymin1 > ymax2) return(0);

	dist = node1->r+node2->r-1;
	xd = node2->x-node1->x;
	yd = node2->y-node1->y;
	realdist = sqrt(xd*xd+yd*yd);
	if (dist <= realdist) return(0);
	*explode = dist/realdist;
	/*
	if (*explode > 1.0)
		printf("OVERLAP %s %s %f %f %f\n", WANTYPEName(node1->site), WANTYPEName(node2->site), dist, realdist, *explode);
		*/
	return(1);
	}

	


void
DrawWANStatusProcessor(wa, proc)
WANDATA	*wa;
WANTYPE	*proc;
	{
	REPTYPE	*rep;

	rep = proc->rep;
	if (!rep) return;
	if (rep->color == RED) totaldown --;
	rep->color = StatusColor(proc->status);
	if (rep->color == RED) totaldown ++;
	SetColor(rep->color);
	DrawDot(wa->da, rep->x0*wa->xscreen, wa->height-rep->y0*wa->yscreen,
		rep->r*MINIMUM(wa->xscreen, wa->yscreen));
	}



void
DrawWANStatusSubnet(wa, subnet)
WANDATA	*wa;
WANTYPE	*subnet;
	{
	REPTYPE	*rep;

	rep = subnet->rep;
	if (!rep) return;
	if (rep->color == RED) totaldown --;
	rep->color = StatusColor(subnet->status);
	if (rep->color == RED) totaldown ++;
	SetColor(rep->color);
	if (rep->class == CLOUD)
		DrawWANStatusCloud(wa, rep->wtobj, rep->x0, rep->y0);
	else
		DrawLine(wa->da, rep->x0*wa->xscreen,
			wa->height-rep->y0*wa->yscreen, rep->x1*wa->xscreen,
			wa->height-rep->y1*wa->yscreen);
	}


void
DrawWANStatusCloud(wa, cloud, x0, y0)
WANDATA	*wa;
WANTYPE	*cloud;
float	x0, y0;
	{
	caddr_t	n;
	WANTYPE	*child;

	n = cloud->childlist;
	while (NextEntry(&n, &child)) {
		if (!child->rep) continue;
		DrawLine(wa->da, x0*wa->xscreen, wa->height-y0*wa->yscreen,
			child->node->x*wa->xscreen,
			wa->height-child->node->y*wa->yscreen);
		}
	}


void
RenderWANStatusSubnet(wa, subnet)
WANDATA	*wa;
WANTYPE	*subnet;
	{
	caddr_t	nipaddr;
	WANTYPE	*ipaddr0, *ipaddr1, *processor;
	NODETYPE	*node;
	float		x0, y0, x1, y1;
	int		count;

	if (!subnet) return;
	if (subnet->nchild < 2) return;
	/*
	printf("render subnet %s\n", subnet->name);
	*/
	nipaddr = subnet->childlist;
	if (subnet->nchild == 2) {
		if (!NextEntry(&nipaddr, &ipaddr0)) return;
		/*
		printf("ipaddr0 %s\n", ipaddr0->name);
		*/
		if (!ipaddr0->physparent) return;
		processor = ipaddr0->physparent;
		/*
		printf("processor0 %s\n", processor->name);
		*/
		if (!processor->node) return;
		node = processor->node;
		/*
		printf("node0 %f %f\n", node->x, node->y);
		*/
		x0 = node->x;
		y0 = node->y;
		if (!NextEntry(&nipaddr, &ipaddr1)) return;
		/*
		printf("ipaddr1 %s\n", ipaddr1->name);
		*/
		if (!ipaddr1->physparent) return;
		processor = ipaddr1->physparent;
		/*
		printf("processor1 %s\n", processor->name);
		*/
		if (!processor->node) return;
		node = processor->node;
		/*
		printf("node1 %f %f\n", node->x, node->y);
		*/
		x1 = node->x;
		y1 = node->y;
		/*
		printf("%f %f %f %f\n", x0, y0, x1, y1);
		*/
		if (!subnet->rep) {
			subnet->rep = (REPTYPE*)myalloc(NULL,
			1, sizeof(REPTYPE));
			subnet->rep->wtobj = (caddr_t)subnet;
			AddEntry(&(wa->replist), subnet->rep, NULL, 0);
			}
		subnet->rep->class = LINE;
		subnet->rep->x0 = x0;
		subnet->rep->y0 = y0;
		subnet->rep->x1 = x1;
		subnet->rep->y1 = y1;
		subnet->rep->color = StatusColor(subnet->status);
		subnet->rep->r = 1;
		FillIpaddrRep(wa, ipaddr0, x0, y0, x1, y1);
		FillIpaddrRep(wa, ipaddr1, x1, y1, x0, y0);
		expose = True;
		}
	else {
		/*
		printf("subnet %s is a cloud\n", subnet->name);
		*/
		x0 = 0;
		y0 = 0;
		count = 0;
		nipaddr = subnet->childlist;
		while (NextEntry(&nipaddr, &ipaddr0)) {
			if (!ipaddr0->physparent) continue;
			processor = ipaddr0->physparent;
			if (!processor->node) continue;
			node = processor->node;
			x0 += node->x;
			y0 += node->y;
			count ++;
			}
		if (count < 2) return;
		x0 = x0/count;
		y0 = y0/count;
		nipaddr = subnet->childlist;
		while (NextEntry(&nipaddr, &ipaddr0)) {
			if (!ipaddr0->physparent) continue;
			processor = ipaddr0->physparent;
			if (!processor->node) continue;
			node = processor->node;
			FillIpaddrRep(wa, ipaddr0, node->x, node->y, x0,
				y0);
			ipaddr0->node = node;
			}
		if (!subnet->rep) {
			subnet->rep = (REPTYPE*)myalloc(NULL,
				1, sizeof(REPTYPE));
			subnet->rep->wtobj = (caddr_t)subnet;
			AddEntry(&(wa->replist), subnet->rep, NULL, 0);
			}
		subnet->rep->class = CLOUD;
		subnet->rep->x0 = x0;
		subnet->rep->y0 = y0;
		subnet->rep->color = StatusColor(subnet->status);
		subnet->rep->r = count;
		expose = True;
		}
	}



void
RenderWANStatusSubnets(wa)
WANDATA	*wa;
	{
	caddr_t	nsub;
	WANTYPE	*subnet;

	nsub = wa->objlist;
	while (NextEntry(&nsub, &subnet)) {
		if (subnet->class != OBJ_subnet) continue;
		RenderWANStatusSubnet(wa, subnet);
		}

	}


void
FillIpaddrRep(wa, ipaddr, x0, y0, x1, y1)
WANDATA	*wa;
WANTYPE	*ipaddr;
float	x0, y0, x1, y1;
	{
	float	dx, dy, d;
	int	addit=0;

	if (!ipaddr->rep) {
		ipaddr->rep = (REPTYPE*)myalloc(NULL, 1, sizeof(REPTYPE));
		ipaddr->rep->wtobj = (caddr_t)ipaddr;
		addit = 1;
		}
	if (ipaddr->physparent->ifnumber &&
	   (ipaddr->physparent->ifnumber == ipaddr->ifnumber))
		ipaddr->rep->class = ARROW;
	else
		ipaddr->rep->class = NULL;
	ipaddr->rep->x1 = (x1-x0)*0.125+x0;
	ipaddr->rep->y1 = (y1-y0)*0.125+y0;
	dx = x0-ipaddr->rep->x1;
	dy = y0-ipaddr->rep->y1;
	d = dx*dx+dy*dy;
	if (d == 0.0) d = 1.0;
	d = RADIUS/fsqrt(d);
	ipaddr->rep->x0 = ipaddr->rep->x1+d*dx;
	ipaddr->rep->y0 = ipaddr->rep->y1+d*dy;
	ipaddr->rep->color = ORANGE;
	ipaddr->rep->r = RADIUS;
	if (addit) AddEntry(&(wa->replist), ipaddr->rep, NULL, 0);
	}


void
DrawWANStatus(wa)
WANDATA	*wa;
	{
	caddr_t	n;
	REPTYPE	*rep;
	char	s[256];

	n = wa->replist;
	totalcount = 0;
	totaldown = 0;
	while (NextEntry(&n, &rep)) {
		SetColor(rep->color);
		switch (rep->class) {
		case LINE:
			DrawLine(wa->da, rep->x0*wa->xscreen,
				wa->height-rep->y0*wa->yscreen,
				rep->x1*wa->xscreen,
				wa->height-rep->y1*wa->yscreen);
			totalcount ++;
			if (rep->color == RED) totaldown ++;
			break;
		case CLOUD:
			DrawWANStatusCloud(wa, rep->wtobj, rep->x0, rep->y0);
			totalcount ++;
			if (rep->color == RED) totaldown ++;
			break;
		default:;
			}
		}

	n = wa->replist;
	while (NextEntry(&n, &rep)) {
		SetColor(rep->color);
		switch (rep->class) {
		case CIRCLE:
			DrawCircle(wa->da, rep->x0*wa->xscreen,
				wa->height-rep->y0*wa->yscreen,
				rep->r*MINIMUM(wa->xscreen, wa->yscreen));
			break;
		case DOT:
			DrawDot(wa->da, rep->x0*wa->xscreen,
				wa->height-rep->y0*wa->yscreen,
				rep->r*MINIMUM(wa->xscreen, wa->yscreen));
			totalcount ++;
			if (rep->color == RED) totaldown ++;
			break;
		default:;
			}
		}

	if (wa->show_route) {
		n = wa->replist;
		while (NextEntry(&n, &rep)) {
			if (rep->class != ARROW) continue;
			SetColor(rep->color);
			SetLineWidth(2);
			DrawArrowHead(wa->da, rep->x0*wa->xscreen,
				wa->height-rep->y0*wa->yscreen,
				rep->x1*wa->xscreen,
				wa->height-rep->y1*wa->yscreen);
			SetLineWidth(1);
			}
		}

	sprintf(s, "%d, %d unreachable", totalcount, totaldown);
	XmTextSetString(wa->object_text, s);
	}


int
InsideWANStatus(wa, rep, x, y)
WANDATA	*wa;
REPTYPE	*rep;
int	x, y;
	{
	int	xs, ys, rs;

	switch (rep->class) {
	case CIRCLE:
	case DOT:
		rs = rep->r*MINIMUM(wa->xscreen, wa->yscreen);
		xs = rep->x0*wa->xscreen;
		ys = wa->height-rep->y0*wa->yscreen;
		if (x < xs-rs) return(0);
		if (y < ys-rs) return(0);
		if (x > xs+rs) return(0);
		if (y > ys+rs) return(0);
		return(1);
	case LINE:
		if (IntersectLine(x, y,
			rep->x0*wa->xscreen,
			wa->height-rep->y0*wa->yscreen,
			rep->x1*wa->xscreen,
			wa->height-rep->y1*wa->yscreen))
			return(1);
		break;
	case CLOUD:
		break;
	default:;
		}
	return(0);
	}


void
SelectWANStatusObject(wa, wt)
WANDATA	*wa;
WANTYPE	*wt;
	{
	REPTYPE	*rep;

	if (!wt->rep) return;
	rep = wt->rep;
	SetColor(BLUE);
	switch (rep->class) {
	case LINE:
		DrawLine(wa->da, rep->x0*wa->xscreen,
			wa->height-rep->y0*wa->yscreen,
			rep->x1*wa->xscreen,
			wa->height-rep->y1*wa->yscreen);
		break;
	case CIRCLE:
		DrawCircle(wa->da, rep->x0*wa->xscreen,
			wa->height-rep->y0*wa->yscreen,
			rep->r*MINIMUM(wa->xscreen, wa->yscreen));
		break;
	case DOT:
		DrawDot(wa->da, rep->x0*wa->xscreen,
			wa->height-rep->y0*wa->yscreen,
			rep->r*MINIMUM(wa->xscreen, wa->yscreen));
		break;
	default:;
		}
	}


void
DrawWANStatusObject(wa, wt)
WANDATA	*wa;
WANTYPE	*wt;
	{
	REPTYPE	*rep;

	if (!wt->rep) return;
	rep = wt->rep;
	SetColor(rep->color);
	switch (rep->class) {
	case LINE:
		DrawLine(wa->da, rep->x0*wa->xscreen,
			wa->height-rep->y0*wa->yscreen,
			rep->x1*wa->xscreen,
			wa->height-rep->y1*wa->yscreen);
	case CIRCLE:
		DrawCircle(wa->da, rep->x0*wa->xscreen,
			wa->height-rep->y0*wa->yscreen,
			rep->r*MINIMUM(wa->xscreen, wa->yscreen));
		break;
	case DOT:
		DrawDot(wa->da, rep->x0*wa->xscreen,
			wa->height-rep->y0*wa->yscreen,
			rep->r*MINIMUM(wa->xscreen, wa->yscreen));
		break;
	default:;
		}
	}


int
ParseLocation(wa, str, x, y)
WANDATA	*wa;
char	*str;
double	*x, *y;
	{
	char	buf[BUFSIZ], *c;
	float	lon, lat, xco, yco;
	int	k;

	*x = 0.0;
	*y = 0.0;
	if (!str) return(0);
	k = sscanf(str, "%f %f", &lon, &lat);
	if (k < 2) return(0);
	if (lon < 0.0)
		lon = (int)(lon-0.5);
	else
		lon = (int)(lon+0.5);
	if (lat < 0.0)
		lat = (int)(lat-0.5);
	else
		lat = (int)(lat+0.5);
	if (wa->project) {
		k = project(lat, lon, &xco, &yco, wa->lat, wa->lon, wa->dist);
		if (!k) {
			*x = 0.0;
			*y = 0.0;
			return(0);
			}
		}
	*x = (xco-wa->xmin)*wa->xscale;
	*y = (yco-wa->ymin)*wa->yscale;
	}


void
SetWANStatusRouteDest(widg, view, a)
Widget	widg;
VIEW	*view;
caddr_t	a;
	{
	char	*deststr, buf[BUFSIZ];
	WANDATA	*wa;
	caddr_t	n;
	WANTYPE	*wtobj;
	int	subscribe, request=False;
	REPTYPE	*ipaddr;

	wa = (WANDATA*)(view->panel->wa);
	if (wa->routedest) XtFree(wa->routedest);
	wa->routedest = XmTextGetString(wa->route_text);
	if (!strlen(wa->routedest)) {
		if (view->varcnt[OBJ_processor] == 2)
			view->varcnt[OBJ_processor] = 1;
		if (wa->routevar)
			subscribe = True;
		else
			subscribe = False;
		wa->routevar = NULL;
		request = False;
		}
	else {
		strcpy(buf, routestr);
		strcat(buf, wa->routedest);
		CreateVariable(buf, &(wa->routevar));
		view->varcnt[OBJ_processor] = 2;
		view->varlist[OBJ_processor][1] = wa->routevar;
		subscribe = True;
		request = True;
		}
	if (subscribe) {
		n = wa->replist;
		while (NextEntry(&n, &ipaddr))
			if (ipaddr->class == ARROW)
				ipaddr->class = NULL;
		n = wa->objlist;
		while (NextEntry(&n, &wtobj))
			if (wtobj->class == OBJ_processor) {
				wtobj->ifnumber = 0;
				if (request)
					Q_RequestObjectVariable(wtobj->obj,
						view, wa->routevar);
				SubscribeObjectVariables(wtobj->obj);
				}
		if (wa->show_route) {
			expose = True;
			ExposeWANStatus(NULL, view->panel, NULL);
			}
		}
	}

void
SetWANStatusRouteOnOff(widg, panel, cb)
Widget		widg;
VIEWPANEL	*panel;
XmToggleButtonCallbackStruct	*cb;
	{
	WANDATA	*wa;

	wa = (WANDATA*)panel->wa;
	wa->show_route = cb->set;
	/*
	if (cb->set) {
		if (wa->routedest)
			XmTextSetString(wa->route_text, wa->routedest);
		}
	else
		XmTextSetString(wa->route_text, "");
	*/
	expose = True;
	ExposeWANStatus(NULL, panel, NULL);
	}


void
ConfigureWANStatus(view, var1, var2, value)
VIEW	*view;
char	*var1;
char	*var2;
char	*value;
	{
	WANDATA	*wa;

	wa = (WANDATA*)(view->panel->wa);
	if (strcmp(var1, "routedest") == 0) {
		XmTextSetString(wa->route_text, value);
		SetWANStatusRouteDest(NULL, view, NULL);
		}
	else if (strcmp(var1, "showroute") == 0) {
		wa->show_route = atoi(value);
		XmToggleButtonSetState(wa->route_onoff, wa->show_route, False);
		}
	}


void
SaveWANStatus(view)
VIEW	*view;
	{
	WANDATA	*wa;

	wa = (WANDATA*)(view->panel->wa);
	if (wa->routedest)
		PutConfiguration(ViewName(view), "routedest", wa->routedest, 2);
	PutConfiguration(ViewName(view), "showroute", wa->show_route, 1);
	}
