
/*
	Copyright 1993  Jeremy Slade.

	You are free to use all or any parts of the Locus project
	however you wish, just give credit where credit is due.
	The author (Jeremy Slade) shall not be held responsible
	for any damages that result out of use or misuse of any
	part of this project.

*/

/*
	Project: Locus

	File: MainController.m

	Description: See MainController.h

	Original Author: Jeremy Slade

	Revision History:
		Created
			V.101	JGS Tue Feb  2 18:05:03 GMT-0700 1993

*/


#import "MainController.h"

#import "Activator.h"
#import "AtomList.h"
#import "Folder.h"
#import "FolderController.h"
#import "FolderViewer.h"
#import "Globals.h"
#import "Group.h"
#import "InfoPanel.h"
#import "Inspector.h"
#import "Preferences.h"
#import "PSWraps.h"

#import <dpsclient/dpsclient.h>
#import <dpsclient/wraps.h>
#import <libc.h>
#import <objc/List.h>
#import <objc/NXStringTable.h>
#import <stdio.h>
#import <stdlib.h>
#import <string.h>


// Flag set by -barHit:
BOOL viewersBuried = NO;

// Flag used when app is initially launched
BOOL stillLaunching = NO;

// Flag set by -appDidBecomeActive:
BOOL stillActivating = NO;



@implementation MainController : Object


+ initialize
/*
	Set the class version number
	Initialize the defaults
*/
{
	[self setVersion:MainController_VERSION];
	
	PSInitWraps(); // Initialize custom PostScript code
	
	NXRegisterDefaults ( [NXApp appName], Defaults );
	NXUpdateDefaults();
	
	return ( self );
}



- init
{
	[super init];
	mainController = self;
	return ( self );
}



- free
{
	// Should free its instance variables, but it only gets freed when
	// the app terminates, so I didn't worry about it

	return ( [super free] );
}



// -------------------------------------------------------------------------
//   Application Delegate Methods
// -------------------------------------------------------------------------


- appWillInit:sender
{
	// Initialize global variables
	// initGlobals should'nt be called until this point, after Main.nib
	// has been loaded
	mainController = self;
	folderController = theFolderController;
	initGlobals();
	
	// Read the preferences
	[self readPrefs:self];
	
	stillLaunching = YES;
	return ( self );
}



- appDidInit:sender
{
	[folderController setup];
	[self showActivator:self];

	// Do AutolLaunch stuff if NXAutoLaunch = YES
	if ( isAutoLaunch ) {
		if ( autolaunchHide ) {
			[NXApp hide:self];
			[folderController perform:@selector(inactive:)
				with:self afterDelay:1 cancelPrevious:YES];
		} else
			[NXApp activateSelf:YES];
	}
	
	stillLaunching = NO; // All done with initial setup
	return ( self );
}


	
- appWillTerminate:sender
{
	if ( ![folderController cleanup] ) return ( nil );
		else return ( self );
}



- appDidResignActive:sender
{
	[folderController inactive:self];
	return ( self );
}



- appDidBecomeActive:sender
{
	int i, count;
	id windowList;
	
	// Move all Folder viewer to front of the screenlist.
	// They could be at the back of the screen if they were 'buried'
	if ( viewersBuried ) {
		windowList = [NXApp windowList];
		count = [windowList count];
		for ( i=0; i<count; i++ )
			if ( [[windowList objectAt:i] class] == [FolderViewer class] )
				[[windowList objectAt:i] orderFront:self];
		viewersBuried = NO;
	}
	
	if ( !stillLaunching ) {
		stillActivating = YES;
		[self perform:@selector(doneActivating:)
			with:self
			afterDelay:1
			cancelPrevious:NO];
	}
	
	[folderController active:sender];
	return ( self );
}



- appDidHide:sender
/*
	Called immed. after the app is hidden.   Make sure the Activator stays visible.
*/
{
	[self showActivator:self];
	return ( self );
}



