/*
 *
 *	statuslog.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	<Xm/Label.h>
#include	<Xm/Text.h>
#include	<Xm/Form.h>
#include	<Xm/Frame.h>
#include	<Xm/ScrolledW.h>
#include	<Xm/List.h>
#include	<Xm/PushB.h>
#include	<Xm/ToggleB.h>
#include	<Xm/RowColumn.h>
#include	<Xm/Separator.h>
#include	<Xm/PanedW.h>

#include	"defines.h"
#include	"externs.h"
#include	"object.h"
#include	"viewpanel.h"
#include	"view.h"
#include	"xsupport.h"
#include	"statuslog.h"

#define		NUM_STATUS	4

typedef		struct	statdata	{
		OBJECT	*obj;
		int	status;
		int	log;
		int	bell;
		} STATDATA;

static STATDATA	*current_data = NULL;

static char	buf[BUFSIZ];
static int	count=0, lastlist=0, flashing=False, unreachable=0, total=0;
static Widget	object_count, unreachable_count;
static Widget	status_text, logbtn, bellbtn;
static VIEW	*statuslog;
static VIEWPANEL	*statusedit;
static caddr_t	reachvar;
static int	statuson[4] = {1, 1, 1, 1};
static int	statusclass[4] =
		{
		OBJ_subnet,
		OBJ_ipaddr,
		OBJ_processor,
		OBJ_interface,
		};
static caddr_t	*objl[4];
static int	statusrecord[NUM_OBJCLASSES] =
		{ /* record, object list */
		0,
		0,		/* agent */
		0,		/* internet */
		0,		/* network */
		0,		/* subnet */
		1,		/* ipaddress */
		0,		/* site */
		2,		/* processor */
		3,		/* interface */
		0,		/* equipment */
		0,		/* administrator */
		0,		/* module */
		};

static Widget	objlist[4], status_button;


/*
 *	Add an object to a list.
 */
void
AddStatusLogObject(v, obj, class, name)
VIEW	*v;
OBJECT	*obj;
int	class;
char	*name;
	{
	int		pos;
	XmString	xs;
	STATDATA	*data;
	register	i;

	data = (STATDATA*)myalloc(NULL, 1, sizeof(STATDATA));
	data->obj = obj;
	for (i=0; i<3; i++) {
		data->log = statuson[statusrecord[class]];
		data->bell = statuson[statusrecord[class]];
		}
	pos = AddEntry(&(objl[statusrecord[class]]), data, CompareStatusName,0);
	XmListAddItem(objlist[statusrecord[class]],
		(xs=X_STR(name)), pos);
	XmStringFree(xs);
	total ++;
	sprintf(buf, "%d", total);
	XmTextSetString(object_count, buf);
	Q_RequestObjectVariable(obj, v, reachvar);
	}


/*
 *	Clear the statuslog work area.
 */
void
ClearStatusLog()
	{
	register	i;

	for (i=0; i<4; i++) {
		XmListDeleteAllItems(objlist[i]);
		RemoveEntryList(objl[i], free);
		objl[i] = NULL;
		}
	XmTextSetString(status_text, "");
	XmTextSetString(object_count, "");
	XmTextSetString(unreachable_count, "");
	XmToggleButtonSetState(logbtn, 0, False);
	XmToggleButtonSetState(bellbtn, 0, False);
	current_data = NULL;
	total = 0;
	unreachable = 0;
	}


/*
 *	Compare two status log objects by name.
 */
int
CompareStatusName(listdata, newdata)
STATDATA	*listdata, *newdata;
	{
	strcmp(listdata->obj->name, newdata->obj->name);
	}


/*
 *	Compare two statuslog object pointers.
 */
int
CompareStatusObject(listdata, obj, a2)
STATDATA	*listdata;
OBJECT		*obj;
caddr_t		a2;
	{
	if (listdata->obj == obj) return(0);
	return(-1);
	}


/*
 *	Apply a configuration file record.
 */
void
ConfigureStatusLog(view, var1, var2, value)
VIEW	*view;
char	*var1;
char	*var2;
char	*value;
	{
	int	objectclass;

	GetObjectClass(var1, &objectclass);
	if (objectclass)
		statuson[statusrecord[objectclass]] = atoi(value);
	}


/*
 *	Make the status log panel.
 */
