/*
  Copyright 1991 Scott Hess.  Permission to use, copy, modify, and
  distribute this software and its documentation for any purpose
  and without fee is hereby granted, provided that this copyright
  notice appear in all copies.  The copyright notice need not appear
  on binary-only distributions - just in source code.
  
  Scott Hess makes no representations about the suitability of this
  software for any purpose.  It is provided "as is" without express
  or implied warranty.
*/

/* Generated by Interface Builder */

/**
*** As its name implies, this object is the application delegate.  It
*** handles setting up the program and cleaning up when the
*** program terminates.
**/

//#import <mach.h>
#import <mach/mach.h>		/* for 3.0 compatibility -- drue */
#import <stdlib.h>
//#import <defaults.h>
#import <defaults/defaults.h>	/* for 3.0 compatibility -- drue */
#import <appkit/nextstd.h>
#import <appkit/Application.h>
#import <appkit/Button.h>
#import <appkit/NXImage.h>
#import "AppDelegate.h"
#import "Monitor.h"

#import "wraps.h"

#define MINPOLLINTERVAL 0.1
#define MINFLIPINTERVAL 0.1

float pollInterval = 1.0;

@implementation AppDelegate

/*****
****** color to string, string to color functions from Ali Ozer
****** 
*****/
// ali ozer code follows...
void convertColorToString (NXColor color, char *str)
{
    static const char hexDigits[16] = "0123456789ABCDEF";
    NXStream *colorStream = NXOpenMemory(NULL, 0, NX_READWRITE);
    NXTypedStream *ts = colorStream ?
		    NXOpenTypedStream(colorStream, NX_WRITEONLY) : NULL;
 
    if (ts) {
	int i, pos;
	NXWriteColor(ts,color);
	NXCloseTypedStream(ts);
	pos = NXTell(colorStream);
    	NXSeek(colorStream, 0, NX_FROMSTART);
	i = 0;
	while (i++ < pos) {
	    unsigned char ch = NXGetc(colorStream);
	    *str++ = hexDigits[(ch>>4) & 0xF];
	    *str++ = hexDigits[ch & 0xF];
        }
    }
    *str = 0;
    if (colorStream) NXCloseMemory (colorStream, NX_FREEBUFFER);
}

#define BAD 255
#define HEX(c) (((c)>='A' && (c)<='F') ? ((c)-'A'+10): (((c)>='0'&&(c)<='9') ? ((c)-'0') : BAD))

BOOL convertStringToColor (const char *str, NXColor *color)
{
    unsigned char binaryBuffer[COLORSTRINGLENGTH];
    NXStream *stream;
    NXTypedStream *ts;
    int len = 0;
    BOOL success = NO;
    
    if(!str)
	return NO;
 
    while (*str) {
	unsigned char first = HEX(str[0]), second = HEX(str[1]);
	if (first == BAD || second == BAD) return NO;	
	binaryBuffer[len] = (first << 4) + second;
	str += 2;
	len++;
    }
 
    if (len &&
	(stream = NXOpenMemory((const char *)binaryBuffer, len, NX_READONLY)) 
	    &&  (ts = NXOpenTypedStream(stream, NX_READONLY))) {
	NX_DURING
	    *color = NXReadColor(ts);
	    success = YES;
	NX_HANDLER
	NX_ENDHANDLER	
    }
    if (ts) NXCloseTypedStream(ts);
    if (stream) NXCloseMemory(stream, NX_SAVEBUFFER);

    return success;
}


- appWillInit:sender
{
	struct task_basic_info 	tbi;
	unsigned int 		ic = TASK_BASIC_INFO_COUNT;

    if( task_info(task_self(),
				  TASK_BASIC_INFO,
				  (task_info_t)&tbi,&ic) != KERN_SUCCESS )
        return nil;
    task_priority(task_self(),tbi.base_priority-4,TRUE);

    return self;
}

