/* Split the default manipulation routines off from the main
	Preferences class */
#import <appkit/appkit.h>
#import "Preferences.h"
#import "InspectorManager.h"

#import <pfs.h>
#import <archie.h>

/*\ -------------- Defaults Stuff -------------- \*/
/* The virgin defaults */
// General preference defaults
#define vShowNewQueries			"YES"
#define vAudioNotification		"YES"
#define vUntitledFirstWindow	"YES"
#define vDebuggingEnabled		"NO"
#define vAppDebugLevel			"0"
#define vDirLoadedSnd			"DirNotifySnd"
#define vQueryReceivedSnd		"QueryNotifySnd"
#define vFTPTransferSnd			"FTPNotifySnd"
// Archie preference defaults
#define vQueryType		"C"
#define vMaxReplies		"100"
#define vSortFlag			"0"
#define vExactMode		"YES"
#define vNiceLevel		"0"
#define vHostname		"archie.sura.net"
#define vHostTag			"5"
#define vIsCustomHost			"NO"
#define vDebugLevel		"2"
// Query preference defaults
#define vModalArchieQuery		"NO"
#define vModalDirQuery		"NO"
#define vServerTimeout			"4"
#define vServerRetries			"3"
#define vMaxDirListingThreads	"2"
// FTP preference defaults
#define vRetrieveSubDirs	"NO"
#define vCollisionWarn		"YES"
#define vMaxFileSize			"20"
#define vTransferPriority	"0"
#define vPrefixCase			"NO"
#define vSuffixCase			"NO"
#define vFtpDebugLevel		"0"
#define vAnonLoginPasswd	"me"
#define vTransferDir		0
#define vFileTypesList		"readme,.txt,index"

/* The owner of the application defaults */
const char *NeXTArchieOwner = "NeXTArchie_SMS";
enum {QueryType,MaxReplies,SortFlag,ExactMode,
	NiceLevel,Hostname,IsCustomHost,DebugLevel,ModalArchieQuery,
	ModalDirQuery,ServerTimeout,ServerRetries,MaxDirListingThreads,
	RetrieveSubDirs,CollisionWarn,MaxFileSize,PrefixCase,
	SuffixCase,FtpDebugLevel,AnonLoginPasswd,FileTypesList,
	ShowNewQueries, AudioNotification, UntitledFirstWindow, DebuggingEnabled,
	AppDebugLevel, TransferDir, DirLoadedSnd, QueryReceivedSnd, FTPTransferSnd,
	TransferPriority, N_Defaults};
#define DStringValue(name) {#name, v ## name}
static NXDefaultsVector NextArchieDefaults = {
	DStringValue(QueryType),
	DStringValue(MaxReplies),
	DStringValue(SortFlag),
	DStringValue(ExactMode),
	DStringValue(NiceLevel),
	DStringValue(Hostname),
	DStringValue(IsCustomHost),
	DStringValue(DebugLevel),
	DStringValue(ModalArchieQuery),
	DStringValue(ModalDirQuery),
	DStringValue(ServerTimeout),
	DStringValue(ServerRetries),
	DStringValue(MaxDirListingThreads),
	DStringValue(RetrieveSubDirs),
	DStringValue(CollisionWarn),
	DStringValue(MaxFileSize),
	DStringValue(PrefixCase),
	DStringValue(SuffixCase),
	DStringValue(FtpDebugLevel),
	DStringValue(AnonLoginPasswd),
	DStringValue(FileTypesList),
	DStringValue(ShowNewQueries),
	DStringValue(AudioNotification),
	DStringValue(UntitledFirstWindow),
	DStringValue(DebuggingEnabled),
	DStringValue(AppDebugLevel),
	DStringValue(TransferDir),
	DStringValue(DirLoadedSnd),
	DStringValue(QueryReceivedSnd),
	DStringValue(FTPTransferSnd),
	DStringValue(TransferPriority),
	{NULL, NULL}
};

/* A macro for retriveing default values */
#define GET_VALUE(STR) NXGetDefaultValue(NeXTArchieOwner, STR)


@implementation Preferences(Defaults)

/* Initialization */
+ initialize
{
char tmp[128], host[64];

[self debug: MAX_DEBUG method: _cmd, "%s(Defaults)", [self name]];

	// Kill any obsolete defaults
	NXRemoveDefault(NeXTArchieOwner, "HostTag");

	/* Set user@hostname as default anonymous password */
	gethostname(host,63);
	host[63] = '\0';
	sprintf(tmp,"%s@%s", NXUserName(), host);
	NextArchieDefaults[AnonLoginPasswd].value = tmp;
	/* Set home dir as default transfer dir */
	NextArchieDefaults[TransferDir].value = NXHomeDirectory();

	/* Register the defaults for the preference items */
	if( NXRegisterDefaults(NeXTArchieOwner, NextArchieDefaults) != 1 )
		[self error: INTERNAL_ALERT method:_cmd key: NXDEFAULTS_FAILURE];

	return self;
}

