/*
 *
 *	sitestatus.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	<stdlib.h>
#include	<string.h>
#include	<math.h>

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

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

#define		RADIUS		7
#define		FATLINE		1
#define		ARC		2
#define		DOT		3
#define		CIRCLE		4
#define		COS		x0
#define		SIN		y0
#define		RAD0		x1
#define		RAD1		y1

typedef		struct	reptype	{
		int		class, color;
		float		x0, y0, x1, y1, r;
		caddr_t		stobj;
		char		*label;
		int		labellen;
		} REPTYPE;

typedef		struct	sitetype	{
		caddr_t		obj;
		REPTYPE		*rep;
		int		class;
		struct sitetype	*ipparent;
		struct sitetype	*physparent;
		int		status;
		char		*name;
		} SITETYPE;

typedef		struct SITESTATUSDATA	{
		caddr_t		objlist;
		caddr_t		replist;
		Widget		da;
		float		xmin, xmax, ymin, ymax;
		float		screen, scale, margin;
		int		width, height, xcenter, ycenter;
		int		nprocs, nsubs;
		int		font, maxsublbl, maxproclbl;
		int		drawsublbl, drawproclbl;
		SITETYPE	*selected;
		} SITESTATUSDATA;

static caddr_t	reachvar;


/*
 *	Add an object to the view.
 */
void
AddSiteStatusObject(view, obj, class, name)
VIEW	*view;
caddr_t	obj;
int	class;
char	*name;
	{
	SITESTATUSDATA	*sd;
	SITETYPE	*st;
	VIEWPANEL	*panel;
	
	panel = view->panel;
	sd = (SITESTATUSDATA*)panel->wa;
	if (FindEntry(sd->objlist, CompareSiteStatusObject, obj, NULL, &st))
		return;
	st = (SITETYPE*)myalloc(NULL, 1, sizeof(SITETYPE));
	st->name = name;
	st->class = class;
	st->obj = obj;
	st->status = STATUS_UNKNOWN;
	AddEntry(&(sd->objlist), st, CompareSiteStatusObjectByName, 0);
	switch (class) {
	case OBJ_site:
		AddObjectChildToView(obj, view, OBJ_processor, PHYSPARENT);
		break;
	case OBJ_subnet:
		Q_RequestObjectVariable(obj, view, reachvar);
		sd->nsubs ++;
		AdjustSiteStatusMargins(sd);
		RenderSiteStatus(sd);
		ExposeSiteStatus(NULL, panel, NULL);
		break;
	case OBJ_processor:
		Q_RequestObjectVariable(obj, view, reachvar);
		sd->nprocs ++;
		AddObjectChildToView(obj, view, OBJ_ipaddr, PHYSPARENT);
		AdjustSiteStatusMargins(sd);
		RenderSiteStatus(sd);
		ExposeSiteStatus(NULL, panel, NULL);
		break;
	case OBJ_ipaddr:
		Q_RequestObjectVariable(obj, view, reachvar);
		AddObjectParentToView(obj, view, IPPARENT);
		break;
	default:;
		}
	}


/*
 *	Determine margins for view.
 */
void
AdjustSiteStatusMargins(sd)
SITESTATUSDATA	*sd;
	{
	int		pm, sm, fnt, subdraw, tw, a, rad, procdraw;

	rad = MINIMUM(sd->width,sd->height);
	sd->screen = (float)rad/(sd->ymax-sd->ymin);
	rad /= 2;
	fnt = 2;
	subdraw = 1;
	procdraw = 1;
	sm = sd->maxsublbl*TextWidth(fnt, "_", 1);
	if (sm > rad) {
		fnt = 1;
		sm = sd->maxsublbl*TextWidth(fnt, "_", 1);
		if (sm > rad) {
			fnt = 1;
			subdraw = 0;
			}
		}
	pm = MINIMUM(sd->maxproclbl, 10)*TextWidth(fnt, "_", 1);
	a = (rad-pm)/(sd->nsubs+1);
	if (a < FontAscent(fnt)) {
		fnt = 1;
		subdraw = 0;
		}
	if (!subdraw) {
		a = 6.28*(rad-pm);
		if (sd->nprocs)
			a = a/sd->nprocs;
		if (a < FontAscent(fnt)) {
			procdraw = 0;
			pm = 0;
			}
		}
	sd->font = fnt;
	sd->margin = pm;
	sd->drawproclbl = procdraw;
	sd->scale = (rad-sd->margin)/rad;
	sd->drawsublbl = subdraw;
	}