- appDidInit:sender
{
	Window	*iconWindow;
	id 	iconView;
	NXImage *recessed;
	NXRect	monitorRect;
	NXDefaultsVector defs =
    {
		{"PollInterval",		"1.0"},
		{"FlipInterval",		"0.0"},
		{"DisplayInfo", 		"CDMN"},
		{"InfoType",			"0"},
		{"CPUSystemColor",
		 "040B747970656473747265616D8103A2840163C08403737373FE81AAA900"},
		{"CPUUserColor",
		 "040B747970656473747265616D8103A2840163C08403737373FE0000"},
		{"CPUNiceColor",
		 "040B747970656473747265616D8103A2840163C0840373737381111100FE"},
		{"DiskColor", 			
		 "040B747970656473747265616D8103A2840163C084037373730081F616FE"},
		{"DiskPageinColor",		
		 "040B747970656473747265616D8103A2840163C084037373736CFE8128EB"},
		{"DiskPageoutColor",
		 "040B747970656473747265616D8103A2840163C08403737373817CB100FE"},
		{"MemInactiveColor",	
		 "040B747970656473747265616D8103A2840163C0840373737381AAA981333300"},
		{"MemActiveColor",		
		 "040B747970656473747265616D8103A2840163C08403737373FE0081BBBA"},
		{"MemWiredColor",		
		 "040B747970656473747265616D8103A2840163C08403737373FE81AAA900"},
		{"NetInColor",			
		 "040B747970656473747265616D8103A2840163C08403737373FE0081E73B"},
		{"NetOutColor",			
		 "040B747970656473747265616D8103A2840163C08403737373FE81FD0200"},
		{"NetCollisionColor",	
		 "040B747970656473747265616D8103A2840163C08403737373FE0000"},
		{"BackgroundColor",		
		 "040B747970656473747265616D8103A2840163C0840373737381111100811111"},
		{NULL,NULL}
    };	

	/***
	**** Instantiate the NXImages needed to do the drawing
	***/
    recessed = [NXImage findImageNamed:"recessed.tiff"];

	/***
	**** Get the application icon's view and put our own views there.
	***/
    iconWindow = [NXApp appIcon];
    iconView = [iconWindow contentView];
    [iconView addSubview:monitor];
    [iconView lockFocus];
    [monitor getFrame:&monitorRect];
    [recessed composite:NX_COPY toPoint:&(monitorRect.origin)];
    [iconView unlockFocus];

    [iconWindow flushWindow];

    [recessed free];

	/***
	**** Register the defaults with the system.
	***/
    NXRegisterDefaults([NXApp appName],defs);

    /***
	**** Read Defaults
	**** 
	***/
	[self readColorDefaults];
    if ( NXGetDefaultValue([NXApp appName],"PollInterval") ) {
		pollInterval = atof(NXGetDefaultValue([NXApp appName],
											  "PollInterval"));
		pollInterval = MAX(pollInterval,MINPOLLINTERVAL);
		[pollSlider setFloatValue:pollInterval];
		[pollText setFloatValue:pollInterval];
	}	
	
    if ( NXGetDefaultValue([NXApp appName],"FlipInterval") ) {
		flipInterval = atof(NXGetDefaultValue([NXApp appName],"FlipInterval"));
		if ( flipInterval > MINFLIPINTERVAL ) {
			[flipSlider setFloatValue:flipInterval];
			[flipText setFloatValue:flipInterval];
		} else {
			[flipSlider setFloatValue:0.0];
			[flipText setStringValue:"OFF"];
		}
	}
	
    displayCpu = displayDisk = displayMemory = displayNetwork = TRUE;
    if ( NXGetDefaultValue([NXApp appName],"DisplayInfo") ) {
		strcpy( displayInfo, NXGetDefaultValue([NXApp appName],"DisplayInfo"));
		//  a lowercase value means the matching option is turned off
		if ( strchr(displayInfo, 'c') ) displayCpu = FALSE;
		if ( strchr(displayInfo, 'd') ) displayDisk = FALSE;
		if ( strchr(displayInfo, 'm') ) displayMemory = FALSE;
		if ( strchr(displayInfo, 'n') ) displayNetwork = FALSE;
	}
    if ( (displayCpu + displayDisk + displayMemory + displayNetwork) < 1)
		displayCpu = TRUE;

    if ( displayCpu )
		[cpuSwitch setState:1];

    if ( displayDisk )
		[diskSwitch setState:1];

    if (! [monitor diskstatAvailable] )
		[diskSwitch setTitle:"Disk (*)"];

    if ( displayMemory )
		[memorySwitch setState:1];

    if ( displayNetwork )
		[networkSwitch setState:1];
	
    if ( NXGetDefaultValue([NXApp appName],"InfoType") ) {
		tag = atoi(NXGetDefaultValue([NXApp appName],"InfoType"));
		switch ( tag )
			{
			case CPU_tag:
			case MEMORY_tag:
			case DISK_tag:
			case NETWORK_tag:
				/* these are all OK */
				break;
			default:
				tag = CPU_tag;
			}
	}
	
	
    [monitor flip:self];

    /***
    **** Register the timed entry with the window server.
    ***/
    stepEntry = DPSAddTimedEntry(pollInterval,
								 (void *)_step,
								 monitor,
								 NX_MODALRESPTHRESHOLD);

    if ( flipInterval > MINFLIPINTERVAL )
        flipEntry = DPSAddTimedEntry(flipInterval*60,
									 (void *)_flip,
									 self,
									 NX_MODALRESPTHRESHOLD);
    return self;	
}

