//
//  DXAppController.m
//  DefEcs
//
//  Created by ttomek on 06-07-30.
//  Copyright 2006 hipercom.pl. All rights reserved.
//

#import "DXAppController.h"
#import "DXStrings.h"

static NSString* dxCross;

@implementation DXAppController

- (void) dealloc
{
	[domains release];
	[dxCross release];
	dxCross = nil;
	[super dealloc];
}

+ (void) initialize
{
	dxCross = [[NSString stringWithFormat: @"%C", 0x2718] retain];
	NSUserDefaultsController* defContr;
	defContr = [NSUserDefaultsController sharedUserDefaultsController];
	[defContr setInitialValues: [NSDictionary dictionaryWithObjectsAndKeys:
		[NSNumber numberWithInt: 0], @"DomainSearch",
		[NSNumber numberWithInt: 0], @"KeySearch",
		[NSNumber numberWithBool: NO], @"AutoSave",
		[NSNumber numberWithBool: NO], @"LookInValues",
		nil]];	
}
- (void) awakeFromNib
{
	if (newKeySheet == nil)
	{				
		[domainContentsView setDoubleAction: @selector(keyDoubleClicked:)];
		[self reloadDomains];	
		[domainListView reloadData];
		
		// load sheets from Sheets.nib
		if (![NSBundle loadNibNamed:@"Sheets" owner: self])
		{
			[[NSAlert alertWithMessageText: DXmsgErrorTitle 
							 defaultButton: DXmsgOKButton 
						   alternateButton: nil
							   otherButton: nil
				 informativeTextWithFormat: DXmsgErrorLoadingNib, @"Sheets.nib"
				] runModal];
			[NSApp terminate: self];
		}
		
		if (![NSBundle loadNibNamed: @"Preferences" owner: self])
		{
			[[NSAlert alertWithMessageText: DXmsgErrorTitle 
							 defaultButton: DXmsgOKButton 
						   alternateButton: nil
							   otherButton: nil
				 informativeTextWithFormat: DXmsgErrorLoadingNib, @"Preferences.nib"
				] runModal];
			[NSApp terminate: self];			
		}
				
		currentSheet = nil;
		currentKey = nil;
		editedKey = nil;
	}	
}

- (void) reloadDomains
{
	[domains release];
	NSUserDefaults* defaults;
	defaults = [NSUserDefaults standardUserDefaults];
	NSArray *domainNames;
	domainNames = [defaults persistentDomainNames];
	NSEnumerator *domainEnumerator;
	domainEnumerator = [domainNames objectEnumerator];
	NSString* currentDomain;
	DXDomainController* newDomain;
	domains = [ [NSMutableArray alloc] init];
	while ( currentDomain = [domainEnumerator nextObject] )
	{
		newDomain = [ [DXDomainController alloc] initWithDomain: currentDomain
												   contentsView: domainContentsView];
		[domains addObject: newDomain];
		[newDomain release];
	}
}

- (int) numberOfRowsInTableView: (NSTableView*) aTableView
{
	if (domains)
		return [domains count];
	else
		return 0;
}

- (id)				tableView: (NSTableView*)aTableView 
	objectValueForTableColumn: (NSTableColumn*) aTableColumn
						  row: (int) rowIndex
{
	NSString* columnId;
	DXDomainController *domain;
	
	domain = [domains objectAtIndex: rowIndex];
	columnId = [aTableColumn identifier];
	
	if ([columnId isEqualToString: @"modified"])
	{
		if ([domain modified])
			return dxCross;
		else
			return @"";
	}
	else if ([columnId isEqualToString: @"domainName"])
	{
		return [domain name];
	}
	else if ([columnId isEqualToString: @"keyCount"])
	{
		return [NSString stringWithFormat: @"%d", [domain count]];
	}
	else
	{
		return DXmsgInvalidDomain;
	}
}

- (BOOL) shouldQuit
{
	if (! [self modifiedDomainExists])
		return YES;
	
	NSAlert *alert;
	
	alert = [NSAlert alertWithMessageText: DXmsgQuitTitle
							defaultButton: DXmsgSaveAndQuit
						  alternateButton: DXmsgDontQuit
							  otherButton: DXmsgDontSave
				informativeTextWithFormat: DXmsgQuitMessage];
	[alert retain];
	int rc;
	rc = [alert runModal];
	
/*	[NSApp beginSheet: alert
	   modalForWindow: mainWindow 
		modalDelegate: nil 
	   didEndSelector: nil
		  contextInfo: NULL
		];
	rc = [NSApp runModalForWindow: alert];
	[NSApp endSheet: alert];
	[alert orderOut: self];*/
	[alert release];
	
	if (rc == NSAlertDefaultReturn)
	{
		// save and quit
		[self saveAllDomains: self];
		return YES;
	}
	else if (rc == NSAlertAlternateReturn)
	{
		// don't quit
		return NO;
	}
	else // don't save
		return YES;
}

- (BOOL)windowShouldClose:(id)sender
{
	return [self shouldQuit];
}

- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
	if (! [mainWindow isVisible]) // question already shown when the window was closed
		return NSTerminateNow;
	if ([self shouldQuit])
		return NSTerminateNow;
	else
		return NSTerminateCancel;
}

- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
{
	return YES;
}

- (void) windowWillClose: (NSNotification*) aNotification
{
	// synchronize the defaults
	[[NSUserDefaults standardUserDefaults] synchronize];
}

- (void) tableViewSelectionDidChange: (NSNotification *) aNotification
{
	DXDomainController* newDataSource;
	int selectedRow;
	
	if ([domainListView numberOfRows] < 1)
	{
		newDataSource = nil;
	}
	else
	{
		selectedRow = [domainListView selectedRow];
		newDataSource = [domains objectAtIndex: selectedRow];
		
	}
	[domainContentsView setDataSource: newDataSource];
	[domainContentsView reloadData];
}

- (void) setCurrentKey: (DXKey*) aKey
{
	[aKey retain];
	[currentKey release];
	currentKey = aKey;
}

- (void) setEditedKey: (DXKey*) aKey
{
	[aKey retain];
	[editedKey release];
	editedKey = aKey;
}

- (IBAction)closeApp:(id)sender
{
}

- (IBAction)deleteDomain:(id)sender
{
	if ([domains count] <= 0) return;
	NSString* domainName;
	domainName = [[self currentDomain] name];
	NSBeginAlertSheet(
					  DXmsgDeleteDomainTitle,
					  DXmsgNoButton,
					  DXmsgYesButton,
					  nil,
					  mainWindow,
					  self,
					  @selector(doRemoveDomain:returnCode:contextInfo:),
					  nil,
					  domainName,
					  DXmsgDeleteDomainMessage,
					  domainName
					  );
}

- (BOOL) modifiedDomainExists
{
	NSEnumerator* e;
	DXDomainController* d;
	e = [domains objectEnumerator];
	while (d = [e nextObject])
		if ([d modified] && ([d count] > 0))
			return YES;
	return NO;
}


- (void) doRemoveDomain: (NSWindow*) sheet
			 returnCode: (int) returnCode
			contextInfo: (void*) contextInfo
{	
	if (returnCode == NSAlertAlternateReturn)
	{
		NSString* domainName;
		DXDomainController* domain;
		DXDomainEnvelope* toDelete;
		domainName = (NSString*) contextInfo;
		domain = [self domainForName: domainName];
		toDelete = [[DXDomainEnvelope alloc] initWithDomainName: domainName
													   contents: [domain databaseRepresentation]];
		[self removeDomain: toDelete];
		[toDelete release];
	}
}

- (void) doRemoveKey: (NSWindow*) sheet
		  returnCode: (int) returnCode
		 contextInfo: (void*) contextInfo
{
	if (returnCode == NSAlertAlternateReturn)
	{
		[self removeKey: currentKey];	
	}
}

- (IBAction)deleteKey:(id)sender
{
	if ([domains count] <= 0) return;
	
	DXDomainController *currentDomain;
	currentDomain = [self currentDomain];
	if ([currentDomain count] <= 0) return;
	DXKey* keyToDelete;
	int row;
	
	row = [domainContentsView selectedRow];
	keyToDelete = [domainContentsView itemAtRow: row];
	[self setCurrentKey: keyToDelete];
	
	NSBeginAlertSheet(
					  DXmsgDeleteKeyTitle,
					  DXmsgNoButton,
					  DXmsgYesButton,
					  nil,
					  mainWindow,
					  self,
					  @selector(doRemoveKey:returnCode:contextInfo:),
					  nil,
					  nil,
					  DXmsgDeleteKeyMessage
					  );	
}

- (void) doExportToFile: (NSSavePanel*) sheet
			 returnCode: (int) returnCode
			contextInfo: (void*) contextInfo
{
	if (returnCode != NSOKButton) return;
	NSString* saveTo;
	NSString* dir;
	saveTo = [sheet filename];
	dir = [sheet directory];
	BOOL res = NO;
	
	[sheet orderOut: self];
	
	NS_DURING
		res = [NSKeyedArchiver archiveRootObject: domains
										  toFile: saveTo];
	NS_HANDLER
		res = NO;
	NS_ENDHANDLER
		
	if (! res)
	{
		NSBeginAlertSheet(
						  DXmsgSaveErrorTitle,		// title
						  DXmsgOKButton,			// default button
						  nil,						// alternate button
						  nil,						// other button
						  mainWindow,				// doc window
						  nil,						// modal delegate
						  nil,						// did end selector
						  nil,						// did dismiss selector
						  NULL,						// context info
						  DXmsgSaveErrorMessage,	// message, ...
						  dir
						  );						  		
	}
}

- (IBAction)exportToFile:(id)sender
{
	NSSavePanel* savePanel;
	savePanel = [NSSavePanel savePanel];
	[savePanel setTitle: DXmsgSavePanelTitle];
	[savePanel setPrompt: DXmsgSavePanelPrompt];
	[savePanel setNameFieldLabel: DXmsgSavePanelFieldLabel];
	[savePanel setCanSelectHiddenExtension: YES];
	[savePanel setAllowedFileTypes: [NSArray arrayWithObject: @"defdoms"]];
	[savePanel setAllowsOtherFileTypes: YES];
	[savePanel beginSheetForDirectory: nil
								 file: nil
					   modalForWindow: mainWindow
						modalDelegate: self
					   didEndSelector: @selector(doExportToFile:returnCode:contextInfo:)
						  contextInfo: nil
		];
}

