#import <pwd.h>
#import <math.h>
#import "Fiend.h"
#import "FiendWraps.h"
#import "Controller.h"
#import "ProgressView.h"
#import "Dock.h"
#import "DockMgrView.h"
#import "ShelfView.h"
#import "IconView.h"
#import "Thinker.h"
#import "Password.h"
#import <misckit/misckit.h>
//#import <otikit/smartkit.h>

@interface MenuCell(LazyEnable)
- lazySetEnabled:(BOOL)flag;
@end

@implementation MenuCell(LazyEnable)
- lazySetEnabled:(BOOL)flag
{
	if ([self isEnabled] != flag)
		[self setEnabled:flag];
	return self;
}
@end

@implementation Controller

+ initialize
{
    static NXDefaultsVector defaults = {
		{"LBX", "50"},
		{"LBY", "13"},
		{"LBW", "11"},
		{"LBH", "11.5"},
		{"RBX", "51"},
		{"RBY", "4.0"},
		{"RBW", "10"},
		{"RBH", "10"},
		{"LIX", "55.0"},
		{"LIY", "38.0"},
		{"LIR", "1.8"},
		{SGRID_VALUE, "64"},
		{DGRID_VALUE, "64"},
		{SCAN_TIME, "0.5"},
        {GRID_ENABLE, "NO"},
		{USE_SOUND, "YES"},
		{SHOW_DOCK, "YES"},
		{TILE_IMAGE, "NO"},
		{CUR_DOCK, "1"},
		{SIZE_FONT, "YES"},
		{HIDE_ICONS, "YES"},
		{SHOW_SELPNL, "YES"},
		{SHOW_PROG, "YES"},
		{SHOW_DCKIDX, "YES"},
		{ENAB_DCLCK, "YES"},
		{ENAB_SCLCK, "YES"},
		{SINK_DOCK, "NO"},
		{FOLLOW_LEVS, "NO"},
		{ENAB_BSPACE, "YES"},
		{ENAB_SHELF, "YES"},
		{CPST_SHLF, "NO"},
		{DRAW_TNAIL, "YES"},
		{LIMIT_SHLF, "NO"},
		{DSTRICT_COPY, "NO"},
		{SSTRICT_COPY, "NO"},
		{SHELF_APPTIL, "NO"},
		{CLOSE_PSTLNCH, "NO"},
		{CLOSE_PSTACT, "YES"},
		{SHOW_CUES, "YES"},
		{PTAB_RETRIES, "20"},
		{ACTIVE_DELAY, "0.5"},
		{DOCK_BLDFNT, "YES"},
		{DOCK_BIGFNT, "NO"},
		{DOCK_LOCKED, "NO"},
		{IMAGE_NAME, DEFAULT_IMAGE_NAME},
		{DCKUPR_LEVEL, "6"},
		{DCKLWR_LEVEL, "-1"},
		{SHELF_LEVEL, "-31000"},
		{"DisableLazyLoad", "NO"},
		{"PreLaunchDelay", "250"},
//		{"DockPromiscuous", "NO"},
#ifdef hppa
		{REDSP_SHLF, "YES"},
#else
		{REDSP_SHLF, "NO"},
#endif
        {NULL}
    };

    NXRegisterDefaults([NXApp appName], defaults);
	NXSetDefault("BackSpace", "windowType", "0");
    return self;
}

- delayedAutolaunch
{
	[dockMgrView performAutolaunches];
	return self;
}