- appWillTerminate:sender
{
    if ( stepEntry )
        {
        DPSRemoveTimedEntry(stepEntry);
        stepEntry = (DPSTimedEntry)0;
        }
    if ( flipEntry )
        {
        DPSRemoveTimedEntry(flipEntry);
        flipEntry = (DPSTimedEntry)0;
        }
    return self;
}

- info:sender
{
    if ( !infoPanel )
        [NXApp loadNibSection:"InfoPanel.nib" owner:self];

    [infoPanel makeKeyAndOrderFront:self];

    return self;
}

- flipMonitor
{
    int newTag, cnt;
    
    newTag = -1;
    for (newTag = -1, cnt= 0; (newTag < 0) && (cnt<=DISPTAG_MAX) ; cnt++) {
	tag++;
	if ( tag > DISPTAG_MAX ) tag = 0;
	switch (tag) {
	case CPU_tag:
	    if (displayCpu) newTag = tag;
	    break;
	case DISK_tag:
	    /* note that we'll still do the disk display even when
	     * diskstatAvailable is off.  The disk display includes
	     * vm-paging statistics, which is always available.
	     */
	    if (displayDisk) newTag = tag;
	    break;
	case MEMORY_tag:
	    if (displayMemory) newTag = tag;
	    break;
	case NETWORK_tag:
	    if (displayNetwork && [monitor netstatAvailable]) newTag = tag;
	    break;
	default:
	    /* Hmm.  This shouldn't happen, better exit... */
	    newTag = CPU_tag;
	}
    }
    
    [monitor flip:self];
    return self;
}

- setPollInterval:sender
{
	char intervalString[6];

    pollInterval = MAX([sender floatValue],MINPOLLINTERVAL);
    sprintf(intervalString,"%4.1f",pollInterval);
    NXWriteDefault([NXApp appName],"PollInterval",intervalString);
    if ( stepEntry ) {
        DPSRemoveTimedEntry(stepEntry);
        stepEntry = (DPSTimedEntry)0;
	}
    stepEntry = DPSAddTimedEntry(pollInterval,
								 (void *)_step,
								 monitor,
								 NX_MODALRESPTHRESHOLD);
    [pollText setStringValue:intervalString];
    return self;
}

- setFlipInterval:sender
{
	char intervalString[6];

    flipInterval = [sender floatValue];
    if ( flipEntry ) {
        DPSRemoveTimedEntry(flipEntry);
        flipEntry = (DPSTimedEntry)0;
	}
    if ( flipInterval > MINFLIPINTERVAL )     {
        sprintf(intervalString,"%4.1f",flipInterval);
        flipEntry = DPSAddTimedEntry(flipInterval*60,
									 (void *)_flip,
									 self,
									 NX_MODALRESPTHRESHOLD);
	}
    else
        strcpy(intervalString,"OFF");
    [flipText setStringValue:intervalString];
    NXWriteDefault([NXApp appName],"FlipInterval",intervalString);
    return self;
}

- setDisplayCpu:sender
{
    displayCpu = [cpuSwitch state];
    [self saveDisplayInfo];
    if ( displayCpu ) { tag = CPU_tag ; [monitor flip:self]; }
    else if ( tag == CPU_tag ) { [self flipMonitor]; }
    return self;
}

