/*
 *
 *	view.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	<time.h>

#include	<X11/StringDefs.h>
#include	<X11/Intrinsic.h>
#include	<X11/Shell.h>
#include	<X11/Core.h>
#include	<Xm/Xm.h>


#include	"defines.h"
#include	"externs.h"
#include	"object.h"
#include	"variable.h"
#include	"viewpanel.h"
#include	"view.h"
#include	"new.h"
#include	"xsupport.h"

static char	buf[BUFSIZ];
static VIEW	*root=NULL;
static char	*nullstr = "";


VIEW*
AllocateView()
	{
	VIEW	*v, *p;

	v = (VIEW*)myalloc(NULL, 1, sizeof(VIEW));
	if (!root)
		root = v;
	else {
		for (p=root; p->next; p=p->next);
		p->next = v;
		}
	return(v);
	}


void
LoadView(view)
VIEW	*view;
	{
	switch (view->class) {
	case WANSTATUS:
		LoadWANStatus(view);
		break;
	case CUSTOMSTATUS:
		LoadCustomStatus(view);
		break;
	case SITESTATUS:
		LoadSiteStatus(view);
		break;
	case OBJECTDATA:
		LoadObjectData(view);
		break;
	case DEFAULT:
		LoadDefault(view);
		break;
	case STATUSLOG:
		LoadStatusLog(view);
		break;
	default:;
		}
	}


void
AnnounceObjectToViews(obj)
OBJECT	*obj;
	{
	VIEW	*p;

	for (p=root; p; p=p->next)
		AnnounceObjectToView(p, obj);
	}


void
AnnounceObjectToView(view, obj)
VIEW	*view;
OBJECT	*obj;
	{
	switch (view->class) {
	case DEFAULT:
		Q_AddObjectToView(view, obj);
		break;
	case OBJECTDATA:
	case SITESTATUS:
		if (view->announce[obj->class]) {
			if (ObjectInViewObjectList(view, obj, 1))
				Q_AddObjectToView(view, obj);
			}
		break;
	default:
		if (view->announce[obj->class]) {
			if (ObjectInViewObjectList(view, obj, 0))
				Q_AddObjectToView(view, obj);
			}
		break;
		}
	}


void
AddViewParent(view, obj, parent, rel)
VIEW	*view;
OBJECT	*obj, *parent;
int	rel;
	{
	switch (view->class) {
	case WANSTATUS:
		AddWANStatusObject(view, parent, parent->class, parent->name);
		break;
	case CUSTOMSTATUS:
		AddCustomStatusParent(view, parent, parent->class,parent->name);
		break;
	case SITESTATUS:
		AddSiteStatusObject(view, parent, parent->class, parent->name);
		break;
	case DEFAULT:
		AddDefaultObject(view, parent, parent->class, parent->name);
		break;
	case STATUSLOG:
		break;
	default:;
		}
	AddViewToObject(parent, view);
	SubscribeObjectVariables(parent);
	UpdateViewParent(view, obj, parent, rel);
	}


void
AddObjectToView(view, obj)
VIEW	*view;
OBJECT	*obj;
	{
	switch (view->class) {
	case WANSTATUS:
		AddWANStatusObject(view, obj, obj->class, obj->name);
		break;
	case CUSTOMSTATUS:
		AddCustomStatusObject(view, obj, obj->class, obj->name);
		break;
	case SITESTATUS:
		AddSiteStatusObject(view, obj, obj->class, obj->name);
		break;
	case OBJECTDATA:
		AddObjectDataObject(view, obj, obj->class, obj->name);
		break;
	case DEFAULT:
		AddDefaultObject(view, obj, obj->class, obj->name);
		break;
	case STATUSLOG:
		AddStatusLogObject(view, obj, obj->class, obj->name);
		break;
	default:;
		}
	AddViewToObject(obj, view);
	SubscribeObjectVariables(obj);
	}


void
Q_AddObjectToView(view, obj)
VIEW	*view;
OBJECT	*obj;
	{
	WorkProc(AddObjectToView, 2, view, obj, NULL, NULL);
	}


void
Q_RemoveViewObject(view, obj)
VIEW	*view;
OBJECT	*obj;
	{
	WorkProc(RemoveViewObject, 2, view, obj, NULL, NULL);
	}


void
RemoveViewObject(view, obj)
VIEW	*view;
OBJECT	*obj;
	{
	switch (view->class) {
	case WANSTATUS:
		RemoveWANStatusObject(view->panel, obj);
		break;
	case CUSTOMSTATUS:
		RemoveCustomStatusObject(view->panel, obj);
		break;
	case SITESTATUS:
		RemoveSiteStatusObject(view->panel, obj);
		break;
	case OBJECTDATA:
		RemoveView(view);
		break;
	case STATUSLOG:
		RemoveStatusLogObject(view, obj);
		break;
	default:;
		}
	}



void
DestroyView(view)
VIEW	*view;
	{
	VIEW		**v;
	register	i;
	
	for (v=&root; *v; v=&((*v)->next)) {
		if (*v != view) continue;
		RemoveViewFromObjects(view);
		for (i=1; i<NUM_OBJCLASSES; i++) {
			free(view->objstr[i]);
			free(view->varstr[i]);
			free(view->varlist[i]);
			}
		if (view->name) free(view->name);
		DestroyViewPanel(view->panel);
		*v = view->next;
		free(view);
		break;
		}
	}



void
RemoveView(widg, view, a)
caddr_t	widg;
VIEW	*view;
caddr_t	a;
	{
	WorkProc(DestroyView, 1, view, NULL, NULL, NULL);
	}


void
OpenView(view)
VIEW	*view;
	{
	if (view->panel) OpenViewPanel(NULL, view->panel, NULL);
	switch (view->class) {
	case STATUSLOG:
		OpenStatusLog();
		break;
	default:;
		}
	}


int
ObjectInViewObjectList(view, obj, exactmatch)
VIEW	*view;
OBJECT	*obj;
int	exactmatch;
	{
	char	s[BUFSIZ];

	if (!(view->objstr[obj->class]))
		return(False);
	if (exactmatch) {
		strcpy(s, view->objstr[obj->class]);
		if (gettoken(s)) {
			if (strcmp(obj->name, s) == 0)
				return(True);
			else
				return(False);
			}
		else
			return(False);
		}
	return(InStrList(view->objstr[obj->class], obj->name));
	}


void
UpdateViewObject(view, obj, var, value, tsc)
VIEW		*view;
OBJECT		*obj;
caddr_t		var;
caddr_t		value;
unsigned int	tsc;
	{
	switch (view->class) {
	case WANSTATUS:
		UpdateWANStatusObject(view, obj, var, value, tsc);
		break;
	case CUSTOMSTATUS:
		UpdateCustomStatusObject(view, obj, var, value, tsc);
		break;
	case SITESTATUS:
		UpdateSiteStatusObject(view->panel, obj, var, value, tsc);
		break;
	case OBJECTDATA:
		UpdateObjectDataObject(view, obj, var, value, tsc);
		break;
	case DEFAULT:
		UpdateDefaultVariable(obj);
		break;
	case STATUSLOG:
		UpdateStatusLogObject(view, obj, var, value, tsc);
		break;
	default:;
		}
	}


void
UpdateViewParent(view, obj, parent, rel)
VIEW		*view;
OBJECT		*obj, *parent;
int		rel;
	{
	
	switch (view->class) {
	case WANSTATUS:
		UpdateWANStatusParent(view, obj, parent, rel);
		break;
	case CUSTOMSTATUS:
		UpdateCustomStatusParent(view, obj, parent, rel);
		break;
	case SITESTATUS:
		UpdateSiteStatusParent(view, obj, parent, rel);
		break;
	default:
		break;
		}
	}


void
Q_UpdateViewParent(view, obj, parent, rel)
VIEW		*view;
OBJECT		*obj, *parent;
int		rel;
	{
	WorkProc(UpdateViewParent, 4, view, obj, parent, rel);
	}


void
AddViewChild(view, obj, child, rel)
VIEW		*view;
OBJECT		*obj, *child;
int		rel;
	{
	
	switch (view->class) {
	case WANSTATUS:
		if (ObjectInViewObjectList(view, child, 0)) {
			AddObjectToView(view, child);
			UpdateViewParent(view, child, obj, rel);
			}
		break;
	case CUSTOMSTATUS:
		if (child->class == OBJ_ipaddr) {
			if (!ObjectInViewObjectList(view, child, 0))
				break;
			}
		AddCustomStatusChild(view, child, child->class, child->name,
			rel);
		AddViewToObject(child, view);
		SubscribeObjectVariables(child);
		UpdateViewParent(view, child, obj, rel);
		break;
	case SITESTATUS:
		if (child->class == OBJ_ipaddr)
			if (!ObjectInViewObjectList(view, child, 0)) break;
		AddObjectToView(view, child);
		UpdateViewParent(view, child, obj, rel);
		break;
	default:
		break;
		}
	}


void
Q_AddViewChild(view, obj, child, rel)
VIEW		*view;
OBJECT		*obj, *child;
int		rel;
	{
	WorkProc(AddViewChild, 4, view, obj, child, rel);
	}


void
Q_AddViewParent(view, obj, parent, rel)
VIEW		*view;
OBJECT		*obj, *parent;
int		rel;
	{
	WorkProc(AddViewParent, 4, view, obj, parent, rel);
	}


void
UpdateViewChild(view, obj, child, rel)
VIEW		*view;
OBJECT		*obj, *child;
int		rel;
	{
	
	switch (view->class) {
	case WANSTATUS:
		if (child->class != OBJ_ipaddr) break;
		if (ObjectInViewObjectList(view, child, 0)) {
			AddObjectToView(view, child);
			UpdateViewParent(view, child, obj, rel);
			}
		break;
	case CUSTOMSTATUS:
		UpdateCustomStatusChild(view, obj, child, rel);
		break;
	case SITESTATUS:
		if (child->class == OBJ_ipaddr) {
			if (rel == IPPARENT) break;
			if (!ObjectInViewObjectList(view, child, 0)) break;
			}
		AddObjectToView(view, child);
		UpdateViewParent(view, child, obj, rel);
		break;
	default:
		break;
		}
	}


void
Q_UpdateViewChild(view, obj, child, rel)
VIEW		*view;
OBJECT		*obj, *child;
int		rel;
	{
	WorkProc(UpdateViewChild, 4, view, obj, child, rel);
	}


void
ClearViews()
	{
	VIEW	*p;

	for (p=root; p; p=p->next) {
		switch (p->class) {
		case WANSTATUS:
			ClearWANStatus(p);
			break;
		case CUSTOMSTATUS:
			ClearCustomStatus(p);
			break;
		case SITESTATUS:
			ClearSiteStatus(p);
			break;
		case OBJECTDATA:
			ClearObjectData(p);
			break;
		case STATUSLOG:
			ClearStatusLog();
			break;
		default:;
			}
		}
	}


char*
ViewTitle(view)
VIEW	*view;
	{
	if (!view) return(nullstr);
	if (!view->panel) return(ViewClassTitle(view->class));
	return(view->panel->title);
	}


char*
ViewName(view)
VIEW	*view;
	{
	if (!view) return(nullstr);
	if (!view->panel) return(ViewClassName(view->class));
	return(view->panel->name);
	}


void
MergeViewVariables(viewlist, class, vars, interval, recvonly, count)
caddr_t	viewlist;
int	class;
caddr_t	**vars;
int	**interval, **recvonly, *count;
	{
	caddr_t	*varlist, n, *viewvars;
	VIEW	*view;
	register	i, j;
	int	*inter, *recv, size=16, k=0;

	varlist = (caddr_t*)myalloc(NULL, size, sizeof(caddr_t));
	inter = (int*)myalloc(NULL, size, sizeof(int));
	recv = (int*)myalloc(NULL, size, sizeof(int));
	n = viewlist;
	while (NextEntry(&n, &view)) {
		viewvars = view->varlist[class];
		if (!viewvars) continue;
		for (i=0; i<view->varcnt[class]; i++) {
			for (j=0; j<k; j++)
				if (varlist[j] == viewvars[i]) {
					if (view->recvonly) break;
					recv[j] = 0;
					if (view->interval < inter[j]) 
						inter[j] = view->interval;
					break;
					}
			if (j == k) {
				if (k == size) {
					size += 16;
					varlist = (caddr_t*)myalloc(varlist,
						size, sizeof(caddr_t));
					inter = (int*)myalloc(inter, size,
						sizeof(int));
					recv = (int*)myalloc(recv, size,
						sizeof(int));
					}
				varlist[k] = viewvars[i];
				inter[k] = view->interval;
				recv[k] = view->recvonly;
				k ++;
				}
			}
		}
	*vars = varlist;
	*interval = inter;
	*recvonly = recv;
	*count = k;
	}


int
ViewRecvonly(view)
VIEW	*view;
	{
	return(view->recvonly);
	}


void
SaveViews()
	{
	VIEW		*p;
	char		buf[BUFSIZ];
	register	i;

	for (p=root; p; p=p->next) {
		PutConfiguration(ViewName(p), "interval", p->interval, 1);
		switch (p->class) {
		case WANSTATUS:
			SaveViewPanel(p->panel, 1);
			PutConfiguration(ViewName(p), "background",
				GetBackgroundName(p->background), 2);
			strcpy(buf, "object.");
			strcat(buf, obj_class_names[OBJ_processor]);
			PutConfiguration(ViewName(p), buf,
				p->objstr[OBJ_processor], 3);
			strcpy(buf, "object.");
			strcat(buf, obj_class_names[OBJ_ipaddr]);
			PutConfiguration(ViewName(p), buf,
				p->objstr[OBJ_ipaddr], 3);
			SaveWANStatus(p);
			break;
		case CUSTOMSTATUS:
			SaveViewPanel(p->panel, 1);
			strcpy(buf, "object.");
			strcat(buf, obj_class_names[OBJ_network]);
			PutConfiguration(ViewName(p), buf,
				p->objstr[OBJ_network], 3);
			strcpy(buf, "object.");
			strcat(buf, obj_class_names[OBJ_subnet]);
			PutConfiguration(ViewName(p), buf,
				p->objstr[OBJ_subnet], 3);
			strcpy(buf, "object.");
			strcat(buf, obj_class_names[OBJ_ipaddr]);
			PutConfiguration(ViewName(p), buf,
				p->objstr[OBJ_ipaddr], 3);
			strcpy(buf, "object.");
			strcat(buf, obj_class_names[OBJ_site]);
			PutConfiguration(ViewName(p), buf,
				p->objstr[OBJ_site], 3);
			strcpy(buf, "object.");
			strcat(buf, obj_class_names[OBJ_processor]);
			PutConfiguration(ViewName(p), buf,
				p->objstr[OBJ_processor], 3);
			SaveCustomStatus(p);
			break;
		case SITESTATUS:
			SaveViewPanel(p->panel, 1);
			strcpy(buf, "object.");
			strcat(buf, obj_class_names[OBJ_ipaddr]);
			PutConfiguration(ViewName(p), buf,
				p->objstr[OBJ_ipaddr], 3);
			strcpy(buf, "object.");
			strcat(buf, obj_class_names[OBJ_site]);
			PutConfiguration(ViewName(p), buf,
				p->objstr[OBJ_site], 3);
			break;
		case STATUSLOG:
			SaveViewPanel(p->panel, 0);
			for (i=1; i<NUM_OBJCLASSES; i++) {
				strcpy(buf, "object.");
				strcat(buf, obj_class_names[i]);
				PutConfiguration(ViewName(p), buf, p->objstr[i],
					3);
				}
			SaveStatusLog(p);
			break;
		case DEFAULT:
			for (i=1; i<NUM_OBJCLASSES; i++) {
				strcpy(buf, "variable.");
				strcat(buf, obj_class_names[i]);
				PutConfiguration(ViewName(p), buf, p->varstr[i],
					3);
				}
			for (i=1; i<NUM_OBJCLASSES; i++) {
				strcpy(buf, "object.");
				strcat(buf, obj_class_names[i]);
				PutConfiguration(ViewName(p), buf, p->objstr[i],
					3);
				}
			PutConfiguration(ViewName(p), "background",
				GetBackgroundName(p->background), 2);
			break;
		case OBJECTDATA:
			SaveViewPanel(p->panel, 1);
			for (i=1; i<NUM_OBJCLASSES; i++) {
				strcpy(buf, "variable.");
				strcat(buf, obj_class_names[i]);
				PutConfiguration(ViewName(p), buf, p->varstr[i],
					3);
				}
			for (i=1; i<NUM_OBJCLASSES; i++) {
				strcpy(buf, "object.");
				strcat(buf, obj_class_names[i]);
				PutConfiguration(ViewName(p), buf, p->objstr[i],
					3);
				}
		default:;
			}
		}
	}


void
GetObjectClass(s, class)
char	*s;
int	*class;
	{
	register	i;

	for (i=1; i<NUM_OBJCLASSES; i++)
		if (strcmp(s, obj_class_names[i]) == 0) {
			*class = i;
			return;
			}
	*class = 0;
	}


void
ConfigureView(view, variable, value)
char	*view;
char	*variable;
char	*value;
	{
	VIEW		*p;
	char		buf[BUFSIZ], *c;
	register	i;
	static VIEW	*lastview=NULL;
	VIEW		*v;
	int		viewclass, viewid, objectclass;

	if ((lastview) && (strcmp(lastview->name, view) == 0))
		v = lastview;
	else
		for (v=root; v; v=v->next)
			if (strcmp(view, v->name) == 0) break;
	if (!v) {
		if (!ParseViewName(view, &viewclass, &viewid)) {
			return;
			}
		else {
			v = AllocateView();
			InitNewView(v, view, viewclass, viewid);
			switch (viewclass) {
			case WANSTATUS:
			case CUSTOMSTATUS:
			case SITESTATUS:
			case OBJECTDATA:
				AddViewButton(v->panel, view);
			default:;
				}
			LoadView(v);
			}
		}
	lastview = v;
	if (ConfigureViewPanel(v->panel, variable, value)) return;
	if (c=strchr(variable, '.')) {
		*c = '\0';
		c ++;
		}
	if (strcmp(variable, "interval") == 0) {
		v->interval = atoi(value);
		}
	else if (strcmp(variable, "background") == 0) {
		v->background = GetBackgroundId(value);
		}
	else if (strcmp(variable, "variable") == 0) {
		GetObjectClass(c, &objectclass);
		if (objectclass)
			v->varstr[objectclass] = newstr(value);
		}
	else if (strcmp(variable, "object") == 0) {
		GetObjectClass(c, &objectclass);
		if (objectclass)
			v->objstr[objectclass] = newstr(value);
		}
	else
		switch (viewclass) {
		case WANSTATUS:
			ConfigureWANStatus(v, variable, c, value);
			break;
		case CUSTOMSTATUS:
			ConfigureCustomStatus(v, variable, c, value);
			break;
		case STATUSLOG:
			ConfigureStatusLog(v, variable, c, value);
			break;
		default:;
			}
	}