- delayedAppDidInit:sender
{
	int				i;
	id				dockWindow;
    int			  	screenCount;
	char			string[200];
    NXScreen		*screens;
    id				shelfWindow = NULL;
	NXRect			iconRect = {{400.0, 400.0}, {64.0, 64.0}};
	NXRect			screenRect = {{0.0, 0.0}, {0.0, 0.0}};
    NXRect			contentRect = {{0.0, 0.0}, {0.0, 0.0}};
	int				lowerLevel = atoi(NXGetDefaultValue([NXApp appName], DCKLWR_LEVEL));
	int				upperLevel = atoi(NXGetDefaultValue([NXApp appName], DCKUPR_LEVEL));
	int				shelfLevel = atoi(NXGetDefaultValue([NXApp appName], SHELF_LEVEL));
	float			preLaunchDelay = atof(NXGetDefaultValue([NXApp appName], "PreLaunchDelay"));
	float			dgridValue = atof(NXGetDefaultValue([NXApp appName], DGRID_VALUE));
	BOOL			sinkDock = !strcmp(NXGetDefaultValue([NXApp appName], SINK_DOCK), "YES");
	BOOL			limitShelf = !strcmp(NXGetDefaultValue([NXApp appName], LIMIT_SHLF), "YES");
	BOOL			showProgress = !strcmp(NXGetDefaultValue([NXApp appName], SHOW_PROG), "YES");
	BOOL			shelfEnabled = !strcmp(NXGetDefaultValue([NXApp appName], ENAB_SHELF), "YES");
	BOOL			redisplayShelf = !strcmp(NXGetDefaultValue([NXApp appName], REDSP_SHLF), "YES");
	BOOL			backSpaceEnabled = !strcmp(NXGetDefaultValue([NXApp appName], ENAB_BSPACE), "YES");
	const char 		*returnTypes[] = {NXFilenamePboardType, NXAsciiPboardType, NULL};
	const char 		*sendTypes[] = {NXFilenamePboardType, NULL};

	[NXApp hide:self];
	[NXApp preventWindowOrdering];
	[NXApp registerServicesMenuSendTypes:sendTypes andReturnTypes:returnTypes];
	[[NXApp appListener] setServicesDelegate:self];

	[NXApp getScreens:&screens count:&screenCount];
	for(i = 0; i < screenCount; i++)
		NXUnionRect(&screens[i].screenBounds, &screenRect);

	if (showProgress)	{
		if (shelfEnabled)
			[[progressField setStringValue:PROG_SHELF] display];
		else
			[[progressField setStringValue:PROG_DOCK] display];
		[progressPanel center];
		[progressPanel makeKeyAndOrderFront:self];
		[progressPanel setFloatingPanel:YES];
	}

	if (shelfEnabled)	{
		shelfWindow = [[Window allocFromZone:NXCreateZone(vm_page_size, vm_page_size, YES)]
								initContent:&screenRect
								style:NX_TOKENSTYLE
								backing:NX_BUFFERED buttonMask:0 defer:NO];

		if (limitShelf)	{
			[shelfWindow setDepthLimit:NX_TwelveBitRGBDepth];
			[shelfWindow setDynamicDepthLimit:YES];
		}
		shelfView = [ShelfView allocFromZone:[shelfWindow zone]];
		[IconView resetCachedShelfImages];
		[shelfView initFrame:&screenRect];
		[[shelfWindow setContentView:shelfView] free];
		[shelfWindow setAvoidsActivation:YES];

		PSsetwindowlevel(shelfLevel, [shelfWindow windowNum]);
		[shelfWindow display];
		[shelfWindow orderBack:self];
		if (redisplayShelf)
			[shelfWindow display];
	}
	else
		[shelfDisabledTee setEnabled:NO];

	[progressView setRatio:1.0];

	if (dgridValue)
		iconRect.size.width = iconRect.size.height = dgridValue;
	dockWindow = [[Window allocFromZone:NXCreateZone(vm_page_size, vm_page_size, YES)]
				            initContent:&iconRect
				                  style:NX_TOKENSTYLE
				                backing:NX_BUFFERED buttonMask:0 defer:NO];

	[dockWindow useOptimizedDrawing:YES];
	[dockWindow addToEventMask:(NX_KEYDOWNMASK | NX_KEYUPMASK)];
	[dockWindow setAvoidsActivation:YES];

	[dockWindow setFrameUsingName:"DockWindow"];
	sprintf(string, "DockWindow%d-%d", (int)NX_WIDTH(&screenRect), (int)NX_HEIGHT(&screenRect));
	[dockWindow setFrameUsingName:string];
	[dockWindow getFrame:&contentRect];
	if (NX_MIDX(&contentRect) > NX_WIDTH(&screenRect))
		NX_X(&contentRect) = fmod(NX_X(&contentRect), NX_WIDTH(&screenRect)-NX_WIDTH(&contentRect));
	if (NX_MIDY(&contentRect) > NX_HEIGHT(&screenRect))
		NX_Y(&contentRect) = fmod(NX_Y(&contentRect), NX_HEIGHT(&screenRect)-NX_HEIGHT(&contentRect));
	[dockWindow moveTo:NX_X(&contentRect) :NX_Y(&contentRect)];
    [[dockWindow contentView] getFrame:&contentRect];

	if (showProgress)	{
		[[progressField setStringValue:PROG_DOCK] display];
		[progressView setRatio:0.0];
	}
	dockMgrView = [DockMgrView allocFromZone:[dockWindow zone]];
	[IconView resetCachedDockImages];
	[IconView setCachedDockImageSize:&contentRect.size];
	[dockMgrView initFrame:&contentRect withWindow:dockWindow];
	[dockMgrView startScanTimer];

    PSsetwindowlevel((sinkDock) ? lowerLevel : upperLevel, [dockWindow windowNum]);
	[dockWindow setDelegate:dockMgrView];
	[dockWindow display];
	[dockWindow orderFront:self];

	if (backSpaceEnabled)	{
		if (showProgress)	{
			[[progressField setStringValue:PROG_BSPACE] display];
			[progressView setRatio:0.0];
		}
		[NXApp loadNibSection:"BackSpace.nib" owner:self withNames:NO];
		[thinker appDidInit:sender];
		[progressView setRatio:1.0];
	}
	else
		[backSpaceMenuItem setEnabled:NO];

	if (showProgress)
		[progressPanel orderOut:self];

	sprintf(string, "%s/.AppInfo", NXHomeDirectory());
	mkdir(string, 0777);
    sprintf(string, "%s/.AppInfo/Fiend", NXHomeDirectory());
	mkdir(string, 0777);

	sprintf(string, "%s", [(NXBundle *)[NXBundle mainBundle] directory]);
	if (!onNeXTDock((const char *)string, screens[0].screenBounds.size.height))
		[[[NXApp appIcon] getFrame:&origFrame] moveTo:-1000.0 :-1000.0];

	[self updateMenus];
	[[Application workspace] beginListeningForApplicationStatusChanges];
	[self perform:@selector(delayedAutolaunch) with:nil afterDelay:preLaunchDelay
		cancelPrevious:NO];
    return self;
}

- appDidInit:sender
{
	[self perform:@selector(delayedAppDidInit:) with:sender afterDelay:1.0
	 cancelPrevious:NO];
	return self;
}