/*
 *	Clear site status work area.
 */
void
ClearSiteStatus(view)
VIEW	*view;
	{
	SITESTATUSDATA	*sd;
	caddr_t		oe;
	SITETYPE	*st;
	
	sd = (SITESTATUSDATA*)(view->panel->wa);
	oe = sd->objlist;
	while (NextEntry(&oe, &st))
		RemoveViewFromObject(st->obj, view);
	RemoveEntryList(sd->objlist, free);
	RemoveEntryList(sd->replist, free);
	sd->objlist = NULL;
	sd->replist = NULL;
	sd->nprocs = 0;
	sd->nsubs = 0;
	ExposeSiteStatus(NULL, view->panel, NULL);
	}


/*
 *	Compare object data.
 */
int
CompareSiteStatusObject(data, obj, a2)
SITETYPE	*data;
caddr_t	obj;
caddr_t	a2;
	{
	if (data->obj == obj)
		return(0);
	else
		return(-1);
	}


/*
 *	Compare two objects by name.
 */
int
CompareSiteStatusObjectByName(data, st)
SITETYPE	*data, *st;
	{
	return(strcmp(data->name, st->name)); 
	}
	
	
/*
 *	Destroy site status work area.
 */
void
DestroySiteStatus(panel)
VIEWPANEL	*panel;
	{
	SITESTATUSDATA	*sd;
	
	sd = (SITESTATUSDATA*)panel->wa;
	RemoveEntryList(sd->objlist, free);
	RemoveEntryList(sd->replist, free);
	XtDestroyWidget(sd->da);
	free(sd);
	}
		
			
/*
 *	Show display list.
 */
void
DrawSiteStatus(sd)
SITESTATUSDATA	*sd;
	{
	caddr_t	n;
	REPTYPE	*rep;
	float	scale, x0, y0, x1, y1, x2, y2;
	
	scale = sd->screen*sd->scale;
	n = sd->replist;
	SetFont(sd->font);
	while (NextEntry(&n, &rep)) {
		if (rep->class != FATLINE) continue;
		x0 = rep->COS*rep->RAD0;
		y0 = rep->SIN*rep->RAD0;
		x1 = rep->COS*(rep->RAD0+2*rep->r);
		y1 = rep->SIN*(rep->RAD0+2*rep->r);
		x2 = rep->COS*rep->RAD1;
		y2 = rep->SIN*rep->RAD1;
		SetColor(GREY);
		DrawLine(sd->da,
			sd->xcenter+x0*scale,
			sd->ycenter-y0*scale,
			sd->xcenter+x2*scale,
			sd->ycenter-y2*scale);
		SetColor(rep->color);
		SetLineWidth((int)(2*rep->r*scale));
		DrawLine(sd->da,
			sd->xcenter+x0*scale,
			sd->ycenter-y0*scale,
			sd->xcenter+x1*scale,
			sd->ycenter-y1*scale);
		SetLineWidth(1);
		if (!sd->drawproclbl) continue;
		SetColor(WHITE);
		DrawAngledText(sd->da,
			sd->xcenter+x1*scale,
			sd->ycenter-y1*scale,
			rep->COS, rep->SIN,
			rep->label, rep->labellen);
		}
	n = sd->replist;
	while (NextEntry(&n, &rep)) {
		SetColor(rep->color);
		if (rep->class == ARC) {
			DrawArc(sd->da,
				sd->xcenter+rep->x0*scale,
				sd->ycenter-rep->y0*scale,
				rep->r*scale);
			SetColor(WHITE);
			DrawText(sd->da,
				(float)sd->xcenter-TextWidth(sd->font,
				rep->label, rep->labellen)-2,
				sd->ycenter+rep->r*scale,
				rep->label, rep->labellen);
			}
		else if (rep->class == CIRCLE)
			DrawCircle(sd->da,
				sd->xcenter+rep->x0*scale,
				sd->ycenter-rep->y0*scale,
				rep->r*scale);
		}
	n = sd->replist;
	while (NextEntry(&n, &rep)) {
		if (rep->class != DOT) continue;
		SetColor(rep->color);
		DrawDot(sd->da,
			sd->xcenter+rep->x0*scale,
			sd->ycenter-rep->y0*scale,
			rep->r*scale+1);
		}
	}


/*
 *	Assign status and draw one ipaddr.
 */
