//************************************************************************
//
//	Preferences.m.  
//
//		Controller for the preferences panel.
//
//			by	Felipe A. Rodriguez		
//
//	This code is supplied "as is" the author makes no warranty as to its 
//	suitability for any purpose.  This code is free and may be distributed 
//	in accordance with the terms of the:
//		
//			GNU GENERAL PUBLIC LICENSE
//			Version 2, June 1991
//			copyright (C) 1989, 1991 Free Software Foundation, Inc.
// 			675 Mass Ave, Cambridge, MA 02139, USA
//
//************************************************************************

#import "Preferences.h"
#import "SwapView.h"
#import "OptionsEditor.h"
#import "ToolBar.h"
#import "HLDelegate.h"

			// used in creating a FIFO
	typedef unsigned short mode_t;
int mkfifo (const char *path, mode_t mode);
#define	FMOD	(S_IREAD | S_IWRITE)					// read, write by owner



@implementation Preferences

//************************************************************************
//
//		sent to us after nib objects are unarchived and init'd 
//
//************************************************************************
 
- awakeFromNib
{
int i = 0;

	[swapView initPopUp];
	[swapView inspectName:"Switches"];
						// remem loc/size
	[[swapView window] setFrameUsingName:[[swapView window] title]];	
	[[swapView window] setFrameAutosaveName:[[swapView window] title]]; 
														// default switches
	do  {								// if set in ddb turn check switch on
		if(strcmp(NXGetDefaultValue([NXApp appName], sList[i]), "YES") == 0)		
			[[swMatrix findCellWithTag:i] setIntValue:1];
		}
	while(sList[++i]);
	for(i = 0; rsList[i] != NULL; i++) 					// redial switches
		{								// if set in ddb turn check switch on
		if(strcmp(NXGetDefaultValue([NXApp appName], rsList[i]), "YES") == 0)		
			[[redialSwMatrix findCellWithTag:i] setIntValue:1];
		}
	[preTimeoutSw setIntValue:1];
	for(i = 0; cList[i]; i++)				// display default trigger str's
		[defaultsForm setStringValue:NXGetDefaultValue([NXApp appName],
															cList[i]) at:i];	
	for(i = 0; rfList[i]; i++)				// display redial trigger str's
		[redialForm setStringValue:NXGetDefaultValue([NXApp appName],
															rfList[i]) at:i];	

	[self setPPPForm:radioButtons];				// set ppp form strings
	[self timeout:self];				// set timeout circ slide/text field
	[self timeoutThreshold:self];		// set timeout circ slide/text field
	[[[[[[[[pHLBrowser setTitled:NO] 	// create and configure nxbrowser
					setHorizontalScrollButtonsEnabled:NO]
					setDelegate:[[NXApp delegate] hotListDelegate]]
					setTarget:[[NXApp delegate] hotListDelegate]]
					setAction:@selector(pBrowserHit:)]
					setDoubleAction:@selector(pBrowserDoubleClick:)]
					setMinColumnWidth:200]
					setMaxVisibleColumns:1];
	[self resetPHLBrowser];
    [hlPathTextField setStringValue:
								NXGetDefaultValue([NXApp appName], HLLIST)];

    return self;
}
//************************************************************************
//
//		show pppEditor 
//
//************************************************************************

- show_pppEditor:sender 
{
	[self setPPPForm:radioButtons];				// set ppp form strings

    return self;
}
//***************************** Editor subview ***************************
//************************************************************************
//
//		 Edit ppp file button was pressed, open radio sel'd file in edit
//
//************************************************************************
 
- pppFileEdit:sender 
{						// if readable
	if([[NXApp delegate] 
					readable:[self pathOf:(int)[radioButtons selectedTag]]])
						// call edit to open radioButtons selected file
		[[Application workspace] openFile:[self pathOf:
					(int)[radioButtons selectedTag]] withApplication:"Edit"];
	
    return self;
}
//************************************************************************
//
//		 Edit example ppp file button was pressed, in Editor subview.
//
//************************************************************************