void
LoadStatusLog(view)
VIEW	*view;
	{
	Widget		l, f, b, w, m, pw;
	XmString	xs;
	int		i;

	statuslog = view;
	statuslog->panel->button = status_button;
	statuslog->panel->title = newstr("Object Reachability Status");
	XtAddCallback(status_button, XmNactivateCallback, OpenStatusLog,
		NULL);
	XmTextSetString(statuslog->panel->titletext,
		"Object Reachability Status");
	w = XtVaCreateManagedWidget("statuslog",
		xmFormWidgetClass,
		statuslog->panel->viewform,
		XmNleftAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_FORM,
		XmNtopAttachment, XmATTACH_FORM,
		NULL);
	m = XtVaCreateManagedWidget("statuslog",
		xmFormWidgetClass,
		w,
		XmNleftAttachment, XmATTACH_FORM,
		XmNleftOffset, 10,
		XmNrightAttachment, XmATTACH_NONE,
		XmNtopAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_FORM,
		NULL);
	object_count = labeled_text("text", m, 2, "Total Objects:");
	m = XtVaCreateManagedWidget("statuslog",
		xmFormWidgetClass,
		w,
		XmNleftAttachment, XmATTACH_WIDGET,
		XmNleftWidget, m,
		XmNrightAttachment, XmATTACH_NONE,
		XmNleftOffset, 5,
		XmNtopAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_FORM,
		NULL);
	unreachable_count = labeled_text("text", m, 2, "Unreachable:");
	m = XtVaCreateManagedWidget("objlogpanel",
		xmFormWidgetClass,
		statuslog->panel->viewform,
		XmNtopAttachment, XmATTACH_WIDGET,
		XmNtopWidget, w,
		XmNleftAttachment, XmATTACH_FORM,
		XmNleftOffset, 5,
		XmNrightAttachment, XmATTACH_FORM,
		XmNrightOffset, 5,
		XmNbottomAttachment, XmATTACH_FORM,
		XmNbottomOffset, 5,
		NULL);
	statuslog->panel->wa = CreateLog(m, "StatusLog");
	m = XmCreatePulldownMenu(statuslog->panel->optionmenu, "menu",
		NULL, 0);
	b = cbutton("cb", statuslog->panel->optionmenu, "Show", m);
	for (i=0; i<NUM_STATUS; i++) {
		b = XtVaCreateManagedWidget("tb",
			xmToggleButtonWidgetClass, m,
			XmNlabelString,
			(xs=X_STR((char*)obj_class_names[statusclass[i]])),
			NULL);
		XmToggleButtonSetState(b, 1, False);
		XtAddCallback(b, XmNvalueChangedCallback, ShowStatusClass, i);
		XmStringFree(xs);
		}
	statuslog->announce[OBJ_subnet] = 1;
	statuslog->objstr[OBJ_subnet] = newstr("*\n");
	statuslog->announce[OBJ_ipaddr] = 1;
	statuslog->objstr[OBJ_ipaddr] = newstr("*\n");
	statuslog->announce[OBJ_processor] = 1;
	statuslog->objstr[OBJ_processor] = newstr("*\n");
	statuslog->announce[OBJ_interface] = 1;
	statuslog->objstr[OBJ_interface] = newstr("*\n");
	
	statusedit = CreateViewPanel("EDIT:", "statuslogedit", 0, 0,
		"statuslog", 0, 0, 0);
	statusedit->title = newstr("Status Log Edit Panel");
	XmTextSetString(statusedit->titletext, "Status Log");
	f = XtVaCreateManagedWidget("form",
		xmFormWidgetClass,
		statusedit->viewform,
		XmNleftAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_FORM,
		XmNrightOffset, 5,
		XmNtopAttachment, XmATTACH_FORM,
		XmNtopOffset, 5,
		XmNbottomAttachment, XmATTACH_NONE,
		XmNbottomOffset, 5,
		NULL);
	logbtn = XtVaCreateManagedWidget("tb",
		xmToggleButtonWidgetClass, f,
		XmNlabelString, (xs=X_STR("Log")),
		XmNtopAttachment, XmATTACH_FORM,
		XmNleftAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_NONE,
		NULL);
	XmToggleButtonSetState(logbtn, 0, False);
	XtAddCallback(logbtn, XmNvalueChangedCallback, SetLogStatus, 0);
	XmStringFree(xs);
	bellbtn = XtVaCreateManagedWidget("tb",
		xmToggleButtonWidgetClass,
		f,
		XmNlabelString, (xs=X_STR("Bell")),
		XmNtopAttachment, XmATTACH_FORM,
		XmNleftAttachment, XmATTACH_NONE,
		XmNbottomAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_FORM,
		NULL);
	XmToggleButtonSetState(bellbtn, 0, False);
	XtAddCallback(bellbtn, XmNvalueChangedCallback, SetBellStatus, 0);
	XmStringFree(xs);
	status_text = XtVaCreateManagedWidget("text",
		xmTextWidgetClass,
		statusedit->viewform,
		XmNleftAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_FORM,
		XmNtopAttachment, XmATTACH_WIDGET,
		XmNtopWidget, f,
		XmNbottomAttachment, XmATTACH_NONE,
		XmNcursorPositionVisible, False,
		XmNsensitive, False,
		NULL);
	pw = XtVaCreateManagedWidget("statuslog",
		xmPanedWindowWidgetClass,
		statusedit->viewform,
		XmNleftAttachment, XmATTACH_FORM,
		XmNtopAttachment, XmATTACH_WIDGET,
		XmNtopWidget, status_text,
		XmNrightAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_FORM,
		NULL);
	for (i=0; i<4; i++) {
		f = XtVaCreateManagedWidget(obj_class_names[statusclass[i]],
			xmFormWidgetClass,
			pw,
			XmNwidth, 200,
			NULL);
		l = XtVaCreateManagedWidget("label",
			xmLabelWidgetClass,
			f,
			XmNleftAttachment, XmATTACH_FORM,
			XmNtopAttachment, XmATTACH_FORM,
			XmNrightAttachment, XmATTACH_FORM,
			XmNlabelString, (xs=X_STR((char*)obj_class_names[
				statusclass[i]])),
			NULL);
		XmStringFree(xs);
		objlist[i] = XmCreateScrolledList(f, "list", 0, 0);
		XtVaSetValues(XtParent(objlist[i]),
			XmNleftAttachment, XmATTACH_FORM,
			XmNtopAttachment, XmATTACH_WIDGET,
			XmNtopWidget, l,
			XmNrightAttachment, XmATTACH_FORM,
			XmNbottomAttachment, XmATTACH_FORM,
			NULL);
		XtVaSetValues(objlist[i],
			XmNvisibleItemCount, 2,
			NULL);
		XtManageChild(objlist[i]);
		XtAddCallback(objlist[i], XmNbrowseSelectionCallback,
			SelectStatusObject, (XtPointer)i);
		}
	b = pbutton("pb", statuslog->panel->optionmenu, "Edit");
	XtAddCallback(b, XmNactivateCallback, OpenStatusEdit, NULL);
	CreateVariable("hnmsObjReachStatus.0", &reachvar);
	statuslog->varlist[OBJ_processor] = (caddr_t*)myalloc(NULL, 1,
		sizeof(caddr_t));
	statuslog->varcnt[OBJ_processor] = 1;
	statuslog->varlist[OBJ_processor][0] = reachvar;
	statuslog->varlist[OBJ_subnet] = (caddr_t*)myalloc(NULL, 1,
		sizeof(caddr_t));
	statuslog->varcnt[OBJ_subnet] = 1;
	statuslog->varlist[OBJ_subnet][0] = reachvar;
	statuslog->varlist[OBJ_ipaddr] = (caddr_t*)myalloc(NULL, 1,
		sizeof(caddr_t));
	statuslog->varcnt[OBJ_ipaddr] = 1;
	statuslog->varlist[OBJ_ipaddr][0] = reachvar;
	statuslog->varlist[OBJ_interface] = (caddr_t*)myalloc(NULL, 2,
		sizeof(caddr_t));
	statuslog->varcnt[OBJ_interface] = 1;
	statuslog->varlist[OBJ_interface][0] = reachvar;
	GetHelp(statuslog->panel, 8, 1);
	GetHelp(statusedit, 9, 1);
	}