- (int)app:sender openFile:(const char *)filename type:(const char *)aType
/*
	Responds to requests from NXApp to open a Folder specified by filename
*/
{
	if ( strcmp ( aType, FOLDER_EXT ) )
		return ( NO ); // Invalid file type

	// Filename is a folder -- open it if not already open; if it is open,
	// make it the key folder
	if ( [folderController folderLoaded:filename] ) {
		[folderController makeKeyFolder:[folderController folderWithFilename:filename]];
		return ( YES );
	}
	
	if ( [folderController openFolder:filename] ) {
		[folderController active:self];
		return ( YES );
	}
		
	return ( NO );
}



- (BOOL)appAcceptsAnotherFile:sender
{
	return ( YES ); // Should always be able to open another folder
}
		


- powerOff:(NXEvent *)theEvent
{
	[folderController saveAllFolders:self];
	[self appWillTerminate:self];
	return ( self );
}



- app:sender powerOffIn:(int)ms andSave:(BOOL)aFlag
{
	[folderController saveAllFolders:self];
	[self appWillTerminate:self];
	return ( self );
}




// -------------------------------------------------------------------------
//   Info panel
// -------------------------------------------------------------------------


- showInfoPanel:sender
{
	// Load nib section if not already done
	if ( !infoPanel ) {
		[NXApp loadNibSection:"Info.nib"
			owner:self
			withNames:NO];
		[infoPanel setDelegate:self];
	}
	
	[infoPanel runInfoPanel:self];	
	return ( self );
}



// -------------------------------------------------------------------------
//   Preferences
// -------------------------------------------------------------------------


- showPrefsPanel:sender
{
	// Create the Prefs panel if necessary
	if ( !preferences ) {
		preferences = [[Preferences alloc] init];
	}
			
	[[[preferences displayPrefs] panel] makeKeyAndOrderFront:self];
	return ( self );
}



