/*
 *			X Based Display Program
 */
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include "../ProblemManager/ProblemManager.h"
#include "../Ctools/ctools.h"

#include <Xm/Xm.h> 
#include <X11/StringDefs.h>
#include <X11/Intrinsic.h>
#include <X11/Shell.h> 
#include <Xm/Form.h> 
#include <Xm/List.h> 
#include <Xm/ToggleB.h> 
#include <Xm/PushB.h> 
#include <Xm/Label.h> 
#include <Xm/Text.h> 
#include <Xm/RowColumn.h> 
#include <Xm/BulletinB.h> 
#include <Xm/SelectioB.h> 

#define HUMANTIME 1
#define ELAPSEDSEC 2
#define ELAPSEDMIN 3
#define LONGTIME 4
int TimeStampFormat=HUMANTIME;

XmString *ProblemEntries;		/* Pointer to array of XmString*/

char *DefaultPingkyDir=".";
char Checking_File[100];
long checkinglasttime;
char Problem_File[100];
long problemfilelasttime;
char CycleTime_File[100];
long cycletimelasttime;
char Log_File[100];
char Host_File[100];
long cycletimelasttime;
char Filter_File[100];		/* File name of the filter pattern specs */

Widget lista,Myclock;
Widget problemcounts,numproblems,cycletime,checkinglabel,checking;

#define MAXFILTERS 12
struct Filters {
	char *Name;		/* Name on PushButton */
	char *RegExp;		/* NodeName Reg Exp   */
	char *Pattern;		/* Compiled pattern   */
	Boolean Selected;	/* Is this net selected*/
	Widget Toggle;		/* Toggle Button	*/
	int count;		/* Count of items in net*/
	Widget Count;		/* Test widget for counts*/
} Filter[MAXFILTERS];

char *pingkydir, *getenv();

Widget helpdialog;
static char *helptextstr=NULL;

SetupFilters()
{
FILE *stream;
int i,line;
static char inbuffer[MAXFILTERS][100];
char buffer[200];

	for( i=0; i<MAXFILTERS; i++ ) Filter[i].Name=NULL;

	if ( ( stream = fopen( Filter_File, "r" )) == NULL ) return;

	for(i=0,line=1; fgets( inbuffer[i], 100, stream ) != NULL; line++) {
		if (inbuffer[i][0] == '#' ) continue;
		if ((Filter[i].Name=strtok(inbuffer[i]," \t\n"))==NULL) {
			fprintf(stderr,"Blank Line  in filter file: %s line %d \n",Filter_File, line);
			continue; /*BLANK*/
		}

		if ((Filter[i].RegExp=strtok(NULL," \t\n"))==NULL) {
			fprintf(stderr,"NULL Regular Expression in filterfile: %s line %d (%s)\n",Filter_File, line,Filter[i].Name );
			Filter[i].Name=NULL;
			continue;
		}
  		if ( ( Filter[i].Pattern = regcmp( Filter[i].RegExp, NULL ) ) == NULL ) {
			fprintf(stderr,"Error compiling %s regexp %s (%s)\n",Filter[i].Name, Filter[i].RegExp,Filter[i].Name);
			Filter[i].Name=NULL;
			continue;
		}
/*printf("Line %d: Filter[i].Name=%s Filter[i].RegExp=%s\n",line,Filter[i].Name,Filter[i].RegExp);*/
		Filter[i].Selected=True;
		Filter[i].count=0;
		if ( i++ >= MAXFILTERS ) {
			fprintf(stderr,"TOO MANY FILTERS in FILTER FILE %s (MAX=%d)\nIgnoring the rest\n",Filter_File, MAXFILTERS);
			break;
		}
	}	
	fclose(stream);
}

char *PrintTimeStamp( TimeStamp )
long TimeStamp;
{
static char buffer[20];
long TimeNow;

        switch( TimeStampFormat ) {
        case LONGTIME:  return( ltoa( TimeStamp, buffer ) );
                                /*NOTREACHED*/
        case HUMANTIME: sprintf(buffer,"%s_%s ",
                                        _Day( TimeStamp ), _Time( TimeStamp ));
                                return( buffer );
                                /*NOTREACHED*/
        case ELAPSEDMIN:        time( & TimeNow );
                                return( ltoa( (TimeNow-TimeStamp)/60, buffer) );
                                /*NOTREACHED*/
        case ELAPSEDSEC:        time( & TimeNow );
                                return( ltoa( (TimeNow-TimeStamp), buffer ) );
                                /*NOTREACHED*/
        default:                return("BADCALL");
                                /*NOTREACHED*/
        }
}

