#import "PhidgetEncoderController.h"

int gotAttach(CPhidgetHandle phid, void *context) {
	[(id)context performSelectorOnMainThread:@selector(phidgetAdded:)
								  withObject:nil
							   waitUntilDone:NO];
	return 0;
}
int gotDetach(CPhidgetHandle phid, void *context) {
	[(id)context performSelectorOnMainThread:@selector(phidgetRemoved:)
								  withObject:nil
							   waitUntilDone:NO];
	return 0;
}

int gotError(CPhidgetHandle phid, void *context, int errcode, const char *error) {
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	[(id)context performSelectorOnMainThread:@selector(ErrorEvent:)
								  withObject:[NSArray arrayWithObjects:[NSNumber numberWithInt:errcode], [NSString stringWithUTF8String:error], nil]
							   waitUntilDone:NO];
	[pool release];
	return 0;
}
int gotInputChange(CPhidgetEncoderHandle phid, void *context, int ind, int val) {
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	[(id)context performSelectorOnMainThread:@selector(InputChange:)
								  withObject:[NSArray arrayWithObjects:[NSNumber numberWithInt:ind], [NSNumber numberWithInt:val], nil]
							   waitUntilDone:NO];
	[pool release];
	return 0;
}
int gotPositionChange(CPhidgetEncoderHandle phid, void *context, int ind, int time, int dir) {
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	int position;
	CPhidgetEncoder_getPosition(phid, ind, &position);
	[(id)context performSelectorOnMainThread:@selector(PositionChange:)
								  withObject:[NSArray arrayWithObjects:
											  [NSNumber numberWithInt:ind], 
											  [NSNumber numberWithInt:time], 
											  [NSNumber numberWithInt:dir], 
											  [NSNumber numberWithInt:position], 
											  nil]
							   waitUntilDone:NO];
	[pool release];
	return 0;
}

@implementation PhidgetEncoderController

- (void)phidgetAdded:(id)nothing
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	
	int serial, version, i;
	const char *name;
	CPhidget_DeviceID devid;
	
	CPhidget_getSerialNumber((CPhidgetHandle)encoder, &serial);
	CPhidget_getDeviceVersion((CPhidgetHandle)encoder, &version);
	CPhidget_getDeviceName((CPhidgetHandle)encoder, &name);
	CPhidget_getDeviceID((CPhidgetHandle)encoder, &devid);
	CPhidgetEncoder_getInputCount(encoder, &numInputs);
	CPhidgetEncoder_getEncoderCount(encoder, &numEncoders);
	
	[connectedField setStringValue:[NSString stringWithUTF8String:name]];
	[serialField setIntValue:serial];
	[versionField setIntValue:version];
	[numEncodersField setIntValue:numEncoders];
	[numInputsField setIntValue:numInputs];
	
	NSRect frame = [mainWindow frame];
	int heightChange;
	switch(devid)
	{
		case PHIDID_ENCODER_1ENCODER_1INPUT:
			heightChange = frame.size.height - 351;
			[timeLabel setStringValue:@"Time (ms):"];
			[indexLabel setHidden:true];
			break;
		case PHIDID_ENCODER_HS_1ENCODER:
			heightChange = frame.size.height - 269;
			[timeLabel setStringValue:@"Time (ms):"];
			[indexLabel setHidden:true];
			break;
		case PHIDID_ENCODER_HS_4ENCODER_4INPUT:
			heightChange = frame.size.height - 405;
			[timeLabel setStringValue:[NSString stringWithUTF8String:"Time (µs):"]];
			[indexLabel setHidden:false];
			break;
		default:
			break;
	}
	
	[positions renewRows:numEncoders columns:1];
	[positionSliders renewRows:numEncoders columns:1];
	[encoderLabels renewRows:numEncoders columns:1];
	[msTimes renewRows:numEncoders columns:1];
	[enabledCheckboxes renewRows:numEncoders columns:1];
	for(i=0;i<numEncoders;i++)
	{
		int enabled;
		CPhidgetEncoder_getEnabled(encoder, i, &enabled);
		[[enabledCheckboxes cellWithTag:i] setState:enabled];
		[[positions cellWithTag:i] setStringValue:@""];
		[[positionSliders cellWithTag:i] setIntValue:0];
		[[msTimes cellWithTag:i] setStringValue:@""];
		[[indexes cellWithTag:i] setStringValue:@""];
		switch(devid)
		{
			case PHIDID_ENCODER_1ENCODER_1INPUT:
				[[positionSliders cellWithTag:i] setMaxValue:250];
				[[positionSliders cellWithTag:i] setMinValue:-250];
				[[enabledCheckboxes cellWithTag:i] setEnabled:false];
				break;
			case PHIDID_ENCODER_HS_1ENCODER:
				[[positionSliders cellWithTag:i] setMaxValue:50000];
				[[positionSliders cellWithTag:i] setMinValue:-50000];
				[[enabledCheckboxes cellWithTag:i] setEnabled:false];
				break;
			case PHIDID_ENCODER_HS_4ENCODER_4INPUT:
				[[positionSliders cellWithTag:i] setMaxValue:50000];
				[[positionSliders cellWithTag:i] setMinValue:-50000];
				[[enabledCheckboxes cellWithTag:i] setEnabled:true];
				break;
			default:
				break;
		}
	}
	NSRect frame2 = [encoderBox frame];
	frame2.origin.y = frame2.origin.y + frame2.size.height - (57+17*numEncoders);
	frame2.size.height = 57+17*numEncoders;
	[encoderBox setFrame:frame2];
	[encoderBox setHidden:FALSE];
	
	if(numInputs)
	{
		[inputs renewRows:1 columns:numInputs];
		[inputLabels renewRows:1 columns:numInputs];
		for(i=0;i<numInputs;i++)
		{
			[[inputs cellWithTag:i] setEnabled:FALSE];
			[[inputs cellWithTag:i] setState:FALSE];
		}
		[inputsBox setHidden:FALSE];
	}
	
	frame.origin.y += heightChange;
	frame.size.height -= heightChange;
	[mainWindow setMinSize:frame.size];
	[mainWindow setFrame:frame display:YES animate:NO];
	
	[self setPicture:version:devid];
	[pool release];
	[mainWindow display];
}

