
/* Generated by Interface Builder */

#import <appkit/appkit.h>
#import <libc.h>
#import <objc/HashTable.h>
#import <objc/List.h>
#import "StateManager.h"
#import "Filter.h"
#import "Script.h"
#import "FilterInspector.h"
#import "ScriptInspector.h"
#import "HelpManager.h"
#import "support.h"

@implementation StateManager

const char *APPNAME = "SystemWorks";

- enableCellList: aCellList
{
	[aCellList makeObjectsPerform: @selector(setEnabled:) with: YES];
}

- disableCellList: aCellList
{
	[aCellList makeObjectsPerform: @selector(setEnabled:) with: NO];
}

- appDidInit: sender	// I'm not sure whether Distributor gets `new' message or not.
{
	static NXDefaultsVector myDefaults = { 
		{"Autosize", "1"},
		{"NoviceUser", "0"},
		{"PATH",
		"/usr/local/bin:/usr/ucb:/bin:/usr/bin:~/Apps:/LocalApps:/NextApps:/NextDeveloper/Demos"},
		{"FilterOpenPath", "~/lib/filt"},
		{"ScriptOpenPath", "~/lib/works"},
		{"SettingOpenPath", "~/lib/set"},
		{"IconOpenPath", "~/lib/icon"},
		{NULL}
	};
	const char *s;

	NXRegisterDefaults(APPNAME, myDefaults);
	s = NXGetDefaultValue(APPNAME, "Autosize");
	[autosizeToggle selectCellWithTag: *s - '0'];
	s = NXGetDefaultValue(APPNAME, "NoviceUser");
	[noviceUserToggle selectCellWithTag: *s - '0'];
	[pathForm setStringValue: NXGetDefaultValue(APPNAME, "PATH") at: 0];
	[dataDirectory setStringValue: NXGetDefaultValue(APPNAME, "FilterOpenPath") at: 0];
	[dataDirectory setStringValue: NXGetDefaultValue(APPNAME, "ScriptOpenPath") at: 1];
	[dataDirectory setStringValue: NXGetDefaultValue(APPNAME, "SettingOpenPath") at: 2];
	[dataDirectory setStringValue: NXGetDefaultValue(APPNAME, "IconOpenPath") at: 3];

	scriptTable = [[HashTable alloc] initKeyDesc: "i" valueDesc: "@"];
	processTable = [[HashTable alloc] initKeyDesc: "i" valueDesc: "@"];

	setNotifyTarget(self);
	[self disableCellList: nilFilterList];
	[self disableCellList: nilScriptList];

	[helpManager appDidInit: self];
	[filterInspector appDidInit: self];
	[scriptInspector appDidInit: self];

	[self setup];
	return self;
}

- createFilter: sender
{
	id newFilter;
	newFilter = [[Filter alloc] init];
	[newFilter setStateManager: self];
	[[activeScript addFilter: newFilter] update];
	[scriptInspector modified];
	return newFilter;
}

- removeFilter: sender
{
	activeFilter = nil;
	[self disableCellList: nilFilterList];
	[activeScript removeFilter];
	[activeScript update];
	[scriptInspector modified];
	return self;
}

- saveFilter: sender
{
	NXTypedStream *ts;
	if ([activeFilter pathname] == NULL)  {
			[self saveFilterAs: self];
	} else {
		ts = NXOpenTypedStreamForFile([activeFilter pathname], NX_WRITEONLY);
		if (ts == NULL)
			return nil;
		// [activeFilter write: ts];
		NXWriteObject(ts, activeFilter);
		NXCloseTypedStream(ts);
	}
}

- saveFilterAs: sender
{
	NXTypedStream *ts;
	static id savePanel = nil;
	int status;

	if (!savePanel) {
		savePanel = [SavePanel new];
	}
	[[[savePanel contentView] findViewWithTag: NX_OPTITLEFIELD]
								setStringValue: "Save Filter"];
	[savePanel setRequiredFileType: "filt"];
	[savePanel setDirectory: NXGetDefaultValue(APPNAME, "FilterOpenPath")];
	if ([activeFilter pathname] == NULL) {
		status = [savePanel runModalForDirectory: [savePanel directory] file: "Untitled"];
	} else {
		status = [savePanel runModal];
	}
	if (status)  {
		ts = NXOpenTypedStreamForFile([savePanel filename], NX_WRITEONLY);
		if (ts == NULL)
			return nil;
		[activeFilter setPathname: [savePanel filename]];
		// [activeFilter write: ts];
		NXWriteObject(ts, activeFilter);
		NXCloseTypedStream(ts);
	}
}