void
DrawSiteStatusIpaddr(sd, ipaddr)
SITESTATUSDATA	*sd;
SITETYPE		*ipaddr;
	{
	REPTYPE	*rep;
	
	rep = ipaddr->rep;
	if (!rep) return;
	rep->color = StatusColor(ipaddr->status);
	DrawSiteStatusObject(sd, ipaddr);
	}


/*
 *	Draw an object.
 */
void
DrawSiteStatusObject(sd, st)
SITESTATUSDATA	*sd;
SITETYPE	*st;
	{
	REPTYPE	*rep;
	float	scale, x0, y0, x1, y1;

	if (!st->rep) return;
	rep = st->rep;
	SetColor(rep->color);
	scale = sd->scale*sd->screen;
	switch (rep->class) {
	case FATLINE:
		x0 = rep->COS*rep->RAD0;
		y0 = rep->SIN*rep->RAD0;
		x1 = rep->COS*(rep->RAD0+2*rep->r);
		y1 = rep->SIN*(rep->RAD0+2*rep->r);
		SetLineWidth((int)(2*rep->r*scale));
		DrawLine(sd->da,
			sd->xcenter+x0*scale,
			sd->ycenter-y0*scale,
			sd->xcenter+x1*scale,
			sd->ycenter-y1*scale);
		SetLineWidth(1);
		break;
	case ARC:
		DrawArc(sd->da,
			sd->xcenter+rep->x0*scale,
			sd->ycenter-rep->y0*scale,
			rep->r*scale);
		break;
	case CIRCLE:
		DrawCircle(sd->da,
			sd->xcenter+rep->x0*scale,
			sd->ycenter-rep->y0*scale,
			rep->r*scale);
		break;
	case DOT:
		DrawDot(sd->da,
			sd->xcenter+rep->x0*scale,
			sd->ycenter-rep->y0*scale,
			rep->r*scale+1);
		break;
	default:;
		}
	}


/*
 *	Assign status and draw one processor.
 */
void
DrawSiteStatusProcessor(sd, proc)
SITESTATUSDATA	*sd;
SITETYPE		*proc;
	{
	REPTYPE	*rep;
	
	rep = proc->rep;
	if (!rep) return;
	rep->color = StatusColor(proc->status);
	DrawSiteStatusObject(sd, proc);
	}


/*
 *	Assign status and draw one subnet.
 */
void
DrawSiteStatusSubnet(sd, subnet)
SITESTATUSDATA	*sd;
SITETYPE		*subnet;
	{
	REPTYPE	*rep;
	
	rep = subnet->rep;
	if (!rep) return;
	rep->color = StatusColor(subnet->status);
	DrawSiteStatusObject(sd, subnet);
	}
	
	
/*
 *	Handle the expose events.
 */
void
ExposeSiteStatus(widg, panel, call_data)
Widget	widg;
VIEWPANEL	*panel;
XmDrawingAreaCallbackStruct		*call_data;
	{
	SITESTATUSDATA	*sd;
	
	if (!XtIsRealized(panel->shell)) return;
	sd = (SITESTATUSDATA*)panel->wa;
	ClearWindow(sd->da);
	DrawSiteStatus(sd);
	}


/*
 *	Initialize site status code.
 */
void
InitializeSiteStatus()
	{
	CreateVariable("hnmsObjReachStatus.0", &reachvar);
	}


/*
 *	Handle object selection.
 */
void
InputSiteStatus(widg, sd, calldata)
Widget	widg;
SITESTATUSDATA	*sd;
XmDrawingAreaCallbackStruct	*calldata;
	{
	XEvent	*e;
	caddr_t	n;
	REPTYPE	*rt;
	int	in;
	
	e = calldata->event;
	if (e->xbutton.button != Button1) return;
	if (e->type == ButtonPress) {
		n = sd->replist;
		while (NextEntry(&n, &rt)) {
			in = InsideSiteStatus(sd, rt, e->xbutton.x,
				e->xbutton.y);
			if (in) sd->selected = (SITETYPE*)rt->stobj;
			}
		if (sd->selected) {
			SetCurrentObject(sd->selected->obj);
			SelectSiteStatusObject(sd, sd->selected);
			}
		}
	else if (e->type == ButtonRelease) {
		if (sd->selected) {
			DrawSiteStatusObject(sd, sd->selected);
			sd->selected = NULL;
			}
		}
	}


/*
 *	Determine if object was selected.
 */