- (void) doExportDomainToFile: (NSSavePanel*) sheet
				   returnCode: (int) returnCode
				  contextInfo: (void*) contextInfo
{
	if (returnCode != NSOKButton) return;
	DXDomainController* currentDomain;
	currentDomain = [self currentDomain];
	if (currentDomain == nil) return;
	NSString* fileName;
	NSString* dir;
	BOOL res = NO;
	fileName = [sheet filename];
	dir = [sheet directory];
	
	NS_DURING
		res = [NSKeyedArchiver archiveRootObject: currentDomain 
										  toFile: fileName];
	NS_HANDLER
		res = NO;		
	NS_ENDHANDLER
	
	if (! res)
	{
		NSBeginAlertSheet(
						  DXmsgSaveErrorTitle,		// title
						  DXmsgOKButton,			// default button
						  nil,						// alternate button
						  nil,						// other button
						  mainWindow,				// doc window
						  nil,						// modal delegate
						  nil,						// did end selector
						  nil,						// did dismiss selector
						  NULL,						// context info
						  DXmsgSaveErrorMessage,	// message, ...
						  dir
						  );						  		
	}
}

- (IBAction) exportDomainToFile: (id) sender
{
	NSSavePanel* savePanel;
	savePanel = [NSSavePanel savePanel];
	[savePanel setTitle: DXmsgSavePanelTitle];
	[savePanel setPrompt: DXmsgSavePanelPrompt];
	[savePanel setNameFieldLabel: DXmsgSavePanelFieldLabel];
	[savePanel setCanSelectHiddenExtension: YES];
	[savePanel setRequiredFileType: @"defdom"];
	[savePanel setAllowedFileTypes: [NSArray arrayWithObject: @"defdom"]];
	[savePanel setAllowsOtherFileTypes: YES];
	[savePanel beginSheetForDirectory: nil
								 file: nil
					   modalForWindow: mainWindow
						modalDelegate: self
					   didEndSelector: @selector(doExportDomainToFile:returnCode:contextInfo:)
						  contextInfo: nil
		];
}

- (void) doImportDomainFromFile: (NSOpenPanel*) sheet
					 returnCode: (int) returnCode
					contextInfo: (void*) contextInfo
{
	if (returnCode != NSOKButton) return;
	NSString* fileName;
	DXDomainController* newDomain = nil;
	
	fileName = [sheet filename];
	[sheet orderOut: self];
	
	NS_DURING
		newDomain = [[NSKeyedUnarchiver unarchiveObjectWithFile: fileName] retain];
		if (![newDomain isKindOfClass: [DXDomainController class]])
		{
			[newDomain release];
			newDomain = nil;
		}
	NS_HANDLER
		newDomain = nil;
	NS_ENDHANDLER

	if (newDomain == nil)
	{
		NSBeginAlertSheet(
						  DXmsgOpenErrorTitle,		// title
						  DXmsgOKButton,			// default button
						  nil,						// alternate button
						  nil,						// other button
						  mainWindow,				// doc window
						  nil,						// modal delegate
						  nil,						// did end selector
						  nil,						// did dismiss selector
						  NULL,						// context info
						  DXmsgOpenErrorMessage,	// message, ...
						  fileName
						  );
		return;
	}
	
	[newDomain setDomainContentsView: domainContentsView];
	DXDomainController* existingDomain;
	existingDomain = [self domainForName: [newDomain name]];
	int idx;
	if (existingDomain != nil)
	{
		idx = [domains indexOfObject: existingDomain];
		BOOL selected;
		selected = [[[self currentDomain] name] isEqualToString: [newDomain name]];
		if (selected)
			[domainContentsView setDataSource: nil];
		[domains replaceObjectAtIndex: idx withObject: newDomain];
		if (selected)
			[domainContentsView setDataSource: newDomain];
	}
	else
	{
		idx = [domains count];
		[domains addObject: newDomain];		
	}
	[domainListView reloadData];
	[domainListView selectRow: idx byExtendingSelection: NO];
	[domainListView scrollRowToVisible: idx];
	[[mainWindow undoManager] removeAllActions];
}

- (IBAction) importDomainFromFile: (id) sender
{
	NSOpenPanel* openPanel;
	openPanel = [NSOpenPanel openPanel];
	[openPanel setCanChooseDirectories: NO];
	[openPanel setAllowsMultipleSelection: NO];
	[openPanel setTitle: DXmsgOpenPanelTitle];
	[openPanel setPrompt: DXmsgOpenPanelPrompt];
	[openPanel setNameFieldLabel: DXmsgOpenPanelFieldLabel];
	[openPanel setCanSelectHiddenExtension: YES];
	[openPanel setRequiredFileType: @"defdom"];
	[openPanel setAllowedFileTypes: [NSArray arrayWithObject: @"defdom"]];
	[openPanel setAllowsOtherFileTypes: NO];
	[openPanel beginSheetForDirectory: nil
								 file: nil
					   modalForWindow: mainWindow
						modalDelegate: self
					   didEndSelector: @selector(doImportDomainFromFile:returnCode:contextInfo:) 
						  contextInfo: nil
		];	
}