- setDisplayDisk:sender
{
    displayDisk = [diskSwitch state];
    [self saveDisplayInfo];
    if ( displayDisk ) { tag = DISK_tag ; [monitor flip:self]; }
    else if ( tag == DISK_tag ) { [self flipMonitor]; }
    return self;
}

- setDisplayMemory:sender
{
    displayMemory = [memorySwitch state];
    [self saveDisplayInfo];
    if ( displayMemory ) { tag = MEMORY_tag ; [monitor flip:self]; }
    else if ( tag == MEMORY_tag ) { [self flipMonitor]; }
    return self;
}

- setDisplayNetwork:sender
{
    displayNetwork = [networkSwitch state];
    [self saveDisplayInfo];
    if ( displayNetwork ) { tag = NETWORK_tag ; [monitor flip:self]; }
    else if ( tag == NETWORK_tag ) { [self flipMonitor]; }
    return self;
}

- saveDisplayInfo
{
    //    at least one option must be on...
    if ( (displayCpu + displayDisk + displayMemory + displayNetwork) < 1) 
	{
	displayCpu = TRUE;		// Note that this always works, while
	[cpuSwitch setState:1];		// This only works if called from setDisplayCpu?!?
	}

    displayInfo[0] = '\0';
    if ( displayCpu )	strcat(displayInfo, "C");
    else		strcat(displayInfo, "c");
    if ( displayDisk )	strcat(displayInfo, "D");
    else		strcat(displayInfo, "d");
    if ( displayMemory ) strcat(displayInfo, "M");
    else		strcat(displayInfo, "m");
    if ( displayNetwork ) strcat(displayInfo, "N");
    else		strcat(displayInfo, "n");

    NXWriteDefault([NXApp appName], "DisplayInfo", displayInfo);
    return self;
}

- selectedCell
{
    return self;
}

- (int)tag
{
    return tag;
}

- changeColor:sender
{
   /*** ===================================================================
   **** [bbum] OK, so I was lazy... basically, this method writes *all* the
   **** default values via -writeColorDefaults.  -writeColorDefaults last
   **** action is to *read* all the color defaults (via -readColorDefaults)
   **** 
   **** Grossly ineffecient?  YES!
   **** 
   **** Avoids making a zillion different IB connections?  YES!
   **** ===================================================================
   ***/
	return [self writeColorDefaults];
}