int
InsideSiteStatus(sd, rep, x, y)
SITESTATUSDATA	*sd;
REPTYPE		*rep;
int	x, y;
	{
	int	r1, r2, xs, ys, rs, d;
	float	scale;

	scale = sd->scale*sd->screen;
	switch (rep->class) {
	case FATLINE:
		rs = rep->r*scale;
		xs = sd->xcenter+rep->COS*(rep->RAD0+rep->r)*scale;
		ys = sd->ycenter-rep->SIN*(rep->RAD0+rep->r)*scale;
		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 DOT:
		rs = rep->r*scale+1;
		xs = sd->xcenter+rep->x0*scale;
		ys = sd->ycenter-rep->y0*scale;
		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 CIRCLE:
	case ARC:
		x = x-sd->xcenter;
		y = sd->ycenter-y;
		d = x*x+y*y;
		r1 = rep->r*scale+2.5;
		r1 = r1*r1;
		r2 = rep->r*scale-1.5;
		r2 = r2*r2;
		if (d > r1) return(0);
		if (d < r2) return(0);
		return(1);
		break;
	default:;
		}
	return(0);
	}


/*
 *	Create and load site status work area.
 */
void
LoadSiteStatus(view)
VIEW	*view;
	{
	VIEWPANEL	*panel;
	SITESTATUSDATA	*sd;
	
	panel = view->panel;
	sd = (SITESTATUSDATA*)myalloc(NULL, 1, sizeof(SITESTATUSDATA));
	panel->wa = (caddr_t)sd;
	sd->da = XtVaCreateManagedWidget("sitestatus",
		xmDrawingAreaWidgetClass,
		panel->viewform,
		XmNtopAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_FORM,
		XmNleftAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_FORM,
		XmNbackground, GetColor(BLACK),
		XmNresizePolicy, XmRESIZE_ANY,
		NULL);
	XtAddCallback(sd->da, XmNresizeCallback, ResizeSiteStatus, panel);
	XtAddCallback(sd->da, XmNexposeCallback, ExposeSiteStatus, panel);
	XtAddCallback(sd->da, XmNinputCallback, InputSiteStatus, sd);
	sd->xmin = 0;
	sd->xmax = ScreenHeight();
	sd->ymin = 0;
	sd->ymax = ScreenHeight();
	sd->scale = 1;
	sd->screen = 1;
	view->recvonly = 0;
	view->varlist[OBJ_processor] = (caddr_t*)myalloc(NULL, 1,
		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_ipaddr] = (caddr_t*)myalloc(NULL, 1,
		sizeof(caddr_t));
	view->varcnt[OBJ_ipaddr] = 1;
	view->varlist[OBJ_ipaddr][0] = reachvar;
	view->announce[OBJ_site] = 1;
	GetHelp(view->panel, 12, 1);
	AddRemoveButton(view, view->panel);
	}


/*
 *	Remove an object from the view.
 */
void
RemoveSiteStatusObject(panel, obj)
VIEWPANEL	*panel;
caddr_t	obj;
	{
	SITESTATUSDATA	*sd;
	SITETYPE	*st;
	
	sd = (SITESTATUSDATA*)panel->wa;
	if (!FindEntry(sd->objlist, CompareSiteStatusObject, obj, NULL, &st))
		return;
	RemoveSITETYPE(sd, st);
	}


/*
 *	Remove a site object list entry.
 */
void
RemoveSITETYPE(sd, st)
SITESTATUSDATA	*sd;
SITETYPE	*st;
	{
	if (st->rep)
		RemoveEntry(&(sd->replist), st->rep, free);
	RemoveEntry(&(sd->objlist), st, free);
	}
	

/*
 *	Assign coordinates to view objects.
 */