- (void)phidgetRemoved:(id)nothing
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	
	[connectedField setTitleWithMnemonic:@"Nothing"];
	[serialField setTitleWithMnemonic:@""];
	[versionField setTitleWithMnemonic:@""];
	[numInputsField setTitleWithMnemonic:@""];
	[numEncodersField setTitleWithMnemonic:@""];
	
	[encoderBox setHidden:TRUE];
	[inputsBox setHidden:TRUE];
	
	NSRect frame = [mainWindow frame];
	int heightChange = frame.size.height - 192;
	frame.origin.y += heightChange;
	frame.size.height -= heightChange;
	[mainWindow setMinSize:frame.size];
	[mainWindow setFrame:frame display:YES animate:NO];
	
	[self setPicture:0:0];
	
	[pool release];
	[mainWindow display];
}

- (void)InputChange:(NSArray *)inputChangeData
{
	[[inputs cellWithTag:[[inputChangeData objectAtIndex:0] intValue]] 
	 setState:[[inputChangeData objectAtIndex:1] intValue]];
}

/* position change */
- (void)PositionChange:(NSArray *)positionChangeData
{
	int index;
	
	[[positions cellWithTag:[[positionChangeData objectAtIndex:0] intValue]] 
	 setIntValue:[[positionChangeData objectAtIndex:3] intValue]];
	[[positionSliders cellWithTag:[[positionChangeData objectAtIndex:0] intValue]] 
	 setIntValue:[[positionChangeData objectAtIndex:3] intValue]];
	[[msTimes cellWithTag:[[positionChangeData objectAtIndex:0] intValue]] 
	 setIntValue:[[positionChangeData objectAtIndex:1] intValue]];
	
	if(!CPhidgetEncoder_getIndexPosition(encoder, [[positionChangeData objectAtIndex:0] intValue], &index))
	{
		[[indexes cellWithTag:[[positionChangeData objectAtIndex:0] intValue]] 
		 setIntValue:index];
	}
}

- (IBAction)enable:(id)sender
{
	CPhidgetEncoder_setEnabled(encoder, [sender selectedTag], [[sender cellWithTag:[sender selectedTag]] state]);
}

