#import <math.h>
#import <appkit/appkit.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"

@implementation Controller

+ initialize
{
    static NXDefaultsVector defaults = {
        {GRID_ENABLE, "YES"},
		{SGRID_VALUE, DEFAULT_SGRID_STRING},
		{DGRID_VALUE, DEFAULT_DGRID_STRING},
		{IMAGE_NAME, DEFAULT_IMAGE_NAME},
		{USE_SOUND, "YES"},
		{SHOW_DOCK, "YES"},
		{TILE_IMAGE, "NO"},
		{CUR_DOCK, "1"},
		{SIZE_FONT, "YES"},
		{HIDE_ICONS, "YES"},
		{SHOW_SELPNL, "YES"},
		{SHOW_PROG, "YES"},
        {NULL}
    };

    NXRegisterDefaults([NXApp appName], defaults);

    return self;
}

- init
{
    infoPanel = nil;
    prefPanel = nil;

    return self;
}

- appDidInit:sender
{
    id				shelfWindow;
	id				dockWindow;
    int			  	screenCount;
    NXRect			contentRect;
    NXScreen		*screens;
	NXRect			iconRect = {{400.0, 400.0}, {64.0, 64.0}};
    id				workspace = [Application workspace];
	float			dgridValue = atof(NXGetDefaultValue([NXApp appName], DGRID_VALUE));
	BOOL			autoLaunch = !strcmp(NXGetDefaultValue([NXApp appName], "NXAutoLaunch"), "YES");
	BOOL			showProgress = !strcmp(NXGetDefaultValue([NXApp appName], SHOW_PROG), "YES");

	[NXApp getScreens:&screens count:&screenCount];

	if (showProgress)	{
		[[progressField setStringValue:PROG_BSPACE] display];
		[progressPanel center];
		[progressPanel makeKeyAndOrderFront:self];
		[progressPanel setFloatingPanel:YES];
	}
	[[NXApp delegate] setProgressViewRatio:0.0];
	[NXApp loadNibSection:"BackSpace.nib" owner:self withNames:NO];
	[thinker appDidInit:sender];
	[self setProgressViewRatio:1.0];

    shelfWindow = [[Window allocFromZone:[self zone]]
				   initContent:&screens[0].screenBounds
				   style:NX_TOKENSTYLE
				   backing:NX_BUFFERED buttonMask:0 defer:NO];

	if (showProgress)	{
		[[progressField setStringValue:PROG_SHELF] display];
		[self setProgressViewRatio:0.0];
	}
	[IconView resetProcessTable];
    [[shelfWindow contentView] getFrame:&contentRect];
    shelfView = [[ShelfView allocFromZone:[shelfWindow zone]]
				                initFrame:&contentRect];
    [[shelfWindow setContentView:shelfView] free];
    [shelfWindow setAvoidsActivation:YES];

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

	[dockWindow setAvoidsActivation:YES];
	if (dgridValue)
		[dockWindow sizeWindow:dgridValue :dgridValue];

	[dockWindow setFrameUsingName:"DockWindow"];
    [[dockWindow contentView] getFrame:&contentRect];

    PSsetwindowlevel(-2147483647, [shelfWindow windowNum]);
	[shelfWindow display];
    [shelfWindow orderBack:self];
	[self setProgressViewRatio:1.0];

	if (showProgress)	{
		[[progressField setStringValue:PROG_DOCK] display];
		[self setProgressViewRatio:0.0];
	}
	dockMgrView = [[DockMgrView allocFromZone:[dockWindow zone]]
				   initFrame:&contentRect withWindow:dockWindow];

    PSsetwindowlevel(NX_DOCKLEVEL+1, [dockWindow windowNum]);
	[dockWindow display];
	[dockWindow orderFront:self];

	[workspace beginListeningForApplicationStatusChanges];
	if (showProgress)
		[progressPanel orderOut:self];

    [NXApp preventWindowOrdering];

	if (autoLaunch)
		[NXApp hide:self];
	else
		[NXApp activateSelf:NO];

    return self;
}

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

- appDidHide:sender
{
	return [thinker appDidHide:sender];
}

- appDidUnhide:sender
{
	return [thinker appDidUnhide:sender];
}

- 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;
}

- appWillTerminate:sender
{
	char		string[10];

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

	[thinker normalMode];

	[shelfView writeShelf];
	[dockMgrView writeDocks];
	NXWriteDefault([NXApp appName], SHOW_DOCK, ([dockMgrView showDock])?"YES":"NO");

	return self;
}

- applicationDefined:(NXEvent *)e
{
	return [thinker applicationDefined:e];
}

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

    if (!*panel && [bundle getPath:path forResource:name ofType:"nib"])
		[NXApp loadNibFile:path owner:self withNames:NO fromZone:[self zone]];

    [*panel makeKeyAndOrderFront:self];

    return self;
}


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

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

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

- whirl:sender
{
	NXRect	shelfFrame;

	[shelfView getFrame:&shelfFrame];

	PSWSetDockOnTop(YES);
	PSWWhirl(NX_MIDX(&shelfFrame), NX_MIDY(&shelfFrame));
	PSWSetDockOnTop(NO);
	return self;
}