- (void) doImportFromFile: (NSOpenPanel*) sheet
			   returnCode: (int) returnCode
			  contextInfo: (void*) contextInfo
{
	if (returnCode != NSOKButton) return;
	NSString* fileName;
	NSMutableArray* newDomains = nil;
	fileName = [sheet filename];
	
	[sheet orderOut: self];
	
	NS_DURING
		newDomains = [[NSKeyedUnarchiver unarchiveObjectWithFile: fileName] retain];
		if (![newDomains isKindOfClass:[NSArray class]])
		{
			[newDomains release];
			newDomains = nil;
		}
	NS_HANDLER
		newDomains = nil;
	NS_ENDHANDLER
		
	if (newDomains == nil)
	{
		NSBeginAlertSheet(
						  DXmsgOpenErrorTitle,		// title
						  DXmsgOKButton,			// default button
						  nil,						// alternate button
						  nil,						// other button
						  mainWindow,				// doc window
						  nil,						// modal delegate
						  nil,						// did end selector
						  nil,						// did dismiss selector
						  NULL,						// context info
						  DXmsgOpenErrorMessage,	// message, ...
						  fileName
						  );
		return;
	}
	
	[domainListView setDataSource: nil];
	[domainListView reloadData];
	[domainContentsView setDataSource: nil];
	[domainContentsView reloadData];
	
	NSEnumerator* enumerator;
	enumerator = [newDomains objectEnumerator];
	DXDomainController* d;
	while (d = [enumerator nextObject])
		[d setDomainContentsView: domainContentsView];
	[domains release];
	domains = newDomains;
	[domainListView setDataSource: self];
	[domainListView reloadData];
	if ([domainListView numberOfRows] > 0)
	{
		[domainListView selectRow: 0 byExtendingSelection: NO];
		[domainListView scrollRowToVisible: 0];		
	}
	[[mainWindow undoManager] removeAllActions];
}

- (IBAction)importFromFile:(id)sender
{
	NSOpenPanel* openPanel;
	openPanel = [NSOpenPanel openPanel];
	[openPanel setCanChooseDirectories: NO];
	[openPanel setAllowsMultipleSelection: NO];
	[openPanel setTitle: DXmsgOpenPanelTitle];
	[openPanel setPrompt: DXmsgOpenPanelPrompt];
	[openPanel setNameFieldLabel: DXmsgOpenPanelFieldLabel];
	[openPanel setCanSelectHiddenExtension: YES];
	[openPanel setAllowedFileTypes: [NSArray arrayWithObject: @"defdoms"]];
	[openPanel setAllowsOtherFileTypes: YES];
	[openPanel beginSheetForDirectory: nil
								 file: nil
					   modalForWindow: mainWindow
						modalDelegate: self
					   didEndSelector: @selector(doImportFromFile:returnCode:contextInfo:) 
						  contextInfo: nil
		];
}

- (IBAction)newDomain:(id)sender
{
	int rc;
	currentSheet = newDomainSheet;
	rc = [self showCurrentSheet];
	if (rc == 0) return;

	DXDomainEnvelope *newDomain;
	NSString* domainName;
	domainName = [newDomainNameEdit stringValue];
	
	if ([domainName isEqualToString: @""])
	{
		NSBeginAlertSheet(
						  DXmsgEmptyDomainTitle,	// title
						  DXmsgOKButton,			// default button
						  nil,						// alternate button
						  nil,						// other button
						  mainWindow,				// doc window
						  nil,						// modal delegate
						  nil,						// did end selector
						  nil,						// did dismiss selector
						  NULL,						// context info
						  DXmsgEmptyDomainMessage	// message, ...
						  );						  
		return;
	}
	
	if ([self indexOfDomain: domainName] != -1)
	{
		NSBeginAlertSheet(
						  DXmsgExistingDomainTitle,	// title
						  DXmsgOKButton,			// default button
						  nil,						// alternate button
						  nil,						// other button
						  mainWindow,				// doc window
						  nil,						// modal delegate
						  nil,						// did end selector
						  nil,						// did dismiss selector
						  NULL,						// context info
						  DXmsgExistingDomainMessage,	// message, ...
						  domainName
						  );						  
		return;
	}
	
	newDomain = [[DXDomainEnvelope alloc] initWithDomainName: domainName];
	[self addDomain: newDomain];
	[newDomain release];
	[domainListView selectRow: [domains count]-1 byExtendingSelection: NO];
	[domainListView scrollRowToVisible: [domains count]-1];
}