- pppExampleEdit:sender 
{						// appWrapper is mainBundle, return path to resources
						// bundled within				 
    if(![[NXBundle mainBundle]getPath:Path forResource:"Examples" ofType:NULL])
		[[NXApp delegate] showAlert:"Error getting mainbundle path"];
	strcat(Path, exlist[(int)[radioButtons selectedTag]]);				
					// call edit to open file
	[[Application workspace] openFile:Path withApplication:"Edit"];
	
    return self;
}
//************************************************************************
//
//		send formcell a path based on the tag of the selected radio button.
//
//************************************************************************

- setPPPForm:sender
{
	[pppForm setStringValue:[self pathOf:(int)[sender selectedTag]] at:0];	
	if((2 < (int)[sender selectedTag]))
		[pppForm setEnabled:NO];  	
	else 
		[pppForm setEnabled:YES];

    return self;
}
//************************************************************************
//
//		 return the path of the item selected in flist[]
//
//************************************************************************

- (char *)pathOf:(int)i 
{
	strcpy(Path, NXGetDefaultValue([NXApp appName], flist[i]));
	
    return Path;
}
//***************************** defaults subview *************************
//************************************************************************
//
//		user has changed the path of one of the ppp files.
//
//************************************************************************

- pppFilesPathChanged:sender
{									// write an entry to defaults database
	if(!NXWriteDefault([NXApp appName], flist[(int)[radioButtons selectedTag]], 
								[sender stringValueAt:[sender selectedIndex]]))
		[[NXApp delegate] showAlert:"ddbWriteError"];

    return self;
}
//************************************************************************
//
//		user has changed a control string, store change in ddb
//
//************************************************************************
 
- defaultsForm:sender
{
int i = (int)[sender selectedIndex];

				// write an entry to defaults database
	if(!NXWriteDefault([NXApp appName], cList[i], [sender stringValueAt:i]))
		[[NXApp delegate] showAlert:"ddbWriteError"];

    return self;
}
//***************************** Link subview *****************************
//************************************************************************
//
//		hotList path changed
//
//************************************************************************
 
- setHotListPath:sender
{				// write an entry to defaults database
	if(!NXWriteDefault([NXApp appName], HLLIST, [sender stringValue]))
		[[NXApp delegate] showAlert:"ddbWriteError"];
	[[[NXApp delegate] hotListDelegate] initHotListPath];
	[self resetPHLBrowser];

    return self; 
}
//************************************************************************
//
//		select a hotList path
//
//************************************************************************
 
- selectHotListPath:sender
{				
id	theOpenPanel;   
const char *filter[2] = {"Gate", NULL};		// filter for Gate doc path's

	theOpenPanel = [OpenPanel new];
	[theOpenPanel setTitle:"HotList Path"];
	if(NX_OKTAG == [theOpenPanel runModalForDirectory:
						NXGetDefaultValue([NXApp appName], "path") file:NULL 	
							types:filter])
		{
		if(!NXWriteDefault([NXApp appName], HLLIST, [theOpenPanel directory]))
			[[NXApp delegate] showAlert:"ddbWriteError"];
		[hlPathTextField setStringValue:[theOpenPanel directory]];
		[[[NXApp delegate] hotListDelegate] initHotListPath];
		[self resetPHLBrowser];
		}

    return self;
}
//************************************************************************
//
//		reset preferences hot list browswer
//
//************************************************************************
 
- resetPHLBrowser
{						// NXBrowser s/load cols from its delegate
	[pHLBrowser loadColumnZero];
	mat = [pHLBrowser matrixInColumn:0];
	[[[NXApp delegate] hotListDelegate] setPreferencesBMat:mat];		
	[mat selectCellAt:[[[NXApp delegate]hotListDelegate]hLSelectedCell]:0];

    return self;
}
//************************************************************************
//
//		user has changed a redial trigger string, store change in ddb
//
//************************************************************************
 