Update()
{
FILE *stream;
char buffer[100];

        if ( FileChanged( CycleTime_File, &cycletimelasttime) ) {
                XmTextSetString( cycletime, "READ.");
                if ((stream=fopen(CycleTime_File,"r"))==NULL)
                        syserr("update_time: CycleTime_File\n");
                fgets( buffer , sizeof(buffer), stream );
                fclose(stream);
                XmTextSetString( cycletime, buffer );
                FileChanged( CycleTime_File, &cycletimelasttime );
        }
        if ( FileChanged( Checking_File, &checkinglasttime) ) {
                XmTextSetString( checking, "READ.");
                if ((stream=fopen(Checking_File,"r"))==NULL)
                        syserr("update_time: Checking_File\n");
                fgets( buffer , sizeof(buffer), stream );
                fclose(stream);
                XmTextSetString( checking, &buffer[11] );
                FileChanged( Checking_File, &checkinglasttime );
        }

	Problem_Manager( CHECK, NULL, NULL, NULL, NULL );

	CreateProblemXmStrings();
}

/*
 *	update_time - Update our Myclock once a minute
 */
void update_time( w, id )
Widget w;
XtIntervalId id;
{
long tloc, rounded_tloc, next_minute;

	time(&tloc);
	rounded_tloc = tloc / 60 * 60;
/*printf("ctime=%s\n",ctime(&rounded_tloc) );*/

	XmTextSetString( w , ctime(&rounded_tloc) );

	Update();

	next_minute = (60 - tloc % 60) * 1000;
	XtAddTimeOut( next_minute, update_time, w );
}

/*
 *	List - Gets executed when user clicks on list entry
 */
void List( w , client_data, call_data )
Widget w;
caddr_t client_data;
XmListCallbackStruct *call_data;
{
char *buffer;

	printf("List callback\n");
	if (XmStringGetLtoR(call_data->item, XmSTRING_DEFAULT_CHARSET, &buffer))
		printf(buffer);
	else
		printf("Unrecognized charset");
	printf("\n");
}
/*
 *	FilterNetCallback - User selected one of the Toggle Buttons
 */
void FilterNetCallback( w , client_data, call_data )
Widget w;
caddr_t client_data;
XmListCallbackStruct *call_data;
{
Arg myArgs[10];
int i;

	/* Get toggle button states! */
	for( i=0; Filter[i].Name!=NULL; i++ ) {
		XtSetArg( myArgs[0], XmNset, &Filter[i].Selected );
		XtGetValues( Filter[i].Toggle,  myArgs, 1 );
	}
	CreateProblemXmStrings();
}
/*
 *	Filter - Actual Filter Routine ( called for each problem entry 
 */
int FilterProblem( p )
struct ProblemType *p;
{
extern char *regex();
int i;

	for( i=0; Filter[i].Name!=NULL; i++ ) {
		if ( regex( Filter[i].Pattern, p->Name ) != NULL ) {
			Filter[i].count++;
			if ( Filter[i].Selected==False) {
				printf("Filtered out %s Node %s\n", Filter[i].Name, p->Name);
				return(0);
			}
			else return(1); /* Matches pattern -user wants to see */
		}
		else;	/* See if we match the next one */
	}
	return(1);	/* No Match - user wants to see */
}

#define NUMTEXTENTRIES (sizeof(text)/sizeof(char *))

CreateProblemXmStrings()
{
static int virgin=1;
char buffer[100];
int i;
Cardinal n;
Arg myArgs[10];
extern char *itoa();
extern struct ProblemType ProblemArray[];/*In Coreversion of existing problems*/
extern int NumProblems;


	XtSetArg( myArgs[0], XmNlistItems, NULL );
	XtSetArg( myArgs[1], XmNlistItemCount, 0 );
	XtSetValues( lista, myArgs, 2 );
	if ( virgin ) {
  		ProblemEntries = (XmString *) XtMalloc(sizeof(XmString) * MAXPROBLEMS );
		virgin=0;
	}
	for( i=0; Filter[i].Name!=NULL; i++ ) Filter[i].count=0;
  	for(n=0,i=0; i < NumProblems; i++ ) {
		if ( FilterProblem( &ProblemArray[i] ) == 1 ) {
			sprintf(buffer,"%s %s %s %s ",PrintTimeStamp(ProblemArray[i].TimeStamp),
				ProblemArray[i].Name,ProblemArray[i].UniqueID,
					ProblemArray[i].TestName);
			while( strlen(buffer) < STATUSX ) strcat(buffer," ");
			if ( ProblemArray[i].StatusLine[0] != '\0' )
				strcat( buffer, ProblemArray[i].StatusLine );
        		ProblemEntries[n++] = XmStringCreate( buffer, XmSTRING_DEFAULT_CHARSET);
		}
	}
	ProblemEntries[n]=NULL;
	XtSetArg( myArgs[0], XmNlistItems, ProblemEntries );
	XtSetArg( myArgs[1], XmNlistItemCount, n );
	XtSetValues( lista, myArgs, 2 );
	
	XmTextSetString( numproblems, itoa( i, buffer ) );

        for( i=0; Filter[i].Name!=NULL; i++ ) 
		XmTextSetString(  Filter[i].Count, itoa( Filter[i].count, buffer ));
}