- readPrefs:sender
{
	char str[101];
	const char *s, *folders, *tab;
	char path[MAXPATHLEN+1];
	int mode, m;
	float red, green, blue;

	NXUpdateDefaults ();

	/*
		Read system defaults
	*/
	
	if ( (s = NXGetDefaultValue ( [NXApp appName], "NXAutoLaunch" )) ) {
		isAutoLaunch = (!strcasecmp ( s, "YES" )) ? YES : NO;
	} else
		isAutoLaunch = NO;
	
	
	/*
		Read Application defaults
	*/

	// Read 'Hide on AutoLaunch'	
	autolaunchHide = (!strcasecmp ( NXGetDefaultValue ( [NXApp appName],
		PREF_AUTOLAUNCH_HIDE ), "YES" )) ? YES : NO;
	
	// Read Activator Mask
	activatorMask = atoi ( NXGetDefaultValue ( [NXApp appName],
		PREF_ACTIVATOR_MASK ) );
	[activator setBar:activatorMask on:YES];
		
	// Read 'Floating activator'
	floatActivator = (!strcasecmp ( NXGetDefaultValue ( [NXApp appName],
		PREF_ACTIVATOR_FLOAT ), "YES" )) ? YES : NO;
	[activator setFloating:floatActivator];
	
	// Read Activator Fill Color
	strcpy ( str, NXGetDefaultValue ( [NXApp appName],
		PREF_ACTIVATOR_COLOR ) );
	sscanf ( str, "%f%f%f", &red, &green, &blue );
	activatorFillColor = NXChangeRedComponent ( activatorFillColor, red );
	activatorFillColor = NXChangeGreenComponent ( activatorFillColor, green );
	activatorFillColor = NXChangeBlueComponent ( activatorFillColor, blue );
	activatorFillColor =
			NXChangeAlphaComponent ( activatorFillColor, NX_NOALPHA );
	[activator setColor:activatorFillColor];
		
	// Read Activator Border Color
	strcpy ( str, NXGetDefaultValue ( [NXApp appName],
		PREF_ACTIVATOR_BORDER ) );
	sscanf ( str, "%f%f%f", &red, &green, &blue );
	activatorBorderColor = NXChangeRedComponent ( activatorBorderColor, red );
	activatorBorderColor =
			NXChangeGreenComponent ( activatorBorderColor, green );
	activatorBorderColor =
			NXChangeBlueComponent ( activatorBorderColor, blue );
	activatorBorderColor =
			NXChangeAlphaComponent ( activatorBorderColor, NX_NOALPHA );
	[activator setBorderColor:activatorBorderColor];

	// Read default viewer frame
	strcpy ( str, NXGetDefaultValue ( [NXApp appName], PREF_VIEWER_FRAME ) );
	sscanf ( str, "%f%f%f%f",
			&defaultViewerFrame.origin.x,
			&defaultViewerFrame.origin.y,
			&defaultViewerFrame.size.width,
			&defaultViewerFrame.size.height );
	
	// Read verifyActions
	verifyActions = (!strcasecmp ( NXGetDefaultValue ( [NXApp appName],
			PREF_VERIFY ), "YES" )) ? YES : NO;
	
	// read autoSave
	autoSave = (!strcasecmp ( NXGetDefaultValue ( [NXApp appName],
			PREF_AUTOSAVE ), "YES" )) ? YES : NO;

	// read activatorAdd
	activatorAdd = (!strcasecmp ( NXGetDefaultValue ( [NXApp appName],
			PREF_ADD_ACTIVATOR ), "YES" )) ? YES : NO;
	[activator setDraggingEnabled:activatorAdd];

	// read appIconAdd
	appIconAdd = (!strcasecmp ( NXGetDefaultValue ( [NXApp appName],
			PREF_ADD_APPICON ), "YES" )) ? YES : NO;
	[appIconView setDraggingEnabled:appIconAdd];

	// read inspectorMode
	strcpy ( str, NXGetDefaultValue ( [NXApp appName], PREF_INSPECTORMODE ) );
	mode = m = INSPECT_NONE;
	while ( inspectorTitles[m] ) {
		if ( !strcasecmp ( str, inspectorTitles[m] ) ) {
			mode = m;
			break;	// Break out of while loop
		} else m++;
	}
	if ( inspector && [inspector inspectorMode] != INSPECT_NONE )
		[inspector setInspectorMode:mode];
	else
		inspectorMode = mode;
	
	// read inspectorLocation
	strcpy ( str, NXGetDefaultValue ( [NXApp appName],
			PREF_INSPECTORLOCATION ) );
	sscanf ( str, "%f %f", &inspectorLocation.x, &inspectorLocation.y );
	
	// read hideDeactive
	hideDeactive = (!strcasecmp ( NXGetDefaultValue ( [NXApp appName],
			PREF_HIDEDEACTIVE ), "YES" )) ? YES : NO;

	// read startupFolders
	if ((folders=NXGetDefaultValue ( [NXApp appName], PREF_STARTUPFOLDERS))) {
		
		// Empty the old list of startupFolders
		if ( startupFolders ) [startupFolders free];
		
		// Create a new list
		startupFolders = [[AtomList alloc] init];

		// folders is a tab-separated list of file names
		if ( folders[0] != '\0' ) do {
			// Read the next path
			sscanf ( folders, "%[^\t]", path ); // Read until next tab

			// Add the path to startupFolders
			[startupFolders addAtom:
				NXUniqueString([folderController relativePathForFolder:path])];
			
			// Move folders to next path in list
			tab = index ( folders, '\t' ); // Find next tab
			if ( tab ) folders = tab + 1;
				else folders = NULL;
		} while ( folders ); // Read all the paths in the list
	}
	
	return ( self );
}