- (IBAction)newKey:(id)sender
{
	DXDomainController* currentDomain;
	DXKey* item;
	DXKey* parent;
	int row, rc;
	
	currentDomain = [self currentDomain];
	if (currentDomain == nil) return;
	
	if ([currentDomain count] == 0)
	{
		parent = [currentDomain rootKey];
	}
	else
	{
		row = [domainContentsView selectedRow];
		item = [domainContentsView itemAtRow: row];
		
		if ([item isCompound])
		{
			if ([domainContentsView isItemExpanded: item])
				parent = item;
			else
				parent = [item parent];
		}
		else
		{
			parent = [item parent];
		}		
	}
	
	if ([parent isArray])
	{
		[newKeyNameEdit setStringValue:
			[NSString stringWithFormat: DXmsgArrayItemNumber, [parent count]]
			];
		[newKeyNameEdit setEnabled: NO];
	}
	else // dictionary
	{
		[newKeyNameEdit setStringValue: DXmsgNewKeyName];
		[newKeyNameEdit setEnabled: YES];
	}
	
	currentSheet = newKeySheet;
	rc = [self showCurrentSheet];
	
	if (rc == 0) return; // user clicked cancel

	NSString* newKeyName;
	newKeyName = [newKeyNameEdit stringValue];
	if ([newKeyName isEqualToString: @""])
	{
		// empty name - cannot add key
		NSBeginAlertSheet(
						  DXmsgEmptyKeyTitle,	// title
						  DXmsgOKButton,			// default button
						  nil,						// alternate button
						  nil,						// other button
						  mainWindow,				// doc window
						  nil,						// modal delegate
						  nil,						// did end selector
						  nil,						// did dismiss selector
						  NULL,						// context info
						  DXmsgEmptyKeyMessage	// message, ...
						  );						  		
		return;
	}
		
	if ([parent isDictionary])
	{
		if ([parent keyExists: newKeyName])
		{
			NSBeginAlertSheet(
							  DXmsgExistingKeyTitle,	// title
							  DXmsgOKButton,			// default button
							  nil,						// alternate button
							  nil,						// other button
							  mainWindow,				// doc window
							  nil,						// modal delegate
							  nil,						// did end selector
							  nil,						// did dismiss selector
							  NULL,						// context info
							  DXmsgExistingKeyMessage,	// message, ...
							  newKeyName
							  );						  					
			return;
		}
	}	
	
	id newKeyValue;
	switch ([newKeyTypePopup indexOfSelectedItem])
	{
		case 1:
			newKeyValue = [[NSNumber alloc] initWithInt: 0];
			break;
		case 2:
			newKeyValue = [[NSCalendarDate alloc] init];
			break;
		case 3:
			newKeyValue = [[NSData alloc] init];
			break;
		case 4:
			newKeyValue = [[NSMutableArray alloc] init];
			break;
		case 5:
			newKeyValue = [[NSMutableDictionary alloc] init];
			break;
		default: // string
			newKeyValue = [[NSString alloc] init];
			break;
	}

	DXKey* keyToAdd;
	keyToAdd = [[DXKey alloc] initWithName: newKeyName
									 value: newKeyValue
									parent: parent
									domain: [currentDomain name]];
	[newKeyValue release];
	[self setCurrentKey: keyToAdd];
	[keyToAdd release];
	
	if (! [currentKey isCompound])
	{ // scalar - let the user set the value
		rc = [self doEditKey];
		if (rc == 0)
			return;
		else
			keyToAdd = [[DXKey alloc] initWithName: [editedKey name]
											 value: [editedKey value]
											parent: [editedKey parent]
											domain: [editedKey domain]];
	}
	else
	{
		keyToAdd = [currentKey retain];
	}
	
	[self addKey: keyToAdd];
	[keyToAdd release];
}

- (IBAction)preferences:(id)sender
{
	[preferencesWindow makeKeyAndOrderFront: self];
}

- (void) doReloadAllDomains: (NSWindow*) sheet
			 returnCode: (int) returnCode
			contextInfo: (void*) contextInfo
{
	if (returnCode != NSAlertDefaultReturn) return;
	[[NSUserDefaults standardUserDefaults] synchronize];
	[domainListView setDataSource: nil];
	[self reloadDomains];
	[domainListView setDataSource: self];
	[domainListView reloadData];
	NSUndoManager* undoManager;
	undoManager = [mainWindow undoManager];
	[undoManager removeAllActions];
}

- (IBAction)reloadAllDomains:(id)sender
{
	NSBeginAlertSheet(
					  DXmsgReloadDomainsTitle,
					  DXmsgYesButton,
					  DXmsgNoButton,
					  nil,
					  mainWindow,
					  self,
					  @selector(doReloadAllDomains:returnCode:contextInfo:),
					  nil,
					  nil,
					  DXmsgReloadDomainsMessage
					  );				
}

- (void) doReloadDomain: (NSWindow*) sheet
			 returnCode: (int) returnCode
			contextInfo: (void*) contextInfo
{
	if (returnCode != NSAlertDefaultReturn) return;
	[[NSUserDefaults standardUserDefaults] synchronize];
	DXDomainController* domain;
	domain = (DXDomainController*) contextInfo;
	[domain reloadDomain];
	[domainListView reloadData];
	[domainContentsView reloadData];
	NSUndoManager* undoManager;
	undoManager = [mainWindow undoManager];
	[undoManager removeAllActions];
}