/*
 *	Open the status edit panel.
 */
void
OpenStatusEdit()
	{
	register	i;

	for (i=0; i<4; i++)
		XmListDeselectAllItems(objlist[i]);
	XmTextSetString(status_text, "");
	XmToggleButtonSetState(logbtn, 0, False);
	XmToggleButtonSetState(bellbtn, 0, False);
	OpenViewPanel(NULL, statusedit, NULL);
	}
	
	
/*
 *	Open the status log panel.
 */
void
OpenStatusLog()
	{
	if (flashing) {
		flashing = False;
		StopFlash(statuslog->panel->button, 0, STATBLK_PIXMAP);
		}
	OpenViewPanel(NULL, statuslog->panel, NULL);
	}


/*
 *	Remove an object from the log.
 */
void
RemoveStatusLogObject(v, obj)
VIEW	*v;
OBJECT	*obj;
	{
	STATDATA	*data;
	XmString	xs;

	if (!FindEntry(objl[statusrecord[obj->class]],CompareStatusObject,obj,
		NULL,&data)) return;
	if (data->status == 3) {
		unreachable --;
		sprintf(buf, "%d", unreachable);
		XmTextSetString(unreachable_count, buf);
		}
	RemoveEntry(&(objl[statusrecord[obj->class]]), data, free);
	XmListDeleteItem(objlist[statusrecord[obj->class]],
		(xs=X_STR(obj->name)));
	XmStringFree(xs);
	total --;
	sprintf(buf, "%d", total);
	XmTextSetString(object_count, buf);
	}