void ListaApplyCallback( w , client_data, call_data )	/* We label it Read Problem File */
Widget w;
caddr_t client_data;
XtCallbackList *call_data;
{
	Update();
}

void ListaCancelCallback( w , client_data, call_data )
Widget w;
caddr_t client_data;
XtCallbackList *call_data;
{
char *text;
XmString xmstr;
Arg myArgs[10];

	printf("Cancel\n");
	XtSetArg( myArgs[0], XmNtextString, &xmstr );
	XtGetValues( w, myArgs, 1 );
	if (XmStringGetLtoR( xmstr, XmSTRING_DEFAULT_CHARSET, &text ) != True)
		printf("Cancel: Error getting label\n");
	else
		if ( text!=NULL ) printf("text was =%s\n",text);
	xmstr=XmStringCreate( "" , XmSTRING_DEFAULT_CHARSET);
	XtSetArg( myArgs[0], XmNtextString, xmstr );
	XtSetValues( w, myArgs, 1 );
	XmListDeselectAllItems(w);
}

char *FindHelpFile( UniqueID )
char *UniqueID;
{
FILE *stream;
char buf[100],*p;
static char helpfile[100];

	if ((stream = fopen( Host_File, "r" ))==NULL) {
		fprintf(stderr,"FindHelpFile: Error opening hostfile %s\n",Host_File);
		return(NULL);
	}
	while( fgets( buf, sizeof(buf), stream ) != NULL ) {
		if (buf[0]=='#') continue;
		p=strtok(buf," \t\n"); if (p==NULL) continue;/*Name*/
		p=strtok(NULL," \t\n");if (p==NULL) continue; /*IP*/
		if (strcmp(p,UniqueID)==0) {
			fclose(stream);
			p=strtok(NULL," \t\n");if (p==NULL) continue; /* Helpfilename*/
			strcpy(helpfile,p);
			return(helpfile);
		}
	}
	fprintf(stderr,"FindHelpFile: Couldn't match %s in %s\n",UniqueID, Host_File);
	fclose(stream);
	return(NULL);
}

void HelpDone( w , client_data, call_data )    /* We label it Read Problem File */
Widget w;
caddr_t client_data;
XtCallbackList *call_data;
{
	printf("help done\n");
}

void ListaHelpCallback( w , client_data, call_data )	/* We label it Read Problem File */
Widget w;
caddr_t client_data;
XtCallbackList *call_data;
{
char *text,*helpfile,Help_File[100],*p;
XmString xmstr;
Arg myArgs[10];
Widget done, helptext;
Cardinal n;
struct stat stbuf;
int fd;

	printf("Help\n");
	XtSetArg( myArgs[0], XmNtextString, &xmstr );
	XtGetValues( w, myArgs, 1 );
	if (XmStringGetLtoR( xmstr, XmSTRING_DEFAULT_CHARSET, &text ) != True)
		printf("Cancel: Error getting label\n");
	else
		if ( text!=NULL )printf("text was =%s\n",text);
	xmstr=XmStringCreate( "" ,  XmSTRING_DEFAULT_CHARSET);
	XtSetArg( myArgs[0], XmNtextString, xmstr );
	XtSetValues( w, myArgs, 1 );

	p=strtok(text," \t\n"); if (p==NULL) return;/*Day*/
	p=strtok(NULL," \t\n");if (p==NULL) return; /*Name*/
	p=strtok(NULL," \t\n");if (p==NULL) return; /*UniqueID*/
	if (( helpfile = FindHelpFile(p))==NULL)
		fprintf(stderr,"No Help File Available for %s\n",p);
	else {
		strcpy(Help_File,helpfile);
		printf("HelpFile=%s\n",Help_File);

		if ( stat( Help_File, &stbuf ) == -1 ) {
			fprintf(stderr,"Help File %s Not found\n", Help_File );
			return;
		}
		helptextstr=XtMalloc( stbuf.st_size +100 );
		if ( ( fd = open( Help_File, O_RDONLY) ) == -1 ) {
	                fprintf(stderr,"Help File %s Not found\n", Help_File );
                        return;
		}
		if ( ( read( fd, helptextstr,  stbuf.st_size ) ) < 0 ) {
                        fprintf(stderr,"Help File %s : Error during Read\n", Help_File );
			close( fd );
                        return;
		}
		close( fd );

		n=0;
		XtSetArg( myArgs[n], XmNx, 0 );	n++;
		XtSetArg( myArgs[n], XmNy, 0 );	n++;
		helpdialog = XmCreateBulletinBoardDialog( lista,	/* parent */
					"helpdialog",
					myArgs, n );
		XtManageChild( helpdialog );

		n=0;
		XtSetArg( myArgs[n], XmNx, 0 );	n++;
		XtSetArg( myArgs[n], XmNy, 0 );	n++;
		XtSetArg( myArgs[n], XmNcolumns, 40 );	n++;
		XtSetArg( myArgs[n], XmNrows, 24 );	n++;
		XtSetArg( myArgs[n], XmNeditable, False );	n++;
		XtSetArg( myArgs[n], XmNeditMode, XmMULTI_LINE_EDIT); n++;
		helptext = XmCreateScrolledText( helpdialog,
					"helptext",
					  myArgs, n );
		XtManageChild( helptext );
		XmTextSetString( helptext, helptextstr );

		done = XtCreateManagedWidget( "done", xmPushButtonWidgetClass, 
						helpdialog, myArgs, n );
		XtAddCallback( done, XmNactivateCallback, HelpDone, NULL );
	}
}