- loadDefaults
{
char *defaultValue;
int defaultNo;
Sound *snd;

	/* Save the init time default values */
	for(defaultNo = 0; defaultNo < N_Defaults; defaultNo ++)
	{
		defaultValue = GET_VALUE(NextArchieDefaults[defaultNo].name);
		NextArchieDefaults[defaultNo].value = defaultValue;
	}

	// General
	defaultValue = NextArchieDefaults[ShowNewQueries].value;
	oldPrefs.showNewQueries = (*defaultValue == 'Y' ? YES : NO);
	defaultValue = NextArchieDefaults[AudioNotification].value;
	oldPrefs.audioNotification = (*defaultValue == 'Y' ? YES : NO);
	defaultValue = NextArchieDefaults[UntitledFirstWindow].value;
	oldPrefs.untitledFirstWindow = (*defaultValue == 'Y' ? YES : NO);
	defaultValue = NextArchieDefaults[DebuggingEnabled].value;
	oldPrefs.debuggingEnabled = (*defaultValue == 'Y' ? YES : NO);
	/* Set the application debug level  if enabled */
	defaultValue = NextArchieDefaults[AppDebugLevel].value;
	oldPrefs.appDebugLevel = atoi(defaultValue);
	if( oldPrefs.debuggingEnabled == YES )
		[self setAppDebugLevel: oldPrefs.appDebugLevel];
	defaultValue = NextArchieDefaults[DirLoadedSnd].value;
	snd = [Sound findSoundFor: defaultValue];
	if( snd == nil )
		snd = [Sound findSoundFor:
			[Preferences notificationDefault: DirLoaded]];
	[snd setName: defaultValue];
	oldPrefs.sounds[DirLoaded] = snd;
	defaultValue = NextArchieDefaults[QueryReceivedSnd].value;
	snd = [Sound findSoundFor: defaultValue];
	if( snd == nil )
		snd = [Sound findSoundFor:
			[Preferences notificationDefault: QueryReceived]];
	[snd setName: defaultValue];
	oldPrefs.sounds[QueryReceived] = snd;
	defaultValue = NextArchieDefaults[FTPTransferSnd].value;
	snd = [Sound findSoundFor: defaultValue];
	if( snd == nil )
		snd = [Sound findSoundFor:
			[Preferences notificationDefault: FTPTransfer]];
	[snd setName: defaultValue];
	oldPrefs.sounds[FTPTransfer] = snd;

	// Archie
	oldPrefs.serverHost = NextArchieDefaults[Hostname].value;
	defaultValue = NextArchieDefaults[IsCustomHost].value;
	oldPrefs.isCustomHost = (*defaultValue == 'Y' ? YES : NO);
	oldPrefs.customHost[0] = '\0';
	if( oldPrefs.isCustomHost == YES )
		strcpy(oldPrefs.customHost, oldPrefs.serverHost);
	defaultValue = NextArchieDefaults[QueryType].value;
	oldPrefs.queryType = *defaultValue;
	oldPrefs.maxReplies = atoi(NextArchieDefaults[MaxReplies].value);
	oldPrefs.sortFlag = atoi(NextArchieDefaults[SortFlag].value);
	if( oldPrefs.sortFlag == 0 )
		cmpProc = AQ_DEFCMP;
	else
		cmpProc = AQ_INVDATECMP;
	defaultValue = NextArchieDefaults[ExactMode].value;
	oldPrefs.exactMode = (*defaultValue == 'Y' ? YES : NO);
	oldPrefs.niceLevel = atoi(NextArchieDefaults[NiceLevel].value);

	// Query
	defaultValue = NextArchieDefaults[ModalArchieQuery].value;
	oldPrefs.modalArchieQueries = (*defaultValue == 'Y' ? YES : NO);
	defaultValue = NextArchieDefaults[ModalDirQuery].value;
	oldPrefs.modalDirQueries = (*defaultValue == 'Y' ? YES : NO);
	oldPrefs.serverTimeout = atoi(NextArchieDefaults[ServerTimeout].value);
	oldPrefs.serverRetries = atoi(NextArchieDefaults[ServerRetries].value);
	oldPrefs.maxThreadCount = atoi(NextArchieDefaults[MaxDirListingThreads].value);
	oldPrefs.debugLevel = atoi(NextArchieDefaults[DebugLevel].value);

	// FTP
	defaultValue = NextArchieDefaults[RetrieveSubDirs].value;
	oldPrefs.retrieveSubDirs = (*defaultValue == 'Y' ? YES : NO);
	defaultValue = NextArchieDefaults[CollisionWarn].value;
	oldPrefs.collisionWarnings = (*defaultValue == 'Y' ? YES : NO);
	oldPrefs.maxFileSize = atoi(NextArchieDefaults[MaxFileSize].value);
	defaultValue = NextArchieDefaults[PrefixCase].value;
	oldPrefs.prefixCaseSensitive = (*defaultValue == 'Y' ? YES : NO);
	defaultValue = NextArchieDefaults[SuffixCase].value;
	oldPrefs.suffixCaseSensitive = (*defaultValue == 'Y' ? YES : NO);
	oldPrefs.anonPasswd = NextArchieDefaults[AnonLoginPasswd].value;
	oldPrefs.transferDir = NextArchieDefaults[TransferDir].value;
	oldPrefs.fileTypeList = NextArchieDefaults[FileTypesList].value;
	oldPrefs.transferPriority = atoi(NextArchieDefaults[TransferPriority].value);
	prefs = oldPrefs;

	return self;
}