/*
 *	Save the status log configuration.
 */
void
SaveStatusLog(view)
VIEW	*view;
	{
	register	i;

	for (i=0; i<4; i++)
		PutConfiguration(ViewName(view),
			obj_class_names[statusclass[i]], statuson[i], 1);
	}


/*
 *	Select an object from a list.
 */
void
SelectStatusObject(w, indx, call_data)
Widget	w;
int	indx;
XmListCallbackStruct	*call_data;
	{
	STATDATA	*data;
	register	i;

	EntryAtPosition(objl[indx], call_data->item_position, &data);
	current_data = data;
	if (lastlist)
		XmListDeselectAllItems(objlist[lastlist]);
	lastlist = indx;
	XmTextSetString(status_text, exstr(call_data->item));
	XmToggleButtonSetState(logbtn, data->log, False);
	XmToggleButtonSetState(bellbtn, data->bell, False);
	}


/*
 *	Set the alarm for a specific object.
 */
void
SetBellStatus(widg, i, cb)
Widget	widg;
int	i;
XmToggleButtonCallbackStruct	*cb;
	{
	if (!current_data) return;
	current_data->bell = cb->set;
	}


/*
 *	Set logging for a specific object.
 */
void
SetLogStatus(widg, i, cb)
Widget	widg;
int	i;
XmToggleButtonCallbackStruct	*cb;
	{
	if (!current_data) return;
	current_data->log = cb->set;
	}


/*
 *	Make the status log button.
 */
void
SetStatusLogButton(btn)
Widget	btn;
	{
	status_button = btn;
	}


/*
 *	Set status to be shown for a class of object.
 */
void
ShowStatusClass(widg, class, cb)
Widget	widg;
int	class;
XmToggleButtonCallbackStruct	*cb;
	{
	statuson[class] = cb->set;
	}
	
	
/*
 *	Update a statuslog object variable.
 */
void
UpdateStatusLogObject(view, obj, var, value, tsc)
VIEW		*view;
OBJECT		*obj;
caddr_t		var;
unsigned int	value;
unsigned int	tsc;
	{
	STATDATA	*data;

	if (var != reachvar) return;
	if (!FindEntry(objl[statusrecord[obj->class]],CompareStatusObject,obj,
		NULL,&data)) return;
	if (value == data->status) return;
	if ((value < 0) || (value > 4)) return;
	if (value == STATUS_UNREACHABLE) {
		unreachable ++;
		sprintf(buf, "%d", unreachable);
		XmTextSetString(unreachable_count, buf);
		}
	else if (data->status == STATUS_UNREACHABLE) {
		unreachable --;
		sprintf(buf, "%d", unreachable);
		XmTextSetString(unreachable_count, buf);
		}
	if ((data->status==STATUS_NOSTATUS) || (data->status==STATUS_UNKNOWN)) {
		data->status = value;
		return;
		}
	if (data->log) {
		PrintToLog(statuslog->panel->wa,
			logbuf("%s: %s to %s at %s.\n", obj->name,
				status_strs[data->status], status_strs[value],
				get_time(tsc)));
		if (data->bell && (value == 3)) {
			Beep(1);
			if (!flashing &&
				!XtIsRealized(statuslog->panel->shell)) {
				flashing = True;
				StartFlash(statuslog->panel->button,
					STATBLK_PIXMAP, STATRED_PIXMAP, 1);
				}
			}
		}
	data->status = value;
	}