- writePrefs:sender
{
	char str[101];
	NXStream *stream;
	char *buf;
	int len, mlen;
	int i, count;
	float red, green, blue;

	// Write 'Hide on autoLaunch'
	NXWriteDefault ( [NXApp appName], PREF_AUTOLAUNCH_HIDE,
			autolaunchHide ? "YES" : "NO" );
	
	// Write activator bar mask
	sprintf ( str, "%d", activatorMask );
	NXWriteDefault ( [NXApp appName], PREF_ACTIVATOR_MASK, str );
	
	// Write 'Floating activation bar'
	NXWriteDefault ( [NXApp appName], PREF_ACTIVATOR_FLOAT,
			floatActivator ? "YES" : "NO" );
	
	// Write activator fill color
	NXConvertColorToRGB ( activatorFillColor, &red, &green, &blue );
	sprintf ( str, "%f %f %f", red, green, blue );
	NXWriteDefault ( [NXApp appName], PREF_ACTIVATOR_COLOR, str );

	// Write activator border color
	NXConvertColorToRGB ( activatorBorderColor, &red, &green, &blue );
	sprintf ( str, "%f %f %f", red, green, blue );
	NXWriteDefault ( [NXApp appName], PREF_ACTIVATOR_BORDER, str );

	// Write default viewer frame
	sprintf ( str, "%.0f %.0f %.0f %.0f",
			defaultViewerFrame.origin.x,
			defaultViewerFrame.origin.y,
			defaultViewerFrame.size.width,
			defaultViewerFrame.size.height );
	NXWriteDefault ( [NXApp appName], PREF_VIEWER_FRAME, str );
	
	// Write verifyActions
	NXWriteDefault ( [NXApp appName], PREF_VERIFY,
			verifyActions ? "YES" : "NO" );
	
	// Write autoSave
	NXWriteDefault ( [NXApp appName], PREF_AUTOSAVE,
			autoSave ? "YES" : "NO" );
	
	// Write hideDeactive
	NXWriteDefault ( [NXApp appName], PREF_HIDEDEACTIVE,
			hideDeactive ? "YES" : "NO" );
	
	// Write activatorAdd
	NXWriteDefault ( [NXApp appName], PREF_ADD_ACTIVATOR,
			activatorAdd ? "YES" : "NO" );
	[activator setDraggingEnabled:activatorAdd];

	// Write appIconAdd
	NXWriteDefault ( [NXApp appName], PREF_ADD_APPICON,
			appIconAdd ? "YES" : "NO" );
	
	// Write startupFolders
	if ( (stream = NXOpenMemory ( NULL, 0, NX_WRITEONLY )) ) {
		// Open a stream to buffer the paths
		// Write all the paths in startupFolders to the stream
		// as a tab-separated list (NXFilenamePboardType format)
		count = [startupFolders count];
		for ( i=0; i<count; i++ )
			if ( i ) NXPrintf ( stream, "\t%s", [startupFolders atomAt:i] );
				else NXPrintf ( stream, "%s", [startupFolders atomAt:i] );

		// Get a pointer to the buffer
		NXGetMemoryBuffer ( stream, &buf, &len, &mlen );
		
		// Write the buffer to the defaults database
		NXWriteDefault ( [NXApp appName], PREF_STARTUPFOLDERS, buf );
		
		// Close the stream and free the buffer
		NXCloseMemory ( stream, NX_FREEBUFFER );
	}

	return ( self );
}


	
// -------------------------------------------------------------------------
//   Activator
// -------------------------------------------------------------------------


- showActivator:sender
{
	[activator show:self];
	return ( self );
}



- hideActivator:sender
{
	[activator hide:self];
	return ( self );
}



- activatorHit:sender
/*
	Delegate method of the Activator, sent when it is clicked in.  If Locus is inactive, this will cause it to activate.  If it is already active, this causes Locus to deactivate.
*/
{
	int i, count;
	id windowList;
	
	[self showActivator:self];
	
	if ( !stillActivating ) { // The bar was hit when we were already active
	
		// 'Bury' viewers by moving them to the back of the screen list
		// This only needs to be done if they aren't automatically hidden
		// when the app deactivates
		if ( !hideDeactive ) {
			windowList = [NXApp windowList];
			count = [windowList count];
			for ( i=0; i<count; i++ )
				if ( [[windowList objectAt:i] class] == [FolderViewer class] )
					[[windowList objectAt:i] orderBack:self];
			viewersBuried = YES;
		}

		[NXApp deactivateSelf];
	}
				
	return ( self );
}



- activator
{
	return ( activator );
}



- doneActivating:sender
{
	// - doneActivating: is called through a delayed perform
	// immed. after the app activates... by the time it actually
	// gets called, everything should have been taken care of...
	stillActivating = NO;
	return ( self );
}



@end