enum {String=1, Int, Char, Bool};
typedef union
{
	char c;
	int i;
	char *str;
} Union;
static char *StringForValue(Preferences *self, int defaultNo,
	void *value, int type)
{
int int_val0, int_val1;
char c_val0, c_val1;
char *str_val0, *str_val1, tmp[128];

	switch( type )
	{
		case String:
			str_val0 = NextArchieDefaults[defaultNo].value;
			str_val1 = * ((char **) value);
[self debug: MAX_DEBUG method:NULL, "StringForValue(%s,%d): s0 = %s; s1 = %s\n",
	NextArchieDefaults[defaultNo].name, defaultNo, str_val0, str_val1];
			if( strcmp(str_val0, str_val1) != 0 )
			{
				str_val0 = malloc(strlen(str_val1)+1);
				strcpy(str_val0, str_val1);
				return str_val0;
			}
			break;
		case Int:
			int_val0 = atoi(NextArchieDefaults[defaultNo].value);
			int_val1 = *((int *) value);
[self debug: MAX_DEBUG method:NULL, "StringForValue(%s,%d): i0 = %d; i1 = %d\n",
	NextArchieDefaults[defaultNo].name, defaultNo, int_val0, int_val1];
			if( int_val0 != int_val1 )
			{
				sprintf(tmp, "%d", int_val1);
				str_val0 = malloc(strlen(tmp)+1);
				strcpy(str_val0, tmp);
				return str_val0;
			}
			break;
		case Char:
			c_val0 = *NextArchieDefaults[defaultNo].value;
			c_val1 = *((char *) value);
[self debug: MAX_DEBUG method:NULL, "StringForValue(%s,%d): c0 = %c; c1 = %c\n",
	NextArchieDefaults[defaultNo].name, defaultNo, c_val0, c_val1];
			if( c_val0 != c_val1 )
			{
				str_val0 = (char *) malloc(2);
				str_val0[0] = c_val1;
				str_val0[1] = '\0';
				return str_val0;
			}
			break;
		case Bool:
			if( *NextArchieDefaults[defaultNo].value == 'Y' )
				c_val0 = YES;
			else
				c_val0 = NO;
			c_val1 = *((char *) value);
[self debug: MAX_DEBUG method:NULL, "StringForValue(%s,%d): c0 = %d; c1 = %d\n",
	NextArchieDefaults[defaultNo].name, defaultNo, c_val0, c_val1];
			if( c_val0 != c_val1 )
			{
				str_val0 = (char *) malloc(4);
				strcpy(str_val0, (c_val1 == YES ? "YES" : "NO"));
				str_val0[3] = '\0';
				return str_val0;
			}
			break;
		default:
			[self error: INTERNAL_ERROR method:NULL key: BAD_DEFAULT_VAL_TYPE];
			break;
	}
	return NULL;
}

/* Update the defaults database with those preferences that have been changed.
	FtpDebugLevel is not saved by this routine. */