- updateMenus
{
	int		dockLevelCount = [dockMgrView levelCount];
	int		dockSelCount = [dockMgrView hasSelectedCells];
	int		stickySelCount = [[dockMgrView stickyDock] hasSelectedCells];
	int		dockTotIconCount = [dockMgrView totalIconCount];
	int		curDockIconCount = [[dockMgrView currentDock] iconCount];
	int		shelfSelCount = (shelfView != nil) ? [shelfView hasSelectedCells] : 0;
	int		shelfIconCount = (shelfView != nil) ? [[shelfView subviews] count] : 0;

	[dockLevelCountTee lazySetEnabled:(dockLevelCount > 1)];
	[dockIconCountTee lazySetEnabled:(curDockIconCount > 0)];

	if (shelfView)	{
		[shelfIconCountTee lazySetEnabled:(shelfIconCount > 0)];
		[shelfSnapMenuItem lazySetEnabled:(shelfSelCount > 0)];
	}

	[cutMenuItem lazySetEnabled:(shelfSelCount > 0 || (dockSelCount > 0 && stickySelCount == 0))];
	[copyMenuItem lazySetEnabled:(shelfSelCount > 0 || dockSelCount > 0)];
	[dockInspectMenuItem lazySetEnabled:(dockSelCount == 1 || stickySelCount == 1)];
	[dockFindIconMenuItem lazySetEnabled:(dockTotIconCount > 0)];
	[dockMoveIconsMenuItem lazySetEnabled:(dockSelCount > 0 && dockLevelCount > 1 && stickySelCount == 0)];
	[dockAddWSMenuItem lazySetEnabled:([dockMgrView findLevelContaining:WKSPC_FILE switch:NO] == -1)];

	return self;
}

- setProgressViewRatio:(float)aValue
{
	[progressView setRatio:aValue];
	return self;
}

- setProgressFieldString:(const char *)aString
{
	[[progressField setStringValue:aString] display];
	return self;
}

- hideOrShowMenus:sender
{
    [[MiscExplodingMenu sharedInstance] explodeMenus:sender];
    return self;
}

- appDidResignActive:sender
{
	[[dockMgrView window] endEditingFor:nil];
	return self;
}

- appDidHide:sender
{
	if (thinker != nil)
		return [thinker appDidHide:sender];
	else
		return self;
}

- appDidUnhide:sender
{
	if (thinker != nil)
		return [thinker appDidUnhide:sender];
	else
		return self;
}

- app:theApp applicationDidTerminate:(const char *)appName
{
	[dockMgrView app:theApp applicationDidTerminate:appName];
	return self;
}

- app:theApp applicationDidLaunch:(const char *)appName
{
	[dockMgrView app:theApp applicationDidLaunch:appName];
	return self;
}

- app:theApp applicationWillLaunch:(const char *)appName
{
	[dockMgrView app:theApp applicationWillLaunch:appName];
	return self;
}

- app:sender powerOffIn:(int)ms andSave:(int)aFlag
{
	return [NXApp terminate:self];
}

- appWillTerminate:sender
{
	int			i;
	int			screenCount;
	char		string[100];
    NXScreen	*screens;
    NXRect		contentRect = {{0.0, 0.0}, {0.0, 0.0}};
	BOOL		shelfEnabled = !strcmp(NXGetDefaultValue([NXApp appName], ENAB_SHELF), "YES");

	[NXApp getScreens:&screens count:&screenCount];
	for(i = 0; i < screenCount; i++)
		NXUnionRect(&screens[i].screenBounds, &contentRect);

	[dockMgrView killLauncher];
	[dockMgrView vanishDocks:NO];
	PSshowcursor(); NXPing();

	sprintf(string, "DockWindow%d-%d", (int)NX_WIDTH(&contentRect), (int)NX_HEIGHT(&contentRect));
	[[dockMgrView window] saveFrameUsingName:string];

	sprintf(string, "%d", [dockMgrView currentDockIndex]+1);
	NXWriteDefault([NXApp appName], CUR_DOCK, string);

	if (thinker != nil)
		[thinker normalMode];

	if (shelfEnabled)
		[shelfView writeShelf];
	[dockMgrView writeDocks];
	NXWriteDefault([NXApp appName], SHOW_DOCK, ([dockMgrView showDock])?"YES":"NO");
	NXWriteDefault([NXApp appName], DOCK_LOCKED, ([dockMgrView dockLocked])?"YES":"NO");
	PSshowcursor(); NXPing();

	return self;
}

- applicationDefined:(NXEvent *)e
{
	if (thinker != nil)
		return [thinker applicationDefined:e];
	else
		return self;
}

- doPanel:(id *)panel named:(const char *) name
{
    char	path[MAXPATHLEN+1];
    id		bundle = [NXBundle mainBundle];

    if ((*panel == nil) && [bundle getPath:path forResource:name ofType:"nib"])	{
		[NXApp loadNibFile:path owner:self withNames:NO fromZone:[self zone]];
		[*panel center];
	}
    [*panel makeKeyAndOrderFront:self];

    return self;
}

- doDocument:sender
{
	char	path[MAXPATHLEN+1];
	int		index = [[sender selectedCell] tag];
	static char	*docs[] = {"aa_README.rtf",
						   "ab_FAQ.rtf",
						   "ac_ReleaseNotes.rtf",
						   "ad_Instructions.rtfd"};

	sprintf(path, "%s/English.lproj/%s", [(NXBundle *)[NXBundle mainBundle] directory], docs[index]);
	[[Application workspace] openFile:path];
	return self;
}