- redialForm:sender
{
int i = (int)[sender selectedIndex];

				// write an entry to defaults database
	if(!NXWriteDefault([NXApp appName], rfList[i], [sender stringValueAt:i]))
		[[NXApp delegate] showAlert:"ddbWriteError"];

    return self;
}
//************************************************************************
//
//		Target method of defaults db entries for our preferences
//		check switches based on the tag assigned in IB to each switch.
//
//************************************************************************

- switch:sender
{
int tag = [sender selectedTag];
										// toggles entries YES/NO
	if(strcmp(NXGetDefaultValue([NXApp appName], sList[tag]),"NO") == 0)
		{														// sw set ON
 		if(!NXWriteDefault([NXApp appName], sList[tag], "YES"))
			[[NXApp delegate] showAlert:"ddbWriteError"];
		else 
			{			// use fifo was enabled,
			if(tag == 0) 
				[self makeFIFO];
			if(tag == 4)						// Dial on Demand was enabled
				[[NXApp delegate] DialOnDemand];		// prepare for dial on 
			if(tag == 6)						// app icon time enabled
				[[NXApp delegate] setAppIconTimer:YES];		
			}
		}
	else 														// sw set OFF
		{
		if(tag == 0) 
			[self makeFile];	// if previously using FIFO create a log file
		if(tag == 4)			// Dial on Demand was disabled, revert to
			[[NXApp delegate] namedReset:"/usr/etc/named"];		// system named
		if(tag == 6)			// app icon time disabled
			[[NXApp delegate] setAppIconTimer:NO];		
		if(!NXWriteDefault([NXApp appName], sList[tag], "NO"))
			[[NXApp delegate] showAlert:"ddbWriteError"];
		}

    return self;
}
//*****************************************************************************
//
// 		target of redial panel's switch matrix 
//
//*****************************************************************************

- redialSwitch:sender;
{
	if((BOOL)[sender intValue])	
		{
		if(!NXWriteDefault([NXApp appName],rsList[[sender selectedTag]],"YES"))
			[[NXApp delegate] showAlert:"ddbWriteError"];
		}
	else
		{
		if(!NXWriteDefault([NXApp appName], rsList[[sender selectedTag]],"NO"))
			[[NXApp delegate] showAlert:"ddbWriteError"];
		}
	if([sender selectedTag] == 4)				// Redial Backoff state change
		[[NXApp delegate] resetDelay:sender];		 

    return self;
}
//*****************************************************************************
//
// 		make the FIFO 
//
//*****************************************************************************

- makeFIFO
{								// find FIFO path per /etc/syslog.conf
	[[NXApp delegate] fifo];	
								// remove FIFO and then remake it
	if((strlen(NXGetDefaultValue([NXApp appName],"locFIFO")) + 20)< MAXPATHLEN)
		{
		strcpy(Path, [[[NXApp delegate] stringTable]
											 valueForStringKey:"createFIFO"]);				
		strcat(Path, NXGetDefaultValue([NXApp appName],"locFIFO"));
		strcat(Path, " ?");
		if(NXRunAlertPanel(0, Path,
                	[[[NXApp delegate] stringTable] valueForStringKey:"Yes"],
                	[[[NXApp delegate] stringTable] valueForStringKey:"No"],
                	NULL) == NX_OKTAG)
			{
			unlink(NXGetDefaultValue([NXApp appName],"locFIFO"));		
			mkfifo(NXGetDefaultValue([NXApp appName],"locFIFO"),(mode_t) FMOD);
			[[NXApp delegate] syslogdRun];			// restart syslogd
			}
		}
	else
		[[NXApp delegate] showAlert:"Error FIFO path is too long"];

    return self;
}
//*****************************************************************************
//
// 		make the Log File
//
//*****************************************************************************