- saveDefaults: sender
{
/* --- MethodDescription
	ReturnValue: self;
	Description: This method updates the application default values to
		those in the instance variable prefs.  A value is updated only if
		it differs from the value read in [self init] and saved in
		NextArchieDefaults. It is invoked whenever the user selects the
		save button in the preferences panel.;
	Args: 
		sender: The save button in the preferences panel;
*/
int count = 0;
char *stringValue;
struct _NXDefault newDefaults[N_Defaults];
#define CHECK_DEFAULT(defaultNo, member, type) \
	{\
	if( (stringValue = StringForValue(self, defaultNo, (void *)&prefs.member,\
		type)) != NULL )\
	{\
		newDefaults[count].name = NextArchieDefaults[defaultNo].name;\
		newDefaults[count ++].value = stringValue;\
		/* Update current default reference */\
		NextArchieDefaults[defaultNo].value = stringValue;\
		[self debug: MAX_DEBUG method:_cmd, "%s = %s", NextArchieDefaults[defaultNo].name, stringValue];\
	}}
#define CHECK_DEFAULT2(defaultNo, ptrvalue, type) \
	{\
	if( (stringValue = StringForValue(self, defaultNo, (void *)ptrvalue,\
		type)) != NULL )\
	{\
		newDefaults[count].name = NextArchieDefaults[defaultNo].name;\
		newDefaults[count ++].value = stringValue;\
		/* Update current default reference */\
		NextArchieDefaults[defaultNo].value = stringValue;\
		[self debug: MAX_DEBUG method:_cmd, "%s = %s", NextArchieDefaults[defaultNo].name, stringValue];\
	}}

	// General
	CHECK_DEFAULT(ShowNewQueries,showNewQueries,Bool);
	CHECK_DEFAULT(AudioNotification,audioNotification, Bool);
	CHECK_DEFAULT(UntitledFirstWindow,untitledFirstWindow, Bool);
	stringValue = [prefs.sounds[DirLoaded] name];
	CHECK_DEFAULT2(DirLoadedSnd,&stringValue, String);
	stringValue = [prefs.sounds[QueryReceived] name];
	CHECK_DEFAULT2(QueryReceivedSnd,&stringValue, String);
	stringValue = [prefs.sounds[FTPTransfer] name];
	CHECK_DEFAULT2(FTPTransferSnd,&stringValue, String);
	// Archie
	CHECK_DEFAULT(Hostname,serverHost, String);
	CHECK_DEFAULT(IsCustomHost,isCustomHost, Bool);
	CHECK_DEFAULT(QueryType,queryType, Char);
	CHECK_DEFAULT(MaxReplies,maxReplies, Int);
	CHECK_DEFAULT(SortFlag,sortFlag, Int);
	CHECK_DEFAULT(ExactMode,exactMode, Bool);
	CHECK_DEFAULT(NiceLevel,niceLevel, Int);
	// Query
	CHECK_DEFAULT(ModalArchieQuery,modalArchieQueries, Bool);
	CHECK_DEFAULT(ModalDirQuery,modalDirQueries, Bool);
	CHECK_DEFAULT(ServerTimeout,serverTimeout,Int);
	CHECK_DEFAULT(ServerRetries,serverRetries,Int);
	CHECK_DEFAULT(MaxDirListingThreads,maxThreadCount,Int);
	CHECK_DEFAULT(DebugLevel,debugLevel,Int);
	// FTP
	CHECK_DEFAULT(RetrieveSubDirs,retrieveSubDirs, Bool);
	CHECK_DEFAULT(CollisionWarn,collisionWarnings, Bool);
	CHECK_DEFAULT(MaxFileSize,maxFileSize,Int);
	CHECK_DEFAULT(PrefixCase,prefixCaseSensitive, Bool);
	CHECK_DEFAULT(SuffixCase,suffixCaseSensitive, Bool);
	CHECK_DEFAULT(AnonLoginPasswd,anonPasswd,String);
	CHECK_DEFAULT(TransferDir,transferDir,String);
	CHECK_DEFAULT(FileTypesList,fileTypeList, String);
	CHECK_DEFAULT(TransferPriority, transferPriority, Int);

	/* If there are any new values write them out */
	if( count > 0 )
	{
		newDefaults[count].name = newDefaults[count].value = NULL;
		NXWriteDefaults(NeXTArchieOwner, newDefaults);
		while( count > 0 )
		{
			free(newDefaults[count].value);
			count --;
		}
		/* Update the backup prefs */
		oldPrefs = prefs;
	}

	return self;
}

- restoreDefaults: sender
{
int group;

	/* Restore the defaults that were loaded at -init time */
	prefs = oldPrefs;

	/* Reset the preferences panel objects */
	group = [sender group];
	if( group == generalPrefsGrp )
		resetPrefPanel |= GENERAL_PREFS_BIT;
	else if( group == archiePrefsGrp )
		resetPrefPanel |= ARCHIE_PREFS_BIT;
	else if( group == queryPrefsGrp )
		resetPrefPanel |= QUERY_PREFS_BIT;
	else if( group == ftpPrefsGrp )
		resetPrefPanel |= FTP_PREFS_BIT;

	[self display];

	return self;
}

@end
/* RCS Information:
	$Author: me $;
	$Date: 94/01/08 14:40:59 $;
	$Source: /usr1/me/NeXTSrc/Archie/RCS/Preferences_Defaults.m,v $;
	$Revision: 1.1 $;
	$Log:	Preferences_Defaults.m,v $
Revision 1.1  94/01/08  14:40:59  me
Check point of 2.09a version.

Revision 1.2  93/03/02  16:04:06  me
Corrected DebuggingEnabled default name.

Revision 1.1  93/02/23  02:11:27  me
Version 2.01a of the project.
;
*/