- doInfo:sender
{
    return [self doPanel:&infoPanel named:"Info"];
}

- showBackSpaceSettings:sender
{
	[thinker showSettingsPanel:self];
	[dockMgrView windowDidResignKey:self];
	return self;
}

- doBackSpaceScreenSaver:sender
{
	[thinker showFakeScreenSaver:self];
	[dockMgrView windowDidResignKey:self];
	return self;
}

- whirl:sender
{
	NXSize		aSize;

	[NXApp getScreenSize:&aSize];
	[dockMgrView stopScanTimer];
	thread_switch(THREAD_NULL, SWITCH_OPTION_WAIT, 1000);
	PSWSetDockOnTop(YES);
	PSWWhirl(aSize.width/2.0, aSize.height/2.0);
	PSWSetDockOnTop(NO);
	[dockMgrView startScanTimer];
	return self;
}

- revertPreferences:sender
{
	const char	*appName = [NXApp appName];
	int		sgridValue = atoi(NXGetDefaultValue(appName, SGRID_VALUE));
	int		dgridValue = atoi(NXGetDefaultValue(appName, DGRID_VALUE));
	double	scanTime = atof(NXGetDefaultValue(appName, SCAN_TIME));
	BOOL	sgridEnabled = !strcmp(NXGetDefaultValue(appName, GRID_ENABLE), "YES");
	BOOL	useSound = !strcmp(NXGetDefaultValue(appName, USE_SOUND), "YES");
	BOOL	tileImage = !strcmp(NXGetDefaultValue(appName, TILE_IMAGE), "YES");
	BOOL	sizeFont = !strcmp(NXGetDefaultValue(appName, SIZE_FONT), "YES");
	BOOL	hideIcons = !strcmp(NXGetDefaultValue(appName, HIDE_ICONS), "YES");
	BOOL	showSelPanel = !strcmp(NXGetDefaultValue(appName, SHOW_SELPNL), "YES");
	BOOL	showProgress = !strcmp(NXGetDefaultValue(appName, SHOW_PROG), "YES");
	BOOL	showDockIndex = !strcmp(NXGetDefaultValue(appName, SHOW_DCKIDX), "YES");
	BOOL	enableDockClick = !strcmp(NXGetDefaultValue(appName, ENAB_DCLCK), "YES");
	BOOL	enableShelfClick = !strcmp(NXGetDefaultValue(appName, ENAB_SCLCK), "YES");
	BOOL	followLevels = !strcmp(NXGetDefaultValue(appName, FOLLOW_LEVS), "YES");
	BOOL	enableBackSpace = !strcmp(NXGetDefaultValue(appName, ENAB_BSPACE), "YES");
	BOOL	enableShelf = !strcmp(NXGetDefaultValue(appName, ENAB_SHELF), "YES");
	BOOL	drawThumbnails = !strcmp(NXGetDefaultValue(appName, DRAW_TNAIL), "YES");
	BOOL	limitShelfDepth = !strcmp(NXGetDefaultValue(appName, LIMIT_SHLF), "YES");
	BOOL	dockStrictCopy = !strcmp(NXGetDefaultValue(appName, DSTRICT_COPY), "YES");
	BOOL	shelfStrictCopy = !strcmp(NXGetDefaultValue(appName, SSTRICT_COPY), "YES");
	BOOL	shelfAppTiles = !strcmp(NXGetDefaultValue(appName, SHELF_APPTIL), "YES");
	BOOL	closePostLaunch = !strcmp(NXGetDefaultValue(appName, CLOSE_PSTLNCH), "YES");
	BOOL	showCues = !strcmp(NXGetDefaultValue(appName, SHOW_CUES), "YES");
	const char	*imageName = NXGetDefaultValue(appName, IMAGE_NAME);

	[shelfSizeField setIntValue:sgridValue];
	[dockSizeField setIntValue:dgridValue];
	if (scanTime >= 0.25 && scanTime <= 10.0)	{
		[scanTimeField setFloatValue:scanTime];
		[scanTimeSlider setFloatValue:scanTime];
	}
	else	{
		[scanTimeField setStringValueNoProcess:"Off"];
		[scanTimeSlider setFloatValue:[(Slider *)scanTimeSlider maxValue]];
	}

	[useGridSwitch setState:sgridEnabled];
	[useSoundSwitch setState:useSound];
	[tileSwitch setState:tileImage];
	[sizeFontSwitch setState:sizeFont];
	[hideIconsSwitch setState:hideIcons];
	[showSelPanelSwitch setState:showSelPanel];
	[showProgressSwitch setState:showProgress];
	[showIndexSwitch setState:showDockIndex];
	[dockSingleClickSwitch setState:enableDockClick];
	[shelfSingleClickSwitch setState:enableShelfClick];
	[followLevelSwitch setState:followLevels];
	[enableBackSpaceSwitch setState:enableBackSpace];
	[enableShelfSwitch setState:enableShelf];
	[drawThumbnailSwitch setState:drawThumbnails];
	[limitDepthSwitch setState:limitShelfDepth];
	[dockStrictCopySwitch setState:dockStrictCopy];
	[shelfStrictCopySwitch setState:shelfStrictCopy];
	[showAppTileSwitch setState:shelfAppTiles];
	[closePostLaunchSwitch setState:closePostLaunch];
	[showCuesSwitch setState:showCues];
	[imageFileField setStringValue:imageName];

	if (!enableShelf)
		[shelfDisabledPrefsTee setEnabled:NO];

	[setPrefsButton setEnabled:NO];
	[revertPrefsButton setEnabled:NO];

	return self;
}