void ListaOKCallback( w , client_data, call_data )	/* We label it Read Problem File */
Widget w;
caddr_t client_data;
XtCallbackList *call_data;
{
char *text, addr[MAXUNIQUEID],service[MAXTESTNAME], dummy[100], Name[100];
XmString xmstr;
Arg myArgs[10];
int i,p;
extern struct ProblemType ProblemArray[];/*In Coreversion of existing problems*/
extern int NumProblems;

	printf("OK-Update Status\n");
	XtSetArg( myArgs[0], XmNtextString, &xmstr );
	XtGetValues( w, myArgs, 1 );
	if (XmStringGetLtoR( xmstr, XmSTRING_DEFAULT_CHARSET, &text ) != True)
		printf("Cancel: Error getting label\n");
	else
		if ( text!=NULL )printf("text was =%s\n",text);
	sscanf(text, "%s %s %s %s", dummy, Name, addr, service );
	printf("%s %s %s\n",Name, addr,service);
	if ( (p=Problem_Exists( addr, service, ProblemArray, NumProblems)) == -1 )
		printf("PROBLEM NOT FOUND- ERR!\n");
	else {	
		printf("ProblemExists: #%d\n",p);
		printf("NewProblemLine=%s\n",text);
		printf("StatusLine=%s\n",&text[STATUSX]);
		if ( strlen(&text[STATUSX]) > MAXSTATUSLINE )
			text[STATUSX+MAXSTATUSLINE-1] = '\0';	/* Avoid BIG STATUS */

         	Problem_Manager( UPDATE_PROBLEM, service, Name, addr,  &text[STATUSX] );
	}
	xmstr=XmStringCreate( "" , XmSTRING_DEFAULT_CHARSET);
	XtSetArg( myArgs[0], XmNtextString, xmstr );
	XtSetValues( w, myArgs, 1 );
	Update();
}

Quit( w , client_data, call_data )
Widget w;
caddr_t client_data;
XtCallbackList *call_data;
{
	exit(1);
}

char *programname;