void
RenderSiteStatus(sd)
SITESTATUSDATA	*sd;
	{
	float	xinc=0, yinc=0, blocksize, dotsize;
	float	xco, yco, radius, procr, f;
	caddr_t	n;
	SITETYPE	*stobj;
	
	radius = (sd->ymax-sd->ymin)/2;
	yinc = radius/(sd->nsubs+1);
	if (sd->drawsublbl)
		xinc = 4.71;
	else
		xinc = 6.28;
	if (sd->nprocs)
		xinc = xinc/(sd->nprocs);
	blocksize = xinc*radius*0.75;
	blocksize = MINIMUM(yinc*0.75, blocksize);
	blocksize = MINIMUM(20., blocksize*0.5);
	dotsize = blocksize*0.3;
		xco = (-1.57);
	yco = radius-yinc;
	procr = radius-2*blocksize;
	
	n = sd->objlist;
	while (NextEntry(&n, &stobj)) {
		switch (stobj->class) {
		case OBJ_subnet:
			if (!stobj->rep) {
				stobj->rep = (REPTYPE*)myalloc(NULL, 1,
					sizeof(REPTYPE));
				stobj->rep->color = StatusColor(stobj->status);
				stobj->rep->stobj = (caddr_t)stobj;
				stobj->rep->label = stobj->name;
				stobj->rep->labellen = strlen(stobj->name);
				sd->maxsublbl = MAXIMUM(sd->maxsublbl,
					stobj->rep->labellen);
				AddEntry(&(sd->replist), stobj->rep, NULL, 0);
				}
			if (sd->drawsublbl)
				stobj->rep->class = ARC;
			else
				stobj->rep->class = CIRCLE;
			stobj->rep->x0 = 0.0;
			stobj->rep->y0 = 0.0;
			stobj->rep->r = yco;
			yco -= yinc;
			break;
		case OBJ_processor:
			if (!stobj->rep) {
				stobj->rep = (REPTYPE*)myalloc(NULL, 1,
					sizeof(REPTYPE));
				stobj->rep->class = FATLINE;
				stobj->rep->color = StatusColor(stobj->status);
				stobj->rep->stobj = (caddr_t)stobj;
				stobj->rep->label = stobj->name;
				stobj->rep->labellen = LabelLength(stobj->name);
				sd->maxproclbl = MAXIMUM(sd->maxproclbl,
					stobj->rep->labellen);
				AddEntry(&(sd->replist), stobj->rep, NULL, 0);
				}
			stobj->rep->COS = cos((double)xco);
			stobj->rep->SIN = sin((double)xco);
			stobj->rep->RAD0 = procr;
			stobj->rep->RAD1 = procr;
			stobj->rep->r = blocksize;
			xco += xinc;
			break;
		default:;
			}
		}
	n = sd->objlist;
	while (NextEntry(&n, &stobj)) {
		if (stobj->class != OBJ_ipaddr) continue;
		if (!stobj->ipparent || !stobj->physparent) continue;
		if (!stobj->rep) {
			stobj->rep = (REPTYPE*)myalloc(NULL, 1,sizeof(REPTYPE));
			stobj->rep->class = DOT;
			stobj->rep->color = StatusColor(stobj->status);
			stobj->rep->stobj = (caddr_t)stobj;
			AddEntry(&(sd->replist), stobj->rep, NULL, 0);
			}
		stobj->rep->x0 = stobj->physparent->rep->COS*
			stobj->ipparent->rep->r;
		stobj->rep->y0 = stobj->physparent->rep->SIN*
			stobj->ipparent->rep->r;
		if (stobj->physparent->rep->RAD1 > stobj->ipparent->rep->r)
			stobj->physparent->rep->RAD1 = stobj->ipparent->rep->r;
		stobj->rep->r = dotsize;
		}
	}
	

/*
 *	Resize site status view.
 */
void
ResizeSiteStatus(widg, panel, call_data)
Widget	widg;
VIEWPANEL	*panel;
caddr_t		*call_data;
	{
	Dimension	w, h;
	int		subdraw;
	SITESTATUSDATA	*sd;
	
	sd = (SITESTATUSDATA*)panel->wa;
	XtVaGetValues(sd->da,
		XmNwidth, &w,
		XmNheight, &h,
		NULL);
	if ((w == sd->width) && (h == sd->height)) return;

	sd->width = w;
	sd->height = h;
	sd->xcenter = w/2;
	sd->ycenter = h/2;
	sd->scale = 1;
	subdraw = sd->drawsublbl;
	AdjustSiteStatusMargins(sd);

	if (subdraw != sd->drawsublbl)
		RenderSiteStatus(sd);
	ExposeSiteStatus(NULL, panel, NULL);
	}


/*
 *	Indicate selected object.
 */