- setPreferences:sender
{
	const char	*appName = [NXApp appName];
	int		sGridValue = [shelfSizeField intValue];
	int		dGridValue = [dockSizeField intValue];
	float	scanTime = [scanTimeSlider floatValue];
	BOOL	sgridEnabled = [useGridSwitch state];
	BOOL	useSound = [useSoundSwitch state];
	BOOL	tileImage = [tileSwitch state];
	BOOL	sizeFont = [sizeFontSwitch state];
	BOOL	hideIcons = [hideIconsSwitch state];
	BOOL	showSelPanel = [showSelPanelSwitch state];
	BOOL	showProgress = [showProgressSwitch state];
	BOOL	showDockIndex = [showIndexSwitch state];
	BOOL	enableDockClick = [dockSingleClickSwitch state];
	BOOL	enableShelfClick = [shelfSingleClickSwitch state];
	BOOL	followLevels = [followLevelSwitch state];
	BOOL	enableBackSpace = [enableBackSpaceSwitch state];
	BOOL	enableShelf = [enableShelfSwitch state];
	BOOL	drawThumbnails = [drawThumbnailSwitch state];
	BOOL	limitShelfDepth = [limitDepthSwitch state];
	BOOL	dockStrictCopy = [dockStrictCopySwitch state];
	BOOL	shelfStrictCopy = [shelfStrictCopySwitch state];
	BOOL	shelfAppTiles = [showAppTileSwitch state];
	BOOL	closePostLaunch = [closePostLaunchSwitch state];
	BOOL	showCues = [showCuesSwitch state];
	const char	*imageName = [imageFileField stringValue];

	int		oldSGridValue = atoi(NXGetDefaultValue(appName, SGRID_VALUE));
	int		oldDGridValue = atoi(NXGetDefaultValue(appName, DGRID_VALUE));
	double	oldScanTime = atof(NXGetDefaultValue(appName, SCAN_TIME));
	BOOL	oldSgridEnabled = !strcmp(NXGetDefaultValue(appName, GRID_ENABLE), "YES");
	BOOL	oldUseSound = !strcmp(NXGetDefaultValue(appName, USE_SOUND), "YES");
	BOOL	oldTileImage = !strcmp(NXGetDefaultValue(appName, TILE_IMAGE), "YES");
	BOOL	oldSizeFont = !strcmp(NXGetDefaultValue(appName, SIZE_FONT), "YES");
	BOOL	oldHideIcons = !strcmp(NXGetDefaultValue(appName, HIDE_ICONS), "YES");
	BOOL	oldShowSelPanel = !strcmp(NXGetDefaultValue(appName, SHOW_SELPNL), "YES");
	BOOL	oldShowProgress = !strcmp(NXGetDefaultValue(appName, SHOW_PROG), "YES");
	BOOL	oldShowDockIndex = !strcmp(NXGetDefaultValue(appName, SHOW_DCKIDX), "YES");
	BOOL	oldEnableDockClick = !strcmp(NXGetDefaultValue(appName, ENAB_DCLCK), "YES");
	BOOL	oldEnableShelfClick = !strcmp(NXGetDefaultValue(appName, ENAB_SCLCK), "YES");
	BOOL	oldFollowLevels = !strcmp(NXGetDefaultValue(appName, FOLLOW_LEVS), "YES");
	BOOL	oldEnableBackSpace = !strcmp(NXGetDefaultValue(appName, ENAB_BSPACE), "YES");
	BOOL	oldEnableShelf = !strcmp(NXGetDefaultValue(appName, ENAB_SHELF), "YES");
	BOOL	oldDrawThumbnails = !strcmp(NXGetDefaultValue(appName, DRAW_TNAIL), "YES");
	BOOL	oldLimitShelfDepth = !strcmp(NXGetDefaultValue(appName, LIMIT_SHLF), "YES");
	BOOL	oldDockStrictCopy = !strcmp(NXGetDefaultValue(appName, DSTRICT_COPY), "YES");
	BOOL	oldShelfStrictCopy = !strcmp(NXGetDefaultValue(appName, SSTRICT_COPY), "YES");
	BOOL	oldShelfAppTiles = !strcmp(NXGetDefaultValue(appName, SHELF_APPTIL), "YES");
	BOOL	oldClosePostLaunch = !strcmp(NXGetDefaultValue(appName, CLOSE_PSTLNCH), "YES");
	BOOL	oldShowCues = !strcmp(NXGetDefaultValue(appName, SHOW_CUES), "YES");
	const char	*oldImageName = NXGetDefaultValue(appName, IMAGE_NAME);

	if (dGridValue != oldDGridValue)	{
		NXWriteDefault(appName, DGRID_VALUE, [dockSizeField stringValue]);
		[dockMgrView setIconSize:[dockSizeField intValue]];
	}

	if (sGridValue != oldSGridValue)	{
		NXWriteDefault(appName, SGRID_VALUE, [shelfSizeField stringValue]);
		[shelfView setAutodisplay:NO];
		[shelfView setGridValue:[shelfSizeField intValue]];
	}

	if (scanTime != oldScanTime)	{
		if (scanTime > 10.0)	{
			scanTime = -1.0;
			NXWriteDefault(appName, SCAN_TIME, "-1.0");
			[dockMgrView restoreIcons];
		}
		else
			NXWriteDefault(appName, SCAN_TIME, [scanTimeSlider stringValue]);
		[dockMgrView stopScanTimer];
		[dockMgrView startScanTimer];
	}

	if (sgridEnabled != oldSgridEnabled)
		NXWriteDefault(appName, GRID_ENABLE, (sgridEnabled)?"YES":"NO");

	if (useSound != oldUseSound)
		NXWriteDefault(appName, USE_SOUND, (useSound)?"YES":"NO");

	if (strcmp(imageName, oldImageName))	{
		[shelfView setAutodisplay:NO];
		if ([shelfView setImageFileName:[imageFileField stringValue]])
			NXWriteDefault(appName, IMAGE_NAME, imageName);
		else
			[imageFileField setStringValue:oldImageName];
	}

	if (tileImage != oldTileImage)	{
		NXWriteDefault(appName, TILE_IMAGE, (tileImage)?"YES":"NO");
		[shelfView setAutodisplay:NO];
		[shelfView setTileImage:tileImage];
	}

	if (sizeFont != oldSizeFont)
		NXWriteDefault(appName, SIZE_FONT, (sizeFont)?"YES":"NO");

	if (hideIcons != oldHideIcons)	{
		NXWriteDefault(appName, HIDE_ICONS, (hideIcons)?"YES":"NO");
		[dockMgrView vanishDocks:hideIcons];
	}

	if (showSelPanel != oldShowSelPanel)
		NXWriteDefault(appName, SHOW_SELPNL, (showSelPanel)?"YES":"NO");
	if (showProgress != oldShowProgress)
		NXWriteDefault(appName, SHOW_PROG, (showProgress)?"YES":"NO");
	if (showDockIndex != oldShowDockIndex)
		NXWriteDefault(appName, SHOW_DCKIDX, (showDockIndex)?"YES":"NO");
	if (enableDockClick != oldEnableDockClick)
		NXWriteDefault(appName, ENAB_DCLCK, (enableDockClick)?"YES":"NO");
	if (enableShelfClick != oldEnableShelfClick)
		NXWriteDefault(appName, ENAB_SCLCK, (enableShelfClick)?"YES":"NO");
	if (followLevels != oldFollowLevels)	{
		NXWriteDefault(appName, FOLLOW_LEVS, (followLevels)?"YES":"NO");
		[dockMgrView setFollowLevels:followLevels];
	}
	if (enableBackSpace != oldEnableBackSpace)
		NXWriteDefault(appName, ENAB_BSPACE, (enableBackSpace)?"YES":"NO");
	if (enableShelf != oldEnableShelf)
		NXWriteDefault(appName, ENAB_SHELF, (enableShelf)?"YES":"NO");
	if (drawThumbnails != oldDrawThumbnails)
		NXWriteDefault(appName, DRAW_TNAIL, (drawThumbnails)?"YES":"NO");
	if (limitShelfDepth != oldLimitShelfDepth)
		NXWriteDefault(appName, LIMIT_SHLF, (limitShelfDepth)?"YES":"NO");
	if (dockStrictCopy != oldDockStrictCopy)
		NXWriteDefault(appName, DSTRICT_COPY, (dockStrictCopy)?"YES":"NO");
	if (shelfStrictCopy != oldShelfStrictCopy)
		NXWriteDefault(appName, SSTRICT_COPY, (shelfStrictCopy)?"YES":"NO");
	if (shelfAppTiles != oldShelfAppTiles)
		NXWriteDefault(appName, SHELF_APPTIL, (shelfAppTiles)?"YES":"NO");
	if (closePostLaunch != oldClosePostLaunch)
		NXWriteDefault(appName, CLOSE_PSTLNCH, (closePostLaunch)?"YES":"NO");
	if (showCues != oldShowCues)	{
		NXWriteDefault(appName, SHOW_CUES, (showCues)?"YES":"NO");
		[dockMgrView redisplayAllIcons];
	}

	[shelfView displayIfNeeded];
	[dockMgrView display];

	[setPrefsButton setEnabled:NO];
	[revertPrefsButton setEnabled:NO];

	return self;
}