- readFilterFromFile: (const char *) filename
{
	NXTypedStream *ts;
	id newFilter;

  NX_DURING
	ts = NXOpenTypedStreamForFile(filename, NX_READONLY);
	if (ts == NULL)
		NX_VALRETURN(nil);
	//
	newFilter = NXReadObject(ts);
	[[activeScript addFilter: newFilter] update];
	[newFilter update];
  NX_HANDLER
	printf("readFilterFromFile@stateManager: stream error\n");
 	NXCloseTypedStream(ts);
	return nil;
  NX_ENDHANDLER
	NXCloseTypedStream(ts);
	return self;
}

- openFilter: sender
{
	static id openPanel = nil;
	static char *fileType[] = { "filt", NULL};

	if (!openPanel) {
		openPanel = [OpenPanel new];
		[openPanel orderFront: self];
	}
	[[[openPanel contentView] findViewWithTag: NX_OPTITLEFIELD]
								setStringValue: "Open Filter"];
	[openPanel setDirectory: NXGetDefaultValue(APPNAME, "FilterOpenPath")];
	if ([openPanel runModalForTypes: fileType ])  {
		return [self readFilterFromFile: [openPanel filename]];
	}
	return self;
}

- addScript: newScript
{
	unsigned int wn;
	wn = [newScript globalWindowNum];
	[scriptTable insertKey: (const void *) wn value: (void *) newScript];
	return newScript;
}

- miniaturized: aScript
{
	unsigned int wn;
	[scriptTable removeKey: (const void *) [aScript globalWindowNum]];
	wn = [aScript globalMiniwindowNum];
	[scriptTable insertKey: (const void *) wn value: (void *) aScript];
	return self;
}

- deminiaturized: aScript
{
	unsigned int wn;
	[scriptTable removeKey: (const void *) [aScript globalMiniwindowNum]];
	wn = [aScript globalWindowNum];
	[scriptTable insertKey: (const void *) wn value: (void *) aScript];
	return self;
}

- createScript: sender
{
	id newScript;

	newScript = [[Script alloc] init];
	[newScript setStateManager: self];
	[[newScript createWindow] update];
	[self addScript: newScript];
	[[newScript window] makeKeyAndOrderFront: self];
}

- removeScript: aScript
{
	[scriptTable removeKey: (const void *) [aScript globalWindowNum]];
	[scriptTable removeKey: (const void *) [aScript globalMiniwindowNum]];
	if ([scriptTable count] == 0) {
		activeScript = activeFilter = nil;
		[self disableCellList: nilFilterList];
		[self disableCellList: nilScriptList];
	}
}

- saveScript: sender
{
	NXTypedStream *ts;
	if ([activeScript pathname] == NULL)  {
			[self saveScriptAs: self];
	} else {
		ts = NXOpenTypedStreamForFile([activeScript pathname], NX_WRITEONLY);
		if (ts == NULL)
			return nil;
		//
		// [activeScript write: ts];
		NXWriteObject(ts, activeScript);
		NXCloseTypedStream(ts);
		[scriptInspector saved];
	}
}

- saveScriptAs: sender
{
	NXTypedStream *ts;
	static id savePanel = nil;
	int status;

	if (!savePanel) {
		savePanel = [SavePanel new];
	}
	[[[savePanel contentView] findViewWithTag: NX_OPTITLEFIELD]
								setStringValue: "Save Script"];
	[savePanel setRequiredFileType: "works"];
	[savePanel setDirectory: NXGetDefaultValue(APPNAME, "ScriptOpenPath")];
	if ([activeScript pathname] == NULL) {
		status = [savePanel runModalForDirectory: [savePanel directory] file: "Untitled"];
	} else {
		status = [savePanel runModal];
	}
	if (status)  {
		ts = NXOpenTypedStreamForFile([savePanel filename], NX_WRITEONLY);
		if (ts == NULL)
			return nil;
		//
		[activeScript setPathname: [savePanel filename]];
		// [activeScript write: ts];
		NXWriteObject(ts, activeScript);
		NXCloseTypedStream(ts);
	}
	[scriptInspector saved];
}