- readColorDefaults
{
	const char *value;
	NXColor theColor;
	
    if ((value = NXGetDefaultValue([NXApp appName], "CPUSystemColor"))
		&& convertStringToColor(value, &theColor)) {
		setCPUSystemColor(NXRedComponent(theColor),
						  NXGreenComponent(theColor),
						  NXBlueComponent(theColor));
		[cpuSystemColor setColor:theColor];
	} else {
		setCPUSystemColor(NXRedComponent(NX_COLORWHITE),
						  NXGreenComponent(NX_COLORWHITE),
						  NXBlueComponent(NX_COLORWHITE));
		[cpuSystemColor setColor:NX_COLORWHITE];
	}

    if ((value = NXGetDefaultValue([NXApp appName], "CPUUserColor"))
		&& convertStringToColor(value, &theColor)) {
		setCPUUserColor(NXRedComponent(theColor),
						  NXGreenComponent(theColor),
						  NXBlueComponent(theColor));
		[cpuUserColor setColor:theColor];
	} else {
		setCPUUserColor(NXRedComponent(NX_COLORWHITE),
						  NXGreenComponent(NX_COLORWHITE),
						  NXBlueComponent(NX_COLORWHITE));
		[cpuUserColor setColor:NX_COLORWHITE];
	}

    if ((value = NXGetDefaultValue([NXApp appName], "CPUNiceColor"))
		&& convertStringToColor(value, &theColor)) {
		setCPUNiceColor(NXRedComponent(theColor),
						  NXGreenComponent(theColor),
						  NXBlueComponent(theColor));
		[cpuNiceColor setColor:theColor];
	} else {
		setCPUNiceColor(NXRedComponent(NX_COLORWHITE),
						  NXGreenComponent(NX_COLORWHITE),
						  NXBlueComponent(NX_COLORWHITE));
		[cpuNiceColor setColor:NX_COLORWHITE];
	}

    if ((value = NXGetDefaultValue([NXApp appName], "DiskColor"))
		&& convertStringToColor(value, &theColor)) {
		setDiskColor(NXRedComponent(theColor),
						  NXGreenComponent(theColor),
						  NXBlueComponent(theColor));
		[diskColor setColor:theColor];
	} else {
		setDiskColor(NXRedComponent(NX_COLORWHITE),
						  NXGreenComponent(NX_COLORWHITE),
						  NXBlueComponent(NX_COLORWHITE));
		[diskColor setColor:NX_COLORWHITE];
	}

    if ((value = NXGetDefaultValue([NXApp appName], "DiskPageinColor"))
		&& convertStringToColor(value, &theColor)) {
		setDiskPageinColor(NXRedComponent(theColor),
						  NXGreenComponent(theColor),
						  NXBlueComponent(theColor));
		[diskPageinColor setColor:theColor];
	} else {
		setDiskPageinColor(NXRedComponent(NX_COLORWHITE),
						  NXGreenComponent(NX_COLORWHITE),
						  NXBlueComponent(NX_COLORWHITE));
		[diskPageinColor setColor:NX_COLORWHITE];
	}

    if ((value = NXGetDefaultValue([NXApp appName], "DiskPageoutColor"))
		&& convertStringToColor(value, &theColor)) {
		setDiskPageoutColor(NXRedComponent(theColor),
						  NXGreenComponent(theColor),
						  NXBlueComponent(theColor));
		[diskPageoutColor setColor:theColor];
	} else {
		setDiskPageoutColor(NXRedComponent(NX_COLORWHITE),
						  NXGreenComponent(NX_COLORWHITE),
						  NXBlueComponent(NX_COLORWHITE));
		[diskPageoutColor setColor:NX_COLORWHITE];
	}

	if ((value = NXGetDefaultValue([NXApp appName], "MemInactiveColor"))
		&& convertStringToColor(value, &theColor)) {
		setMemInactiveColor(NXRedComponent(theColor),
						  NXGreenComponent(theColor),
						  NXBlueComponent(theColor));
		[memInactiveColor setColor:theColor];
	} else {
		setMemInactiveColor(NXRedComponent(NX_COLORWHITE),
						  NXGreenComponent(NX_COLORWHITE),
						  NXBlueComponent(NX_COLORWHITE));
		[memInactiveColor setColor:NX_COLORWHITE];
	}

	if ((value = NXGetDefaultValue([NXApp appName], "MemActiveColor"))
		&& convertStringToColor(value, &theColor)) {
		setMemActiveColor(NXRedComponent(theColor),
						  NXGreenComponent(theColor),
						  NXBlueComponent(theColor));
		[memActiveColor setColor:theColor];
	} else {
		setMemActiveColor(NXRedComponent(NX_COLORWHITE),
						  NXGreenComponent(NX_COLORWHITE),
						  NXBlueComponent(NX_COLORWHITE));
		[memActiveColor setColor:NX_COLORWHITE];
	}

	if ((value = NXGetDefaultValue([NXApp appName], "MemWiredColor"))
		&& convertStringToColor(value, &theColor)) {
		setMemWiredColor(NXRedComponent(theColor),
						  NXGreenComponent(theColor),
						  NXBlueComponent(theColor));
		[memWiredColor setColor:theColor];
	} else {
		setMemWiredColor(NXRedComponent(NX_COLORWHITE),
						  NXGreenComponent(NX_COLORWHITE),
						  NXBlueComponent(NX_COLORWHITE));
		[memWiredColor setColor:NX_COLORWHITE];
	}

	if ((value = NXGetDefaultValue([NXApp appName], "NetInColor"))
		&& convertStringToColor(value, &theColor)) {
		setNetInColor(NXRedComponent(theColor),
						  NXGreenComponent(theColor),
						  NXBlueComponent(theColor));
		[netInColor setColor:theColor];
	} else {
		setNetInColor(NXRedComponent(NX_COLORWHITE),
						  NXGreenComponent(NX_COLORWHITE),
						  NXBlueComponent(NX_COLORWHITE));
		[netInColor setColor:NX_COLORWHITE];
	}

	if ((value = NXGetDefaultValue([NXApp appName], "NetOutColor"))
		&& convertStringToColor(value, &theColor)) {
		setNetOutColor(NXRedComponent(theColor),
						  NXGreenComponent(theColor),
						  NXBlueComponent(theColor));
		[netOutColor setColor:theColor];
	} else {
		setNetOutColor(NXRedComponent(NX_COLORWHITE),
						  NXGreenComponent(NX_COLORWHITE),
						  NXBlueComponent(NX_COLORWHITE));
		[netOutColor setColor:NX_COLORWHITE];
	}

	if ((value = NXGetDefaultValue([NXApp appName], "NetCollisionColor"))
		&& convertStringToColor(value, &theColor)) {
		setNetCollisionColor(NXRedComponent(theColor),
						  NXGreenComponent(theColor),
						  NXBlueComponent(theColor));
		[netCollisionColor setColor:theColor];
	} else {
		setNetCollisionColor(NXRedComponent(NX_COLORWHITE),
						  NXGreenComponent(NX_COLORWHITE),
						  NXBlueComponent(NX_COLORWHITE));
		[netCollisionColor setColor:NX_COLORWHITE];
	}

	if ((value = NXGetDefaultValue([NXApp appName], "BackgroundColor"))
		&& convertStringToColor(value, &theColor)) {
		setBackgroundColor(NXRedComponent(theColor),
						  NXGreenComponent(theColor),
						  NXBlueComponent(theColor));
		[backgroundColor setColor:theColor];
	} else {
		setBackgroundColor(NXRedComponent(NX_COLORWHITE),
						  NXGreenComponent(NX_COLORWHITE),
						  NXBlueComponent(NX_COLORWHITE));
		[backgroundColor setColor:NX_COLORWHITE];
	}

	return self;
}