- makeFile
{
int fd;
								// find path per /etc/syslog.conf
	[[NXApp delegate] fifo];	
								// remove FIFO and then remake it
	if((strlen(NXGetDefaultValue([NXApp appName],"locFIFO")) + 27)< MAXPATHLEN)
		{
		strcpy(Path, [[[NXApp delegate] stringTable]
											 valueForStringKey:"createFile"]);				
		strcat(Path, NXGetDefaultValue([NXApp appName],"locFIFO"));
		strcat(Path, " ?");
		if(NXRunAlertPanel(0, Path,
                	[[[NXApp delegate] stringTable] valueForStringKey:"Yes"],
                	[[[NXApp delegate] stringTable] valueForStringKey:"No"],
                	NULL) == NX_OKTAG)
			{
			unlink(NXGetDefaultValue([NXApp appName],"locFIFO"));
			if((fd = open(NXGetDefaultValue([NXApp appName],"locFIFO"), 
								O_RDWR|O_CREAT|O_TRUNC,(mode_t) 644)) != -1)
				close(fd);		
			[[NXApp delegate] syslogdRun];			// restart syslogd
			}
		}
	else
		[[NXApp delegate] showAlert:"log file path is too long"];

    return self;
}
//*****************************************************************************
//
// 		target of timeout circular slider 
//
//*****************************************************************************

- timeout:sender
{
int i;

	if(sender == self) 							// if initial display of pref
		i = atoi(NXGetDefaultValue([NXApp appName], "iTimeout"));
	else										// else user changed control
		{
		i = [sender intValue];
		[[NXApp delegate] setTimeout:i];		// set timeout in Coordinator
		}
	if(i == 0)
		[timeoutField setStringValue:"Off"];
	else
		[timeoutField setIntValue:i];
	[timeoutCircSlider setIntValue:i];

    return self;
}
//*****************************************************************************
//
// 		target of pre timeout switch 
//
//*****************************************************************************

- setPreTimeout:sender
{
	if((BOOL)[sender intValue])
		{
 		if(!NXWriteDefault([NXApp appName], "preTimeout", "YES"))
			[[NXApp delegate] showAlert:"ddbWriteError"];
		}
	else 
		{
		if(!NXWriteDefault([NXApp appName], "preTimeout", "NO"))
			[[NXApp delegate] showAlert:"ddbWriteError"];
		}

    return self;
}
//*****************************************************************************
//
// 		target of timeout threshold circular slider 
//
//*****************************************************************************

- timeoutThreshold:sender
{
int i;

	if(sender == self)		// if initial display of pref
		i = atoi(NXGetDefaultValue([NXApp appName], "iTimeThreshold"));
	else										// else user changed control
		{
		i = [sender intValue];
		sprintf(Path,"%d",(int)i);
		if(!NXWriteDefault([NXApp appName], "iTimeThreshold", Path))
			[[NXApp delegate] showAlert:"ddbWriteError"];
		}											
	[timeoutThreshField setIntValue:i];
	[timeoutThreshCircSlider setIntValue:i];

    return self;
}
//*********************** text field matrix delegation ************************
//*****************************************************************************
//
// 		as text delegate we recieve this when textfield cell is being edited 
//
//*****************************************************************************

- (BOOL)textWillChange:textObject
{
	[[swapView window] setDocEdited:YES];	// indicate change is not saved

    return NO;
}
//*****************************************************************************
//
// 		text delegate receives when editing of textfield cell is ended 
//
//*****************************************************************************

- textDidEnd:textObject endChar:(unsigned short)whyEnd
{
    if ((whyEnd == 16) || (whyEnd == 17)) 
		[[swapView window] setDocEdited:NO];	// indicate change is saved

    return self;
}

@end

//*****************************************************************************
//
// 		create FIFO at designated path with mode set to 
//
//*****************************************************************************

int mkfifo (const char *path, mode_t mode)
{
	return mknod (path, mode | S_IFIFO, 0);
}