- (void)openCmdLine
{
	int serial = -1, remote = 0;
	NSArray *args = [[NSProcessInfo processInfo] arguments];
	if([args count] > 1)
	{
		if([[args objectAtIndex:1] isEqualToString:@"remote"])
			remote = 1;
		serial = [[args objectAtIndex:[args count]-1] intValue];
		if(serial == 0) serial = -1;
	}
	
	if(remote)
		CPhidget_openRemote((CPhidgetHandle)encoder, serial, NULL, [[passwordField stringValue] UTF8String]);
	else
		CPhidget_open((CPhidgetHandle)encoder, serial);
}

/*
* This gets run when the GUI gets displayed
*/
- (void)awakeFromNib
{
	[mainWindow setDelegate:self];
	
	
	CPhidgetEncoder_create(&encoder);
	
	CPhidget_set_OnAttach_Handler((CPhidgetHandle)encoder, gotAttach, self);
	CPhidget_set_OnDetach_Handler((CPhidgetHandle)encoder, gotDetach, self);
	CPhidget_set_OnError_Handler((CPhidgetHandle)encoder, gotError, self);
	CPhidgetEncoder_set_OnInputChange_Handler(encoder, gotInputChange, self);
	CPhidgetEncoder_set_OnPositionChange_Handler(encoder, gotPositionChange, self);
	
	[self openCmdLine];
}

- (void)windowWillClose:(NSNotification *)aNotification {
	CPhidget_close((CPhidgetHandle)encoder);
	CPhidget_delete((CPhidgetHandle)encoder);
	encoder = NULL;
	[NSApp terminate:self];
}

- (void)setPicture:(int)version:(CPhidget_DeviceID)devid
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	NSString *imgPath;
	
	switch(devid)
	{
		case PHIDID_ENCODER_1ENCODER_1INPUT:
			imgPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"1052_0" ofType:@"icns"];
			break;
		case PHIDID_ENCODER_HS_1ENCODER:
			imgPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"1057_1" ofType:@"icns"];
			break;
		case PHIDID_ENCODER_HS_4ENCODER_4INPUT:
			imgPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"1047_0" ofType:@"icns"];
			break;
		default:
			imgPath = nil;
			break;
	}
	
	NSImage *img = [[NSImage alloc]  initByReferencingFile:imgPath];
	
	//otherwise the images are just painted over each other - and the transparency causes trouble
	[pictureBox setImage:nil];
	[pictureBox display];
	if(imgPath!=nil)
		[NSApp setApplicationIconImage: img];
	[pictureBox setImage:img];
	[pictureBox display];
	
	[pool release];
}

int errorCounter = 0;
- (void)ErrorEvent:(NSArray *)errorEventData
{
	int errorCode = [[errorEventData objectAtIndex:0] intValue];
	NSString *errorString = [errorEventData objectAtIndex:1];
	
	switch(errorCode)
	{
		case EEPHIDGET_BADPASSWORD:
			CPhidget_close((CPhidgetHandle)encoder);
			[NSApp runModalForWindow:passwordPanel];
			break;
		case EEPHIDGET_BADVERSION:
			CPhidget_close((CPhidgetHandle)encoder);
			NSRunAlertPanel(@"Version mismatch", [NSString stringWithFormat:@"%@\nApplication will now close.", errorString], nil, nil, nil);
			[NSApp terminate:self];
			break;
		default:
			errorCounter++;
			
			NSAttributedString *string = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@\n",errorString]];
			
			[[errorEventLog textStorage] beginEditing];
			[[errorEventLog textStorage] appendAttributedString:string];
			[[errorEventLog textStorage] endEditing];
			
			[errorEventLogCounter setIntValue:errorCounter];
			if(![errorEventLogWindow isVisible])
				[errorEventLogWindow setIsVisible:YES];
			break;
	}
}

- (IBAction)clearErrorLog:(id)sender
{
	[[errorEventLog textStorage] setAttributedString:[[NSAttributedString alloc] initWithString:@""]];
	[errorEventLogCounter setIntValue:0];
	errorCounter = 0;
}

- (IBAction)passwordOK:(id)sender
{
	[passwordPanel setIsVisible:NO];
	[NSApp stopModal];
	[self openCmdLine];
	[passwordField setStringValue:@""];
}

- (IBAction)passwordCancel:(id)sender
{
	[passwordPanel setIsVisible:NO];
	[NSApp stopModal];
	[NSApp terminate:self];
}
@end