- doPreferences:sender
{

    [self doPanel:&prefPanel named:"Preferences"];
	[prefPanel disableFlushWindow];
	[self revertPreferences:self];
	[[prefPanel reenableFlushWindow] flushWindowIfNeeded];
	[dockMgrView windowDidResignKey:self];

    return self;
}

- activatePrefButtons:sender
{
	if (sender != self && [sender tag] == 1)	{
		NXRunAlertPanel([NXApp appName],
						"This change will take effect when you restart Fiend...",
						NULL, NULL, NULL);
	}

	[setPrefsButton setEnabled:YES];
	[revertPrefsButton setEnabled:YES];
	return self;
}

- takeFloatValueFrom:sender
{
	float	value = [sender floatValue];

	if (value > 10.0)	{
		[scanTimeSlider setFloatValue:[(Slider *)scanTimeSlider maxValue]];
		[scanTimeField setStringValueNoProcess:"Off"];
	}
	else	{
		if (sender == scanTimeSlider)
			[scanTimeField setFloatValue:[sender floatValue]];
		else	{
			[sender selectText:self];
			[scanTimeSlider setFloatValue:[sender floatValue]];
		}
	}
	return [self activatePrefButtons:self];
}

- textDidChange:sender
{
	return [self activatePrefButtons:self];
}

- setBackSpacePassword:sender;
{
	if (thinker != nil)
		[passObj setPassword:sender];
	return self;
}