- readScriptFromFile: (const char *) filename
{
	NXTypedStream *ts;
	id newScript;

  NX_DURING
	ts = NXOpenTypedStreamForFile(filename, NX_READONLY);
	if (ts == NULL)
		NX_VALRETURN(nil);
	//
	newScript = NXReadObject(ts);
	[newScript setStateManager: self];
	[[[newScript createWindow] addFilters] update];
	[self addScript: newScript];
	[newScript setPathname: filename];
	[[newScript window] makeKeyAndOrderFront: self];
  NX_HANDLER
	printf("readScriptFromFile@stateManager: stream error\n");
	NXCloseTypedStream(ts);
	return nil;
  NX_ENDHANDLER
	NXCloseTypedStream(ts);
	return self;
}

- openScript: sender
{
	static id openPanel = nil;
	static char *fileType[] = { "works", NULL};

	if (!openPanel) {
		openPanel = [OpenPanel new];
		[openPanel orderFront: self];
	}
	[[[openPanel contentView] findViewWithTag: NX_OPTITLEFIELD]
								setStringValue: "Open Script"];
	[openPanel setDirectory: NXGetDefaultValue(APPNAME, "ScriptOpenPath")];
	if ([openPanel runModalForTypes:  fileType])  {
		return [self readScriptFromFile: [openPanel filename]];
	}
	return nil;
}

- (int)openFile:(const char *)fullPath ok:(int *)flag
{
	char *suffix;

	*flag = NO;
	suffix = strrchr(fullPath, '.');
	if (strcmp(suffix, ".works") == 0) {
		if ([self readScriptFromFile: fullPath])
			*flag = YES;
	}else if (strcmp(suffix, ".filt") == 0) {
		if (activeScript  &&  [self readFilterFromFile: fullPath])
			*flag = YES;
	}
	return 0;
}

- saveScriptsToFile: (char *) filename
{
	NXTypedStream *ts;
	unsigned int wn;
	id script;
	NXRect aFrame;
	NXHashState state = [scriptTable initState];
	
	ts = NXOpenTypedStreamForFile(filename, NX_WRITEONLY);
	if (ts == NULL) {
		NXRunAlertPanel(NULL, "Cannot write file: %s", "OK", NULL, NULL, filename);
		return nil;
	}
	while ([scriptTable nextState: &state key: (void **) &wn value: (void **) &script])  {
		[[script window] getFrame: &aFrame];
		NXWriteRect(ts, &aFrame);
		// [script write: ts];
		NXWriteObject(ts, script);
	}
	NXCloseTypedStream(ts);
	return self;
}

- saveSetting: sender
{
	char filename[256];
	strcpy(filename, NXHomeDirectory());
	strcat(filename, "/.systemWorks");
	[self saveScriptsToFile: filename];
	return self;
}

- saveSettingAs: sender
{
	static id savePanel = nil;
	int status;

	if (!savePanel) {
		savePanel = [SavePanel new];
	}
	[[[savePanel contentView] findViewWithTag: NX_OPTITLEFIELD]
								setStringValue: "Save Setting"];
	[savePanel setRequiredFileType: "set"];
	[savePanel setDirectory: NXGetDefaultValue(APPNAME, "SettingOpenPath")];
	status = [savePanel runModalForDirectory: [savePanel directory] file: "Untitled"];
	if (status)  {
		[self saveScriptsToFile: [savePanel filename]];
	}
	return self;
}

- readSettingFromFile: (char *) filename
{
	NXTypedStream *ts;
	id newScript;
	NXRect aFrame;

  NX_DURING
	ts = NXOpenTypedStreamForFile(filename, NX_READONLY);
	if (ts == NULL)
		NX_VALRETURN(nil);
	while (!NXEndOfTypedStream(ts)) {
		NXReadRect(ts, &aFrame);
		newScript = NXReadObject(ts);
		[newScript setStateManager: self];
		[[[newScript createWindow] addFilters] update];
		[self addScript: newScript];		
		[[newScript window] placeWindow: &aFrame];
		[[[newScript update] window] orderFront: self];
	}
  NX_HANDLER
	printf("readSettingFromFile@stateManager: stream error\n");
	NXCloseTypedStream(ts);
	return self;
  NX_ENDHANDLER
	NXCloseTypedStream(ts);
	return self;
}