- writeColorDefaults
{
	char buf[COLORSTRINGLENGTH];
	NXColor theColor;

	// CPU colors
	theColor = [cpuSystemColor color];
	convertColorToString(theColor, buf);
    NXWriteDefault([NXApp appName], "CPUSystemColor", buf);	
	theColor = [cpuUserColor color];
	convertColorToString(theColor, buf);
    NXWriteDefault([NXApp appName], "CPUUserColor", buf);	
	theColor = [cpuNiceColor color];
	convertColorToString(theColor, buf);
    NXWriteDefault([NXApp appName], "CPUNiceColor", buf);	

	// Disk Colors
	theColor = [diskColor color];
	convertColorToString(theColor, buf);
    NXWriteDefault([NXApp appName], "DiskColor", buf);
	theColor = [diskPageinColor color];
	convertColorToString(theColor, buf);
    NXWriteDefault([NXApp appName], "DiskPageinColor", buf);	
	theColor = [diskPageoutColor color];
	convertColorToString(theColor, buf);
    NXWriteDefault([NXApp appName], "DiskPageoutColor", buf);	

	// Memory Colors
	theColor = [memActiveColor color];
	convertColorToString(theColor, buf);
    NXWriteDefault([NXApp appName], "MemActiveColor", buf);	
	theColor = [memInactiveColor color];
	convertColorToString(theColor, buf);
    NXWriteDefault([NXApp appName], "MemInactiveColor", buf);	
	theColor = [memWiredColor color];
	convertColorToString(theColor, buf);
    NXWriteDefault([NXApp appName], "MemWiredColor", buf);	

	// Network Colors
	theColor = [netInColor color];
	convertColorToString(theColor, buf);
    NXWriteDefault([NXApp appName], "NetInColor", buf);	
	theColor = [netOutColor color];
	convertColorToString(theColor, buf);
    NXWriteDefault([NXApp appName], "NetOutColor", buf);	
	theColor = [netCollisionColor color];
	convertColorToString(theColor, buf);
    NXWriteDefault([NXApp appName], "NetCollisionColor", buf);	

	// background color
	theColor = [backgroundColor color];
	convertColorToString(theColor, buf);
    NXWriteDefault([NXApp appName], "BackgroundColor", buf);	

	return [self readColorDefaults];
}

@end

/******************************************************************************************************************************
 *    This function is called by a timed entry.                                                                               *
 *    It gets the load data from the system.                                                                                  *
 ******************************************************************************************************************************/
void _step(DPSTimedEntry teNumber,double now,id monitor)
{
    [monitor step];
    return;
}

void _flip(DPSTimedEntry teNumber,double now,id self)
{
    [self flipMonitor];
    return;
}