- (IBAction)reloadDomain:(id)sender
{
	if ([domains count] <= 0) return;
	DXDomainController* currentDomain;
	currentDomain = [self currentDomain];
	if ([currentDomain modified])
	{
		NSBeginAlertSheet(
						  DXmsgReloadDomainTitle,
						  DXmsgYesButton,
						  DXmsgNoButton,
						  nil,
						  mainWindow,
						  self,
						  @selector(doReloadDomain:returnCode:contextInfo:),
						  nil,
						  currentDomain,
						  DXmsgReloadDomainMessage
						  );			
	}
	else
		[self doReloadDomain: nil returnCode: NSAlertDefaultReturn contextInfo: currentDomain];
}

- (void) doSaveDomain: (DXDomainController*) domain
{
	if (! [domain modified]) return;
	NSUserDefaults* def;
	def = [NSUserDefaults standardUserDefaults];
	[def setPersistentDomain: [domain databaseRepresentation] forName: [domain name]];
	[domain setModified: NO];
}

- (IBAction)saveAllDomains:(id)sender
{
	NSEnumerator* domainEnumerator;
	DXDomainController* currentDomain;
	BOOL warningShown;

	if (sender == self)
		warningShown = YES;
	else
		warningShown = NO;
	if ([domains count] <= 0) return;
	domainEnumerator = [domains objectEnumerator];
	while (currentDomain = [domainEnumerator nextObject])
	{
		if ([currentDomain count] > 0)
		{
			[self doSaveDomain: currentDomain];
		}
		else
		{
			if (! warningShown)
			{
				warningShown = YES;
				NSBeginAlertSheet(
								  DXmsgSavingEmptyDomainTitle,		// title
								  DXmsgOKButton,			// default button
								  nil,						// alternate button
								  nil,						// other button
								  mainWindow,				// doc window
								  nil,						// modal delegate
								  nil,						// did end selector
								  nil,						// did dismiss selector
								  NULL,						// context info
								  DXmsgSavingEmptyDomainsMessage	// message, ...
								  );
			}
		}
	}
	[domainListView reloadData];
}

- (IBAction)saveDomain:(id)sender
{
	DXDomainController* currentDomain;
	if ([domains count] <= 0) return;
	currentDomain = [self currentDomain];	
	if (currentDomain == nil) return;
	if ([currentDomain count] > 0)
	{
		[self doSaveDomain: currentDomain];
		[domainListView reloadData];		
	}
	else
	{
		NSBeginAlertSheet(
						  DXmsgSavingEmptyDomainTitle,		// title
						  DXmsgOKButton,			// default button
						  nil,						// alternate button
						  nil,						// other button
						  mainWindow,				// doc window
						  nil,						// modal delegate
						  nil,						// did end selector
						  nil,						// did dismiss selector
						  NULL,						// context info
						  DXmsgSavingEmptyDomainMessage,	// message, ...
						  [currentDomain name]
						  );
	}
}

- (IBAction) searchDomain: (id) sender
{
	NSString* toSearch;
	toSearch = [domainSearchField stringValue];
	if ([toSearch isEqualToString: @""]) 
		return;
	BOOL onlyBeginning;
	int i, c, r;
	NSRange position;
	NSString* currentDomain;
	c = [domains count];
	if (c < 2) return;
	onlyBeginning = 
		[[[[NSUserDefaultsController sharedUserDefaultsController] values] valueForKey: @"DomainSearch"] boolValue];
	r = [domainListView selectedRow];
	i = r + 1;
	if (i >= c) i = 0;
	while (i != r)
	{
		currentDomain = [[domains objectAtIndex: i] name];
		position = [currentDomain rangeOfString: toSearch options: NSCaseInsensitiveSearch];
		if ((position.location != NSNotFound) &&
			((position.location == 0) || (! onlyBeginning)))
		{
			[domainListView selectRow: i byExtendingSelection: NO];
			[domainListView scrollRowToVisible: i];
			[mainWindow makeFirstResponder: domainSearchField];
			return;
		}		
		i++;
		if (i >= c) i = 0;
	}
	NSBeep();
}

- (IBAction) searchKey: (id) sender
{
	NSString* toSearch;
	toSearch = [keySearchField stringValue];
	if ([toSearch isEqualToString: @""])
		return;
	int i, c, r;
	NSRange position;
	NSString* key;
	DXKey* item;
	NSString* value;
	BOOL onlyBeginning;
	BOOL inValues;
	c = [domainContentsView numberOfRows];
	if (c < 2) return;
	onlyBeginning =
		[[[[NSUserDefaultsController sharedUserDefaultsController] values] valueForKey: @"KeySearch"] boolValue];
	inValues =
		[[[[NSUserDefaultsController sharedUserDefaultsController] values] valueForKey: @"LookInValues"] boolValue];
	r = [domainContentsView selectedRow];
	i = r + 1;
	if (i >= c) i = 0;
	while (i != r)
	{
		item = [domainContentsView itemAtRow: i];
		key = [item nameDescription];
		value = [item valueDescription];
		if (inValues)
			key = [NSString stringWithFormat: @"%@ %@", key, value];
		position = [key rangeOfString: toSearch options: NSCaseInsensitiveSearch];
		if ((position.location != NSNotFound) &&
			((position.location == 0) || (! onlyBeginning)))
		{
			[domainContentsView selectRow: i byExtendingSelection: NO];
			[domainContentsView scrollRowToVisible: i];
			[mainWindow makeFirstResponder: keySearchField];
			return;
		}				
		i++;
		if (i >= c) i = 0;
	}
}