void
SelectSiteStatusObject(sd, st)
SITESTATUSDATA	*sd;
SITETYPE	*st;
	{
	REPTYPE	*rep;
	float	scale, x0, y0, x1, y1;

	if (!st->rep) return;
	rep = st->rep;
	SetColor(BLUE);
	scale = sd->scale*sd->screen;
	switch (rep->class) {
	case FATLINE:
		x0 = rep->COS*rep->RAD0;
		y0 = rep->SIN*rep->RAD0;
		x1 = rep->COS*(rep->RAD0+2*rep->r);
		y1 = rep->SIN*(rep->RAD0+2*rep->r);
		SetLineWidth((int)(2*rep->r*scale));
		DrawLine(sd->da,
			sd->xcenter+x0*scale,
			sd->ycenter-y0*scale,
			sd->xcenter+x1*scale,
			sd->ycenter-y1*scale);
		SetLineWidth(1);
		break;
	case ARC:
		DrawArc(sd->da,
			sd->xcenter+rep->x0*scale,
			sd->ycenter-rep->y0*scale,
			rep->r*scale);
		break;
	case CIRCLE:
		DrawCircle(sd->da,
			sd->xcenter+rep->x0*scale,
			sd->ycenter-rep->y0*scale,
			rep->r*scale);
		break;
	case DOT:
		DrawDot(sd->da,
			sd->xcenter+rep->x0*scale,
			sd->ycenter-rep->y0*scale,
			rep->r*scale+1);
		break;
	default:;
		}
	}


/*
 *	Update an object variable.
 */
void
UpdateSiteStatusObject(panel, obj, var, value, tsc)
VIEWPANEL	*panel;
caddr_t		obj;
caddr_t		var;
caddr_t		value;
unsigned int	tsc;
	{
	SITESTATUSDATA	*sd;
	SITETYPE	*stobj;
	
	if (var != reachvar) return;
	if (value == STATUS_NOSTATUS) value = (caddr_t)STATUS_UNKNOWN;
	sd = (SITESTATUSDATA*)panel->wa;
	if (!FindEntry(sd->objlist, CompareSiteStatusObject, obj, NULL,
		&stobj)) return;
	switch (stobj->class) {
	case OBJ_processor:
		stobj->status = (unsigned int)value;
		if (XtIsRealized(panel))
			DrawSiteStatusProcessor(sd, stobj);
		break;
	case OBJ_subnet:
		stobj->status = (unsigned int)value;
		if (XtIsRealized(panel))
			DrawSiteStatusSubnet(sd, stobj);
		break;
	case OBJ_ipaddr:
		stobj->status = (unsigned int)value;
		if (XtIsRealized(panel))
			DrawSiteStatusIpaddr(sd, stobj);
		break;
	default:;
		}
	}


/*
 *	Update an object parent relation.
 */
void
UpdateSiteStatusParent(view, obj, parent, rel)
VIEW	*view;
caddr_t	obj, parent;
int	rel;
	{
	SITESTATUSDATA	*sd;
	SITETYPE	*stobj, *stparent, *stipaddr;
	caddr_t		n;
	
	sd = (SITESTATUSDATA*)(view->panel->wa);
	if (!FindEntry(sd->objlist, CompareSiteStatusObject, obj, NULL,
		&stobj)) return;
	if (!FindEntry(sd->objlist, CompareSiteStatusObject, parent, NULL,
		&stparent)) stparent = NULL;
	switch (stobj->class) {
	case OBJ_processor:
		if (!stparent) {
			n = sd->objlist;
			while (NextEntry(&n, &stipaddr))
				if (stipaddr->physparent == stobj)
					RemoveSITETYPE(sd, stipaddr);
			RemoveSITETYPE(sd, stobj);
			sd->nprocs --;
			AdjustSiteStatusMargins(sd);
			RenderSiteStatus(sd);
			ExposeSiteStatus(NULL, view->panel, NULL);
			}
		else
			stobj->physparent = stparent;
		break;
	case OBJ_ipaddr:
		if (rel == IPPARENT) {
			if (stobj->ipparent == stparent) break;
			stobj->ipparent = stparent;
			if (!stparent) {
				if (stobj->rep) {
					RemoveEntry(&(sd->replist), stobj->rep,
						free);
					stobj->rep = NULL;
					}
				}
			AdjustSiteStatusMargins(sd);
			RenderSiteStatus(sd);
			ExposeSiteStatus(NULL, view->panel, NULL);
			}
		else if (rel == PHYSPARENT) {
			if (stobj->physparent == stparent) break;
			stobj->physparent = stparent;
			if (!stparent) RemoveSITETYPE(sd, stobj);
			AdjustSiteStatusMargins(sd);
			RenderSiteStatus(sd);
			ExposeSiteStatus(NULL, view->panel, NULL);
			}
		break;
	default:;
		}
	}