- openSetting: sender
{
	static id openPanel = nil;
	static char *fileType[] = { "set", NULL};

	if (!openPanel) {
		openPanel = [OpenPanel new];
		[openPanel orderFront: self];
	}
	[[[openPanel contentView] findViewWithTag: NX_OPTITLEFIELD]
								setStringValue: "Open Setting"];
	[openPanel setDirectory: NXGetDefaultValue(APPNAME, "SettingOpenPath")];
	if ([openPanel runModalForTypes: fileType])  {
		return [self readSettingFromFile: [openPanel filename]];
	}
	return nil;
}

- setup
{
	char filename[256];
	strcpy(filename, NXHomeDirectory());
	strcat(filename, "/.systemWorks");
	[self readSettingFromFile: filename];
	return self;
}

- openIconDirectory: sender
{
	NXTypedStream *ts;
	static id openPanel = nil;
	char iconDir[256], *filename;

	strcpy(iconDir, NXGetDefaultValue(APPNAME, "IconOpenPath"));
	tilde_expand(iconDir);
	if (!openPanel) {
		openPanel = [OpenPanel new];
		[openPanel orderFront: self];
	}
	[[[openPanel contentView] findViewWithTag: NX_OPTITLEFIELD]
								setStringValue: "Open Icon"];
	[openPanel setDirectory: iconDir];
	if ([openPanel runModal])  {
		filename = [openPanel filename];
		if (strncmp(iconDir, filename, strlen(iconDir)) == 0)
			[resultIconPathForm setStringValue: filename + strlen(iconDir)+1 at: 0];
		else
			[resultIconPathForm setStringValue: filename at: 0];
	}
	return self;
}

static int cellcmp(const void *first, const void *second)
{
    const char *s1 = [*((id *)first) title];
    const char *s2 = [*((id *)second) title];
    return (s1 && s2) ? strcmp(s1, s2) : 0;
}

- addToActivate: sender
{
	id cells;
	cells = [[activateMenu itemList] cellList];
	[[activateMenu addItem: [sender scriptName]  action:@selector(activate:)  keyEquivalent:0]
		setTarget: sender];
	if (cells) {
		qsort(NX_ADDRESS(cells), [cells count], sizeof(id *), cellcmp);
		[activateMenu sizeToFit];
	}
	return self;
}

- removeFromActivate: sender
{
	int i, count;
	const char *s;
	char *name;
	id matrix, cells;

	matrix = [activateMenu itemList];
	cells = [matrix cellList];
	count = [cells count];
	name = [sender scriptName];
	for (i = 0; i < count; i++) {
		s = [[cells objectAt:i] title];
		if (s && !strcmp(s, name)) {
			[matrix removeRowAt:i andFree:YES];
			break;
		}
	}
	if (i != count) {
		qsort(NX_ADDRESS(cells), [cells count], sizeof(id *), cellcmp);
		[activateMenu sizeToFit];
	}
	return self;
}

- registerProcess: anObject id: (int) pid
{
	[processTable insertKey: (const void *) pid value: (void *) anObject];
	return self;
}

- processTerminated: (int) pid status: (union wait *) status
{
	id anObject;
	anObject = (id) [processTable valueForKey: (void *) pid];
	[processTable removeKey: (void *) pid];
	[anObject childTerminated: pid status: status];
}

- backgroundRead: (int) pid status: (union wait *) status
{
	id anObject;
	anObject = (id) [processTable valueForKey: (void *) pid];
	[anObject childTerminated: pid status: status];
}

- setActiveFilter: aFilter
{
	activeFilter = aFilter;
	if (!activeFilter)  {
		[self disableCellList: nilFilterList];
	} else {
		[self enableCellList: nilFilterList];
		[filterInspector activeChanged];
	}
	return self;
}

- setActiveScript: aScript
{
	activeScript = aScript;
	[self enableCellList: nilScriptList];
	[scriptInspector activeChanged];
	[helpManager activeChanged];
}

- filterInspector
{
	return filterInspector;
}
- scriptInspector
{
	return scriptInspector;
}
- activeFilter
{
	return activeFilter;
}
- activeScript
{
	return activeScript;
}
- (int) autosize
{
	return [[autosizeToggle selectedCell] tag];
}
- (int) novice
{
	return [[noviceUserToggle selectedCell] tag];
}