- (NSWindow*) sheetForKey: (DXKey*) aKey
{	
	if ([DXKey isObjectNumber: [aKey value]])
		return numberValueSheet;
	else if ([DXKey isObjectDate: [aKey value]])
		return dateValueSheet;
	else if ([DXKey isObjectData: [aKey value]])
		return dataValueSheet;
	else
		return stringValueSheet;
}

- (int) doEditKey
{
	int rc;

	currentSheet = [self sheetForKey: currentKey];

	if (currentSheet == numberValueSheet)
	{
		[numberController setNumber: [currentKey value]];
	}
	else if (currentSheet == dateValueSheet)
	{
		[dateValueEdit setDateValue: [currentKey value]];
	}
	else if (currentSheet == dataValueSheet)
	{
		[dataValueConverter setData: [currentKey value]];
	}
	else // stringValueSheet
	{
		[stringValueEdit setStringValue: [currentKey value]];
	}
	
	[NSApp beginSheet: currentSheet
	   modalForWindow: mainWindow
		modalDelegate: nil
	   didEndSelector: nil
		  contextInfo: NULL
		];
	rc = [NSApp runModalForWindow: currentSheet];
	[NSApp endSheet: currentSheet];
	[currentSheet orderOut: self];
	
	if (rc == 1)
	{
		id newValue;
		
		if (currentSheet == numberValueSheet)
			newValue = [numberController number];
		else if (currentSheet == dateValueSheet)
			newValue = [dateValueEdit dateValue];
		else if (currentSheet == dataValueSheet)
			newValue = [dataValueConverter data];
		else // string
			newValue = [stringValueEdit stringValue];
		
		DXKey* keyAfterEdit;
		keyAfterEdit = [[DXKey alloc] initWithName: [currentKey name]
											 value: newValue
											parent: [currentKey parent]
											domain: [currentKey domain]];
		[self setEditedKey: keyAfterEdit];
		[keyAfterEdit release];
	}
	
	return rc;
}

- (IBAction) keyDoubleClicked:(id)sender
{
	int row;
	DXKey* currentItem;
	int rc;
	
	row = [domainContentsView selectedRow];
	currentItem = [domainContentsView itemAtRow: row];
	
	if ([currentItem isCompound])
	{
		if ([domainContentsView isItemExpanded: currentItem])
			[domainContentsView collapseItem: currentItem];
		else
			[domainContentsView expandItem: currentItem];
	}
	else
	{
		[self setCurrentKey: currentItem];

		rc = [self doEditKey];
		if (rc == 0)
			return;
		
		NSArray* keySequence;
		keySequence = [NSArray arrayWithObjects: currentKey, editedKey, nil];
		[self replaceKeys: keySequence];
	}
	
}

- (IBAction) sheetOKClicked:(id)sender
{
	[NSApp stopModalWithCode: 1];
}

- (IBAction) sheetCancelClicked:(id)sender
{
	[NSApp stopModalWithCode: 0];
}

- (IBAction) showAbout: (id) sender
{
	[NSApp orderFrontStandardAboutPanelWithOptions:
		[NSDictionary dictionaryWithObjectsAndKeys:
			@"DefEcs", @"ApplicationName",
			@"", @"Version",
			[NSString stringWithFormat: DXmsgCopyright, 0xa9], @"Copyright",
			DXmsgVersion, @"ApplicationVersion",
			nil
			]
		];
}


- (int) showCurrentSheet
{
	int rc;
	[NSApp beginSheet: currentSheet
	   modalForWindow: mainWindow 
		modalDelegate: nil 
	   didEndSelector: nil
		  contextInfo: NULL
		];
	rc = [NSApp runModalForWindow: currentSheet];
	[NSApp endSheet: currentSheet];
	[currentSheet orderOut: self];
	return rc;
}

- (DXDomainController*) domainForName: (NSString*) domainName
{
	int i, c;
	DXDomainController *domain;
	c = [domains count];
	for (i = 0; i < c; i++)
	{
		domain = [domains objectAtIndex: i];
		if ([domainName isEqualToString: [domain name]])
			return domain;
	}
	return nil;
}

- (DXDomainController*) currentDomain
{
	return [domainContentsView dataSource];
}

- (int) indexOfDomain: (NSString*) domainName
{
	int i, c;
	c = [domains count];
	for (i = 0; i < c; i++)
	{
		if ([[[domains objectAtIndex: i] name] isEqualToString: domainName])
			return i;
	}
	return -1;
}

- (void) addDomain: (DXDomainEnvelope*) aDomain
{
	NSString* domainName = [aDomain name];
	if ([self domainForName: domainName] != nil)
		return; // domain already exists
	DXDomainController* newDomain;
	newDomain = [[DXDomainController alloc]
		initWithDomain: domainName
			  contents: [aDomain contents]
		  contentsView: domainContentsView];
	[newDomain setModified: YES];
	[domains addObject: newDomain];
	[domainListView reloadData];
	NSUndoManager* undoManager;
	undoManager = [mainWindow undoManager];
	if (undoManager != nil)
	{
		[undoManager registerUndoWithTarget: self
								   selector: @selector(removeDomain:)
									 object: aDomain];
		if ([undoManager isUndoing])
			[undoManager setActionName: DXmsgDeleteDomainAction];
		else
			[undoManager setActionName: DXmsgNewDomainAction];
	}
}