main(argc, argv)
    int   argc;
    char *argv[];
{
  Widget toplevel, mainwindow, commands;
  Widget quit, selectfilter,programtitle;
  Widget cycletimelabel, collectorstatus, collectorstatuslabel, numproblemslabel;
  Arg myArgs[10];
  XmString *TextEntries;
  Cardinal n;
  int i;

    programname=argv[0];

    if ((pingkydir=getenv("PINGKYDIR"))==NULL) pingkydir=DefaultPingkyDir;

    strcpy(Problem_File,pingkydir); strcat(Problem_File ,"/PROBLEM.FILE");
    strcpy(Checking_File,pingkydir); strcat(Checking_File,"/CHECKING");
    strcpy(CycleTime_File,pingkydir); strcat(CycleTime_File,"/pingky.cycle");
    strcpy(Log_File,pingkydir); strcat(Log_File,"/problemlog");
    strcpy(Host_File,pingkydir); strcat(Host_File,"/hostfile");
    strcpy(Filter_File,pingkydir); strcat(Filter_File,"/pingky.filter");


    SetupFilters();


  /*
   * Initialize the Intrinsics, create one TopLevelShell.
   */
  toplevel = XtInitialize(argv[0], "XDisplay", NULL, 0, 
                          &argc, argv);

  n=0;
  XtSetArg( myArgs[n], XmNwidth, 400); n++;
  XtSetArg( myArgs[n], XmNheight, 100); n++;
  mainwindow = XtCreateManagedWidget( "mainwindow", xmBulletinBoardWidgetClass, toplevel, myArgs, n );

/*
	commands
*/
  programtitle = XtCreateManagedWidget( "progtitle", xmLabelWidgetClass, mainwindow, NULL, 0);
  Myclock = XtCreateManagedWidget( "clock", xmTextWidgetClass, mainwindow,NULL,0 );

  commands = XtCreateManagedWidget( "commands", xmRowColumnWidgetClass, mainwindow, NULL, 0 );
  problemcounts = XtCreateManagedWidget("problemcounts", xmRowColumnWidgetClass, mainwindow, NULL, 0 );
  selectfilter = XtCreateManagedWidget( "selectfilter", xmLabelWidgetClass, commands, NULL, 0);
  XtSetArg( myArgs[0], XmNset, True );

  for( i=0; Filter[i].Name != NULL; i++ ) {
  	Filter[i].Toggle = XtCreateManagedWidget(Filter[i].Name, xmToggleButtonWidgetClass, commands, myArgs, 1 );
  	XtAddCallback( Filter[i].Toggle, XmNvalueChangedCallback, FilterNetCallback, NULL );
  	Filter[i].Count= XtCreateManagedWidget(Filter[i].Name, xmTextWidgetClass, problemcounts, NULL, 0 );
  }
  quit = XtCreateManagedWidget("quit", xmPushButtonWidgetClass, commands, NULL, 0 );
  XtAddCallback( quit, XmNactivateCallback, Quit, NULL );

/*
	collector status 
*/
  collectorstatus = XtCreateManagedWidget( "collectorstatus", 
			xmBulletinBoardWidgetClass, mainwindow, NULL, 0 );
  collectorstatuslabel = XtCreateManagedWidget( "collectorstatuslabel", 
			xmLabelWidgetClass, collectorstatus, NULL, 0 );
  numproblemslabel= XtCreateManagedWidget( "numproblemslabel", 
			xmLabelWidgetClass, collectorstatus, NULL, 0 );
  checkinglabel = XtCreateManagedWidget( "checkinglabel", 
			xmLabelWidgetClass, collectorstatus, NULL, 0 );
  n=0;
  XtSetArg( myArgs[n], XmNeditable, False ); n++;

  numproblems =  XtCreateManagedWidget( "numproblems", xmTextWidgetClass, collectorstatus,myArgs,n );
  cycletimelabel =  XtCreateManagedWidget( "cycletimelabel", xmLabelWidgetClass, collectorstatus,NULL,0 );
  cycletime =  XtCreateManagedWidget( "cycletime", xmTextWidgetClass, collectorstatus,myArgs,1 );
  checking =  XtCreateManagedWidget( "checking", xmTextWidgetClass, collectorstatus,myArgs,1 );
/*
	list of problems
*/
  /*TextEntries = (XmString *) XtMalloc(sizeof(XmString) * NUMTEXTENTRIES);
  for(i=0;i<NUMTEXTENTRIES;i++)
	TextEntries[i] = XmStringCreate( text[i], XmSTRING_DEFAULT_CHARSET);	*/

  n=0;
/*  XtSetArg( myArgs[n], XmNlistItems, TextEntries ); n++;
  XtSetArg( myArgs[n], XmNlistItemCount, NUMTEXTENTRIES ); n++;*/
  XtSetArg( myArgs[n], XmNscrollBarDisplayPolicy, XmCONSTANT); n++;
  XtSetArg( myArgs[n], XmNlistSizePolicy, XmCONSTANT); n++;
/*  XtSetArg( myArgs[n], XmNmustMatch, True ); n++;	/* Text selections MUST match */
  lista = XmCreateSelectionBox( mainwindow, "lista", myArgs, n );
  XtManageChild(lista);
  XtAddCallback( lista, XmNapplyCallback, ListaApplyCallback, NULL );
  XtAddCallback( lista, XmNcancelCallback, ListaCancelCallback, NULL );
  XtAddCallback( lista, XmNhelpCallback, ListaHelpCallback, NULL );
  XtAddCallback( lista, XmNokCallback, ListaOKCallback, NULL );
  
  update_time( Myclock, NULL );

  XtRealizeWidget(toplevel);
  XtMainLoop();
}