- doPreferences:sender
{
	BOOL	useSound = !strcmp(NXGetDefaultValue([NXApp appName], USE_SOUND), "YES");

    [self doPanel:&prefPanel named:"Preferences"];

	[tileSwitch setState:[shelfView tileImage]];
	[imageFileField setStringValue:[shelfView getImageFileName]];
    [shelfSizeField setIntValue:[shelfView gridValue]];
    if ([shelfView gridEnabled])
		[shelfGridSwitch setState:YES];
	[useSoundSwitch setState:useSound];
	[[dockSizeField setIntValue:[dockMgrView iconSize]] selectText:self];

    return self;
}

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

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

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

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

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

- gotoLevel:sender
{
	[gotoField setIntValue:[dockMgrView currentDockIndex]+1];
	[gotoField selectText:self];
	[NXApp runModalFor:gotoPanel];
	[dockMgrView gotoDockLevel:[gotoField intValue]-1];
	[dockMgrView display];
	return self;
}

- moveLevel:sender
{
	[moveField setIntValue:[dockMgrView currentDockIndex]+1];
	[moveField selectText:self];
	[NXApp runModalFor:movePanel];
	[dockMgrView moveLevelTo:[moveField intValue]-1];
	[dockMgrView display];
	return self;
}

- findString:sender
{
	[findStringField selectText:self];
	[NXApp runModalFor:findPanel];
	[dockMgrView findLevelContaining:[findStringField stringValue]];
	[dockMgrView display];
	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];
	return self;
}

/*
 *  Find out if a window just closed.  If it was the info panel or the pref
 *  panel, forget about its identity, since it will free itself on close.
 */
- windowWillClose:sender
{
    return self;
}


- setDoTile:sender
{
	[shelfView setTileImage:[sender state]];
	[shelfView setImageFileName:[imageFileField stringValue]];
	return self;
}

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

	if (sender == imageFileField)
		[shelfView setImageFileName:[sender stringValue]];
	else	{
		if (![openPanel runModalForDirectory:"." file:"" types:types])
			return nil;
		if ([shelfView setImageFileName:[openPanel filename]])
			[imageFileField setStringValue:[openPanel filename]];
	}
	[imageFileField selectText:self];
	return self;
}

- snapShelfToGrid:sender
{
	[shelfView alignSubviews];
	return self;
}

- enableGrid:sender
{
    unsigned int	newValue = [shelfSizeField intValue];

	if (newValue < 32 || newValue > 200)	{
		NXRunAlertPanel([NXApp appName],
						"Size must be between 32 and 200...please reenter",
						NULL, NULL, NULL);
		[[shelfSizeField setIntValue:[shelfView gridValue]] selectText:self];
		return self;
	}

    [shelfView setGridValue:newValue];
    if ([shelfView gridValue] != newValue)
		[shelfSizeField setIntValue:[shelfView gridValue]];

    [shelfView setGridEnabled:[shelfGridSwitch state]];
	if (sender == shelfSizeField)
		[shelfSizeField selectText:self];

    return self;
}

- selectShelf:sender
{
	NXRect		frame;

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

- selectDock:sender
{
	[[dockMgrView currentDock] select:YES all:self];
	return self;
}

- setDockIconSize:sender
{
	int		newValue = [sender intValue];
	char	defString[10];

	if (newValue < 32 || newValue > 200)	{
		NXRunAlertPanel([NXApp appName],
						"Size must be between 32 and 200...please reenter",
						NULL, NULL, NULL);
		[[sender setIntValue:[dockMgrView iconSize]] selectText:self];
		return self;
	}

	sprintf(defString, "%d", newValue);
	NXWriteDefault([NXApp appName], DGRID_VALUE, defString); 
	[dockMgrView setIconSize:newValue];
	[dockMgrView display];
	[sender selectText:self];
	return self;
}

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

- deselectDock
{
	[[dockMgrView currentDock] select:NO all:self];
	return self;
}

- setUseSounds:sender
{
	NXWriteDefault([NXApp appName], USE_SOUND, ([sender state])?"YES":"NO");
	return self;
}	

- copy:sender
{
	if ([shelfView hasSelectedCells])
		[shelfView copy:self andCut:NO];
	else
		[dockMgrView copy:self andCut:NO];
	return self;
}


- cut:sender
{
	if ([shelfView hasSelectedCells])
		[shelfView copy:self andCut:YES];
	else
		[dockMgrView copy:self andCut:YES];
	return self;
}

- pasteToShelf:sender
{
	int		status;
	char 	*showSelPanel = (char *)NXGetDefaultValue([NXApp appName], SHOW_SELPNL);

	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 currentDock] select:NO all:self];
	[shelfView paste:self];

	return self;
}

- pasteToDock:sender
{
	[shelfView deselectAll:self];
	[[dockMgrView currentDock] select:NO all:self];
	[dockMgrView paste:self];

	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];
}

@end


@implementation Object(BriansPathMethods)
- (void) perform:(SEL) sel withPaths:(const char *) paths
{
    const char	*scan = paths;
    char	*copy;
    char	aPath[MAXPATHLEN];

    if (!paths || !*paths)
    	return;

    do {
    	copy = aPath;

    	while (*scan && *scan != '\t')
			*copy++ = *scan++;
        *copy = '\0';

        if (*scan == '\t')
			scan++;

		[self perform:sel with:(id) aPath];

    } while (*scan);
}
@end