- (void) removeDomain: (DXDomainEnvelope*) aDomain
{
	int domainIndex;
	domainIndex = [self indexOfDomain: [aDomain name]];
	if (domainIndex == -1) return;
	[domains removeObjectAtIndex: domainIndex];
	[domainListView reloadData];
	[domainListView scrollRowToVisible: [domainListView selectedRow]];
	[self tableViewSelectionDidChange: nil];
	NSUserDefaults* defaults;
	defaults = [NSUserDefaults standardUserDefaults];
	[defaults removePersistentDomainForName: [aDomain name]];
	NSUndoManager* undoManager;
	undoManager = [mainWindow undoManager];
	if (undoManager != nil)
	{
		[undoManager registerUndoWithTarget: self
								   selector: @selector(addDomain:)
									 object: aDomain];
		if ([undoManager isUndoing])
			[undoManager setActionName: DXmsgNewDomainAction];
		else
			[undoManager setActionName: DXmsgDeleteDomainAction];
	}
}

- (void) addKey: (DXKey*) aKey
{
	DXDomainController* modifiedDomain;
	DXKey* parent;
	
	modifiedDomain = [self domainForName: [aKey domain]];
	parent = [aKey parent];
	if ([parent isArray])
		[parent addKey: aKey];
	else
		[parent addKey: aKey forName: [aKey name]];
	[modifiedDomain setModified: YES];
	if (parent == [modifiedDomain rootKey])
	{
		[domainContentsView reloadData];		
	}
	else
		[domainContentsView reloadItem: parent reloadChildren: YES];
	[domainListView reloadData];
	NSUndoManager* undoManager;
	undoManager = [mainWindow undoManager];
	if (undoManager != nil)
	{
		[undoManager registerUndoWithTarget: self
								   selector: @selector(removeKey:)
									 object: aKey];
		if ([undoManager isUndoing])
			[undoManager setActionName: DXmsgDeleteKeyAction];
		else
			[undoManager setActionName: DXmsgNewKeyAction];
	}
	if ([[[[NSUserDefaultsController sharedUserDefaultsController] values] valueForKey: @"AutoSave"] boolValue])
		[self doSaveDomain: modifiedDomain];
}

- (void) removeKey: (DXKey*) aKey
{
	DXDomainController* modifiedDomain;
	DXKey* parent;
	
	modifiedDomain = [self domainForName: [aKey domain]];
	parent = [aKey parent];
	[parent removeKey: aKey];
	[modifiedDomain setModified: YES];
	[domainListView reloadData];
	if (parent == [modifiedDomain rootKey])
		[domainContentsView reloadData];
	else
		[domainContentsView reloadItem: parent reloadChildren: YES];	
	NSUndoManager* undoManager;
	undoManager = [mainWindow undoManager];
	if (undoManager != nil)
	{
		[undoManager registerUndoWithTarget: self
								   selector: @selector(addKey:)
									 object: aKey];
		if ([undoManager isUndoing])
			[undoManager setActionName: DXmsgNewKeyAction];
		else
			[undoManager setActionName: DXmsgDeleteKeyAction];
	}
	if ([modifiedDomain count] > 0)
	{
		if ([[[[NSUserDefaultsController sharedUserDefaultsController] values] valueForKey: @"AutoSave"] boolValue])
			[self doSaveDomain: modifiedDomain];
	}
}

- (void) replaceKeys: (NSArray*) theKeys
{
	DXKey* oldKey;
	DXKey* newKey;
	if ([theKeys count] != 2) return;
	oldKey = [theKeys objectAtIndex: 0];
	newKey = [theKeys objectAtIndex: 1];
	
	if (
		(! [[oldKey domain] isEqualToString: [newKey domain]])
		||
		([oldKey parent] != [newKey parent])
		)
		return;
	
	DXDomainController* modifiedDomain;
	modifiedDomain = [self domainForName: [oldKey domain]];
	DXKey* parent;
	parent = [oldKey parent];
	[parent replaceKey: oldKey withKey: newKey];
	
	[modifiedDomain setModified: YES];
	[domainListView reloadData];
	if (parent == [modifiedDomain rootKey])
		[domainContentsView reloadData];
	else
		[domainContentsView reloadItem: parent reloadChildren: YES];	
	NSUndoManager* undoManager;
	undoManager = [mainWindow undoManager];
	if (undoManager != nil)
	{
		[undoManager registerUndoWithTarget: self
								   selector: @selector(replaceKeys:)
									 object: [NSArray arrayWithObjects: newKey, oldKey, nil]];
		[undoManager setActionName: DXmsgEditKeyAction];
	}
	if ([[[[NSUserDefaultsController sharedUserDefaultsController] values] valueForKey: @"AutoSave"] boolValue])
		[self doSaveDomain: modifiedDomain];
}

- (IBAction) goToHomePage: (id) sender
{
	[[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString: DXmsgDefEcsURL]];
}


@end