- ping:sender
{
	return [self activatePrefButtons:self];
}

- clearLevel:sender
{
	[dockMgrView clearDockLevel];
	return self;
}

- rotateLevel:sender
{
	[dockMgrView rotateOffsets];
	[dockMgrView display];
	return self;
}

- toggleDockLock:sender
{
	[dockMgrView setDockLocked:![dockMgrView dockLocked]];
	return self;
}

- toggleDock:sender
{
	[dockMgrView setShowDock:![dockMgrView showDock]];
	return self;
}

- nextLevel:sender
{
	[dockMgrView nextLevel];
	return self;
}

- previousLevel:sender
{
	[dockMgrView previousLevel];
	return self;
}

- nameLevel:sender
{
	[nameLevelField setStringValue:[[dockMgrView currentDock] name]];
	[nameLevelField selectText:self];
	[dockMgrView windowDidResignKey:self];
	modalCanceled = NO;
	[NXApp runModalFor:nameLevelPanel];
	if (!modalCanceled)    {
		[(DockMgrView *)dockMgrView nameLevel:(char *)[nameLevelField stringValue]];
		[dockMgrView display];
	}

	return self;
}

- findNamedLevel:sender
{
	[findLevelStringField selectText:self];
	[dockMgrView windowDidResignKey:self];
	modalCanceled = NO;
	[NXApp runModalFor:findLevelPanel];
	if (!modalCanceled)    {
		[dockMgrView gotoNamedLevel:(char *)[findLevelStringField stringValue]];
		[dockMgrView display];
	}
	return self;
}

- moveIcons:sender
{
	[moveIconsField selectText:self];
	[dockMgrView windowDidResignKey:self];
	modalCanceled = NO;
	[NXApp runModalFor:moveIconsPanel];
	if (!modalCanceled)   {
		[dockMgrView moveIconsTo:[moveIconsField intValue]-1];
		[dockMgrView display];
	}
	return self;
}

- gotoLevel:sender
{
	[gotoField setIntValue:[dockMgrView currentDockIndex]+1];
	[gotoField selectText:self];
	[dockMgrView windowDidResignKey:self];
	modalCanceled = NO;
	[NXApp runModalFor:gotoPanel];
	if (!modalCanceled)   {
		[dockMgrView gotoDockLevel:[gotoField intValue]-1];
		[dockMgrView display];
	}
	return self;
}

- moveLevel:sender
{
	[moveField setIntValue:[dockMgrView currentDockIndex]+1];
	[moveField selectText:self];
	[dockMgrView windowDidResignKey:self];
	modalCanceled = NO;
	[NXApp runModalFor:movePanel];
	if (!modalCanceled)  {
		[dockMgrView moveLevelTo:[moveField intValue]-1];
		[dockMgrView display];
	}
	return self;
}

- sendLevelToBottom:sender
{
	[(DockMgrView *)dockMgrView sendCurrentToBottom];
	[dockMgrView display];
	return self;
}

- bringLevelToTop:sender
{
	[(DockMgrView *)dockMgrView bringCurrentToTop];
	[dockMgrView display];
	return self;
}

- findNamedIcon:sender
{
	[findIconStringField selectText:self];
	[dockMgrView windowDidResignKey:self];
	modalCanceled = NO;
	[NXApp runModalFor:findIconPanel];
	if (!modalCanceled)  {
		[dockMgrView findLevelContaining:[findIconStringField stringValue] switch:YES];
		[dockMgrView display];
	}
	return self;
}

- inspectIcon:sender
{
	[dockMgrView inspectIcon:self];
	return self;
}

- addLevel:sender
{
	[dockMgrView addLevel];
	[dockMgrView display];
	return self;
}

- deleteLevel:sender
{
	[dockMgrView deleteLevel];
	[dockMgrView display];
	return self;
}

- modalDone:sender
{
	[[sender window] orderOut:self];
	[NXApp stopModal];
	if ([sender tag] == 0)
		modalCanceled = YES;
	return self;
}

- windowWillClose:sender
{
	if (sender == infoPanel) infoPanel = nil;
	if (sender == prefPanel) prefPanel = nil;
    return self;
}


- setShelfImage:sender
{
	id	openPanel = [OpenPanel new];
	const char * const *types = [NXImage imageFileTypes];

	if (![openPanel runModalForDirectory:"." file:"" types:types])
		return nil;
	[imageFileField setStringValue:[openPanel filename]];
	[imageFileField selectText:self];
	[self activatePrefButtons:self];
	return self;
}

- snapShelfToGrid:sender
{
	if ([shelfView hasSelectedCells])
		[shelfView alignSubviews];
	return self;
}

- selectShelf:sender
{
	NXRect		frame;

	[shelfView getFrame:&frame];
	NXInsetRect(&frame, -1000.0, -1000.0);
	[shelfView selectViewsInRect:&frame deselect:YES];
	[self updateMenus];
	return self;
}

- selectDock:sender
{
	[[dockMgrView currentDock] select:YES all:self];
	if (![dockMgrView showDock])
		[dockMgrView setShowDock:YES];
	[self updateMenus];
	return self;
}

- (NXZone *)dockZone
{
	return [dockMgrView zone];
}

- (NXZone *)shelfZone
{
	return [shelfView zone];
}

- deselectShelf
{
	[shelfView deselectAll:self];
	return self;
}

- deselectDock
{
	[dockMgrView deselectAll:self];
	return self;
}