- preferenceOK: sender
{
	static char s[2] = "1";
	*s = [[autosizeToggle selectedCell] tag] + '0';
	NXWriteDefault(APPNAME, "Autosize", s);
	*s = [[noviceUserToggle selectedCell] tag] + '0';
	NXWriteDefault(APPNAME, "NoviceUser", s);
	NXWriteDefault(APPNAME, "PATH", [pathForm stringValueAt: 0]);
// export $PATH

	NXWriteDefault(APPNAME, "FilterOpenPath", [dataDirectory stringValueAt: 0]);
	NXWriteDefault(APPNAME, "ScriptOpenPath", [dataDirectory stringValueAt: 1]);
	NXWriteDefault(APPNAME, "SettingOpenPath", [dataDirectory stringValueAt: 2]);
	NXWriteDefault(APPNAME, "IconOpenPath", [dataDirectory stringValueAt: 3]);
}

- (int)iconEntered:(int)windowNum at:(double)x :(double)y
    iconWindow:(int)iconWindowNum 
    iconX:(double)iconX iconY:(double)iconY
    iconWidth:(double)iconWidth 
    iconHeight:(double)iconHeight
    pathList:(char *)pathList
{
	id target;
	int r;

	target = (id)[scriptTable valueForKey: (void *) windowNum];
	currentTarget = target;
	r = [currentTarget iconEntered: windowNum at: x : y
		    iconWindow: iconWindowNum 
		    iconX: iconX iconY: iconY
		    iconWidth: iconWidth 
		    iconHeight: iconHeight
		    pathList: pathList];
	return r;
}

- (int)iconReleasedAt:(double)x :(double)y ok:(int *)flag
{
	int r;
	r = [currentTarget iconReleasedAt: x : y ok: flag];
	return r;
}

// glues
- setFilterInspector: anObject		{filterInspector = anObject; }
- setScriptInspector: anObject		{scriptInspector = anObject; }
- setHelpManager: anObject			{helpManager = anObject; }
// script inspector
- setResultIconPathForm: anObject	{resultIconPathForm = anObject; }
// preference
- setAutosizeToggle: anObject		{autosizeToggle = anObject; }
- setNoviceUserToggle: anObject;	{noviceUserToggle = anObject; }
- setPathForm: anObject;			{pathForm = anObject; }
- setDataDirectory: anObject			{dataDirectory = anObject; }

- setActivateMenuCell: aMenuCell
{
	activateMenu = [aMenuCell target];
}

- addToNoviceList: anObject
{
	if (!noviceList)
		noviceList = [[List alloc] init];
	[noviceList addObject: anObject];
}
- addToNilScriptList: anObject
{
	if (!nilScriptList)
		nilScriptList = [[List alloc] init];
	[nilScriptList addObject: anObject];
}
- addToNilFilterList: anObject
{
	if (!nilFilterList)
		nilFilterList = [[List alloc] init];
	[nilFilterList addObject: anObject];
}

- setScriptNewMenuCell: anObject
	{ [self addToNoviceList: anObject]; }
- setScriptInspectorMenuCell: anObject
	{ [self addToNoviceList: anObject]; }
- setScriptSaveMenuCell: anObject
	{ [self addToNilScriptList: anObject]; }
- setScriptSaveAsMenuCell: anObject
	{ [self addToNilScriptList: anObject]; }
- setScriptHelpMenuCell: anObject
	{ [self addToNilScriptList: anObject]; }

- setFilterCloseMenuCell: anObject
	{ [self addToNoviceList: anObject]; [self addToNilFilterList: anObject]; }
- setFilterOpenMenuCell: anObject
	{ [self addToNoviceList: anObject]; [self addToNilScriptList: anObject]; }
- setFilterNewMenuCell: anObject
	{ [self addToNoviceList: anObject]; [self addToNilScriptList: anObject]; }
- setFilterSaveMenuCell: anObject
	{ [self addToNoviceList: anObject]; [self addToNilFilterList: anObject]; }
- setFilterSaveAsMenuCell: anObject
	{ [self addToNoviceList: anObject]; [self addToNilFilterList: anObject]; }
- setFilterInspectorMenuCell: anObject
	{ [self addToNoviceList: anObject]; }


- setFilterOKButton: anObject
	{ [self addToNilFilterList: anObject]; }
- setScriptOKButton: anObject
	{ [self addToNilScriptList: anObject]; }
@end
