#import "DictionaryViewerController.h"

@implementation DictionaryViewerController
CPhidgetDictionaryHandle dict;
CPhidgetDictionaryListenerHandle listener = NULL;
	
int
event_handler(CPhidgetDictionaryHandle dict, void *context, const char *key, const char *val, CPhidgetDictionary_keyChangeReason reason)
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	[(id)context performSelectorOnMainThread:@selector(gotAKey:)
								  withObject:[[[KeyInfo alloc] initWithKeyValReason:key:val:reason] retain]
							   waitUntilDone:NO];
	[pool release];
	return 0;
}

int gotConnect(CPhidgetDictionaryHandle dict, void *context) {
	[(id)context performSelectorOnMainThread:@selector(serverConnected:)
								  withObject:nil
							   waitUntilDone:NO];
	return 0;
}

int gotDisconnect(CPhidgetDictionaryHandle dict, void *context) {
	[(id)context performSelectorOnMainThread:@selector(serverDisconnected:)
								  withObject:nil
							   waitUntilDone:NO];
	return 0;
}

int gotError(CPhidgetDictionaryHandle phid, void *context, int errcode, const char *error) {
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	[(id)context performSelectorOnMainThread:@selector(gotErrEvent:)
								  withObject:[[NSArray arrayWithObjects:[NSString stringWithCString:error], [NSNumber numberWithInt:errcode], nil] retain]
							   waitUntilDone:NO];
	[pool release];
	return 0;
}

- (IBAction)guiAddKey:(id)sender
{
	CPhidgetDictionary_addKey(dict, [[keyField stringValue] UTF8String], [[valueField stringValue] UTF8String], TRUE);
}

- (IBAction)DelKey:(id)sender
{
	CPhidgetDictionary_removeKey(dict, [[keyField stringValue] UTF8String]);
}

- (IBAction)chooseOpenType:(id)sender
{
	if([[sender titleOfSelectedItem] isEqualToString:@"Address, Port"])
	{
		[addressText setStringValue:@"Address:"];
		[addressField setStringValue:@"localhost"];
		[portText setHidden:FALSE];
		[portField setHidden:FALSE];
	}
	else if([[sender titleOfSelectedItem] isEqualToString:@"Server ID"])
	{
		[addressText setStringValue:@"ServerID:"];
		[addressField setStringValue:@""];
		[portText setHidden:TRUE];
		[portField setHidden:TRUE];
	}
}

- (void)gotErrEvent:(NSArray *)errInfo
{
	switch([[errInfo objectAtIndex:1] intValue])
	{
		case EEPHIDGET_BADPASSWORD:
			[self connect:nil];
			NSRunAlertPanel(@"Authentication failed", @"The Phidget webservice requires a password.", nil, nil, nil);
			break;
		case EEPHIDGET_BADVERSION:
			[self connect:nil];
			NSRunAlertPanel(@"Version mismatch", [errInfo objectAtIndex:0], nil, nil, nil);
			break;
		case EEPHIDGET_NETWORK:
			//NSRunAlertPanel(@"Network Error", [NSString stringWithFormat:@"Message: %s", error], nil, nil, nil);
			break;
		default:
			//NSRunAlertPanel(@"Received an Asynchronous Error", [NSString stringWithFormat:@"Code: %d\n%s", errcode, error], nil, nil, nil);
			break;
	}
}

- (void)gotAKey:(KeyInfo *)keyInfo
{
	[NSAutoreleasePool addObject:keyInfo];
	if([keyInfo reason] == PHIDGET_DICTIONARY_ENTRY_REMOVING)
		[keys removeObject: keyInfo];
	else
	{
		[keys removeObject: keyInfo];
		[keys addObject: keyInfo];
	}
	
	newTableData = TRUE;
}

- (void) reloadTable
{
	if(newTableData == TRUE)
	{
		[keys sortUsingSelector:@selector(compareKey:)];
		[treeView reloadData];
		[keycountField setIntValue:[keys count]];
		newTableData = FALSE;
	}
}