- addWorkspaceToDock:sender
{
	[dockMgrView addWorkspace];
	return self;
}

- addRecyclerToDock:sender
{
	[dockMgrView addRecycler];
	return self;
}

- validRequestorForSendType:(NXAtom)typeSent andReturnType:(NXAtom)typeReturned
{
    if ((typeSent == NXFilenamePboardType || typeSent == NULL) && (typeReturned == NULL))	{
		if (typeSent == NULL || [shelfView hasSelectedCells] || [dockMgrView hasSelectedCells])
			return self;
	}
	else if ((typeReturned == NXFilenamePboardType) || (typeReturned == NXAsciiPboardType))
		return self;
    return nil;
}

- submitToFiendDock:(id)pb userData:(const char *)data error:(char **)msg
{
	[dockMgrView paste:self toPasteboard:pb];
	return self;
}

- submitToFiendShelf:(id)pb userData:(const char *)data error:(char **)msg
{
	BOOL	shelfEnabled = !strcmp(NXGetDefaultValue([NXApp appName], ENAB_SHELF), "YES");

	if (shelfEnabled)
		return [shelfView paste:self toPasteboard:pb];
	else	{
		NXRunAlertPanel([NXApp appName], "Fiend Shelf is not enabled!!", NULL, NULL, NULL);
		return nil;
	}
	return self;
}

- (BOOL)writeSelectionToPasteboard:pb types:(NXAtom *)types
{
	BOOL	shelfEnabled = !strcmp(NXGetDefaultValue([NXApp appName], ENAB_SHELF), "YES");

	if (shelfEnabled && [shelfView hasSelectedCells])	{
		[shelfView copy:self toPasteboard:pb andCut:NO];
		[shelfView deselectAll:self];
	}
	else if ([dockMgrView hasSelectedCells])	{
		[dockMgrView copy:self toPasteboard:pb andCut:NO];
		[dockMgrView deselectAll:self];
	}
	else	{
		NXBeep();
		return NO;
	}
	return YES;
}

- copy:sender
{
	id		pb = [Pasteboard new];
	BOOL	shelfEnabled = !strcmp(NXGetDefaultValue([NXApp appName], ENAB_SHELF), "YES");

	if (shelfEnabled && [shelfView hasSelectedCells])
		[shelfView copy:self toPasteboard:pb andCut:NO];
	else if ([dockMgrView hasSelectedCells])
		[dockMgrView copy:self toPasteboard:pb andCut:NO];
	else	{
		NXBeep();
		return nil;
	}
	return self;
}


- cut:sender
{
	id		pb = [Pasteboard new];
	BOOL	shelfEnabled = !strcmp(NXGetDefaultValue([NXApp appName], ENAB_SHELF), "YES");

	if (shelfEnabled && [shelfView hasSelectedCells])
		[shelfView copy:self toPasteboard:pb andCut:YES];
	else if ([dockMgrView hasSelectedCells])
		[dockMgrView copy:self toPasteboard:pb andCut:YES];
	else
		NXBeep();
	return self;
}

- pasteToShelf:sender
{
	int		status;
	char 	*showSelPanel = (char *)NXGetDefaultValue([NXApp appName], SHOW_SELPNL);
	BOOL	shelfEnabled = !strcmp(NXGetDefaultValue([NXApp appName], ENAB_SHELF), "YES");

	if (!shelfEnabled)	{
		NXRunAlertPanel([NXApp appName], "Fiend Shelf is not enabled!!", NULL, NULL, NULL);
		return nil;
	}

	if (!strcmp(showSelPanel, "YES"))	{
		status = NXRunAlertPanel([NXApp appName],
								 "Click mouse to choose paste site...",
								 "Ok", "Ok Forever", NULL);
		if (status == NX_ALERTALTERNATE)
			NXWriteDefault([NXApp appName], SHOW_SELPNL, "NO");
	}

	[shelfView deselectAll:self];
	[dockMgrView deselectAll:self];
	[shelfView paste:self];

	return self;
}

- pasteToDock:sender
{
	[shelfView deselectAll:self];
	[dockMgrView deselectAll:self];
	[dockMgrView paste:self];

	return self;
}

- doSuggestion:sender
{
	id		to = [MiscString newWithString:EMAIL_ADDRESS];
	id		subj = [[MiscString alloc] init];
	id		body = [[MiscString alloc] init];
	id		mailer = [MiscMailApp localMailer];
	struct passwd *pwdStruct = getpwuid(getuid());

	[body setFromFormat:"Hi Dave!\n\nGreat work on Fiend v%s - but I have to tell you...\n\n\n\n\n- %s\n",
		                    FIEND_VERSION, pwdStruct->pw_gecos];
	[subj setFromFormat:"Suggestion/Bug Report for Fiend v%s", FIEND_VERSION];
	[mailer sendMailTo:to subject:subj body:body];

	[to free];
	[body free];
	[subj free];
	
	return self;
} 

- (const char *)appDirectory
{
	return [thinker appDirectory];
}

- commonImageInspector
{
	return [thinker commonImageInspector];
}

- (struct mach_header *) headerForModule:(const char *)name
{
	return [thinker headerForModule:name];
}

- (const char *)moduleDirectory:(const char *)name
{
	return [thinker moduleDirectory:name];
}

- (NXDragOperation) draggingSourceOperationMaskForLocal:(BOOL)flag
{
    return NX_DragOperationAll;
}

@end