- (IBAction)connect:(id)sender
{
	if([[connectButton title] isEqualToString:@"Connect"])
	{	
		[statusText setStringValue:@"Trying to Connect..."];
		if([[openTypeComboBox titleOfSelectedItem] isEqualToString:@"Address, Port"])
			CPhidgetDictionary_openRemoteIP(dict, [[addressField stringValue] UTF8String], [portField intValue], [[passwordField stringValue] UTF8String]);
		if([[openTypeComboBox titleOfSelectedItem] isEqualToString:@"Server ID"])
		{
			if(![[addressField stringValue] UTF8String][0])
				CPhidgetDictionary_openRemote(dict, NULL, [[passwordField stringValue] UTF8String]);
			else
				CPhidgetDictionary_openRemote(dict, [[addressField stringValue] UTF8String], [[passwordField stringValue] UTF8String]);
		}
		[connectButton setTitle:@"Disconnect"];
	}
	else if([[connectButton title] isEqualToString:@"Disconnect"])
	{
		[connectButton setTitle:@"Connect"];
		[self serverDisconnected:nil];
		CPhidgetDictionary_close(dict);
	}
}

- (void)serverConnected:(id)nothing
{
	CPhidgetDictionary_set_OnKeyChange_Handler(dict, &listener, ".*", event_handler, self);
	[statusText setStringValue:@"Connected"];
	[valueField setEnabled:TRUE];
	[keyField setEnabled:TRUE];
	[addButton setEnabled:TRUE];
	[deleteButton setEnabled:TRUE];
	
	NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.1
													  target:self
													selector:@selector(reloadTable)
													userInfo:nil
													 repeats:YES];
	reloadTableTimer = timer;
}

- (void)serverDisconnected:(id)nothing
{
	if(listener)
	{
		CPhidgetDictionary_remove_OnKeyChange_Handler(listener);
		listener = NULL;
	}
	if([[connectButton title] isEqualToString:@"Connect"])
		[statusText setStringValue:@"Not Connected"];
	else if([[connectButton title] isEqualToString:@"Disconnect"])
		[statusText setStringValue:@"Trying to Connect..."];
	[keys removeAllObjects];
    [treeView reloadData];
	[valueField setEnabled:FALSE];
	[keyField setEnabled:FALSE];
	[addButton setEnabled:FALSE];
	[deleteButton setEnabled:FALSE];
	
	if(reloadTableTimer != nil)
	{
		[reloadTableTimer invalidate];
		reloadTableTimer = nil;
	}
}

/*
 * This gets run when the GUI gets displayed
 */
- (void)awakeFromNib
{
	[mainWindow setDelegate:self];
	// Create the storage our table will use.
    keys = [[NSMutableArray alloc] init];
    // Be the data source... 
    [treeView setDataSource:self];
	
	CPhidgetDictionary_create(&dict);
	
	CPhidgetDictionary_set_OnServerConnect_Handler(dict, gotConnect, self);
	CPhidgetDictionary_set_OnServerDisconnect_Handler(dict, gotDisconnect, self);
	CPhidgetDictionary_set_OnError_Handler(dict, gotError, self);
}

- (void)windowWillClose:(NSNotification *)aNotification {
	CPhidgetDictionary_close(dict);
	CPhidgetDictionary_delete(dict);
	dict = 0;
	[NSApp terminate:self];
}

// ---------------------------------------------------------
//  Data source methods
// ---------------------------------------------------------

- (int)numberOfRowsInTableView:(NSTableView *)tv {
    return [keys count];
}

- (id)tableView:(NSTableView *)tv objectValueForTableColumn:(NSTableColumn *)tc row:(int)row {
	NSParameterAssert(row >= 0 && row < [keys count]);
    if ([[tc identifier] isEqualToString:@"Key"]) {
        return [[keys objectAtIndex:row] key];
    } else if ([[tc identifier] isEqualToString:@"Value"]) {
        return [[keys objectAtIndex:row] val];
    } else {
        return NULL;
    }
}

- (void)tableView:(NSTableView *)tv
    setObjectValue:objectValue
    forTableColumn:(NSTableColumn *)tc
    row:(int)row
{
	char buf[1024];
    KeyInfo *keyInfo = [keys objectAtIndex:row];
	sprintf(buf, "%s",([keyInfo.key UTF8String]));
	printf("set: %s -> %s\n",buf,[objectValue UTF8String]);
	
	CPhidgetDictionary_addKey(dict, buf, [objectValue UTF8String], TRUE);
	
	return;
	
	NSParameterAssert(row >= 0 && row < [keys count]);
    if ([[tc identifier] isEqualToString:@"Key"]) {
        [[keys objectAtIndex:row] setKey: objectValue];
    } else {
        [[keys objectAtIndex:row] setVal: objectValue];
    }
}


@end
