#import "PhidgetTextLCDController.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 stringWithCString:error], nil]
							   waitUntilDone:NO];
	[pool release];
	return 0;
}

int gotSleep(void *context) {
	CPhidgetTextLCD_setDisplayString([(id)context getLcd], 0, "System Sleep.");
	return 0;
}

int gotWakeup(void *context) {
	CPhidgetTextLCD_setDisplayString([(id)context getLcd], 0, "System Wakeup.");
	return 0;
}

@implementation PhidgetTextLCDController

- (IBAction)contrastChanged:(id)sender
{
	CPhidgetTextLCD_setContrast(lcd,[sender intValue]);
	[contrastField setIntValue:[sender intValue]];
}

- (IBAction)brightnessChanged:(id)sender
{
	CPhidgetTextLCD_setBrightness(lcd,[sender intValue]);
	[brightnessField setIntValue:[sender intValue]];
}

- (IBAction)backlightChecked:(id)sender
{
	CPhidgetTextLCD_setBacklight(lcd,[sender state]);
}

- (IBAction)cursorChecked:(id)sender
{
	CPhidgetTextLCD_setCursorOn(lcd,[sender state]);
}

- (IBAction)cursorBlinkChecked:(id)sender
{
	CPhidgetTextLCD_setCursorBlink(lcd,[sender state]);
}

- (IBAction)setScreen:(id)sender
{
	CPhidgetTextLCD_setScreen(lcd, [sender indexOfSelectedItem]);
	[self fillForm];
}

- (IBAction)setScreenSize:(id)sender
{
	CPhidgetTextLCD_setScreenSize(lcd, [sender indexOfSelectedItem]+1);
	[self fillForm];
}

- (IBAction)initializeScreen:(id)sender
{
	CPhidgetTextLCD_initialize(lcd);
}

- (CPhidgetTextLCDHandle)getLcd
{
	return lcd;
}

- (void)fillForm
{
	NSRect frame = [mainWindow frame];
	int heightChange = 0, i;
	CPhidgetTextLCD_ScreenSize screenSize;
	int backlight, brightness, contrast;
	
	if(!CPhidgetTextLCD_getBacklight(lcd, &backlight))
	{
		[backlightCheck setState:backlight];
	}
	
	if(!CPhidgetTextLCD_getContrast(lcd, &contrast))
	{
		[contrastSlider setIntValue:contrast];
		[contrastField setIntValue:contrast];
	}
	
	if(!CPhidgetTextLCD_getBrightness(lcd, &brightness))
	{
		[brightnessSlider setIntValue:brightness];
		[brightnessField setIntValue:brightness];
	}
	
	if(!CPhidgetTextLCD_getScreenSize(lcd, &screenSize) && screenSize != PHIDGET_TEXTLCD_SCREEN_NONE)
	{
		CPhidgetTextLCD_getRowCount(lcd, &numRows);
		CPhidgetTextLCD_getColumnCount(lcd, &numCols);
		
		//22px per display string + 10px between - full size 118 + 40 for the box
		NSRect displayBoxFrame = [displayBox frame];
		displayBoxFrame.origin.y = displayBoxFrame.origin.y + displayBoxFrame.size.height - (40+22*numRows+10*(numRows-1));
		displayBoxFrame.size.height = 40+22*numRows+10*(numRows-1);
		[displayBox setFrame:displayBoxFrame];
		
		NSRect displayStringsFrame = [displayStrings frame];
		displayStringsFrame.origin.x = 18 + (40 - numCols)/2 * 8.15;
		[displayStrings setFrame:displayStringsFrame];
		
		NSSize cSize = [displayStrings cellSize];
		cSize.width = 8.15*numCols;
		[displayStrings setCellSize:cSize];
		
		[displayStrings renewRows:numRows columns:1];
		[displayStrings sizeToCells];
		
		//add 8 for spacing between boxes
		heightChange = -(40+22*numRows+10*(numRows-1)+8);
	
		for(i=0;i<numRows;i++)
		{
			[[displayStrings cellWithTag:i] setStringValue:@""];
			[[displayStrings cellWithTag:i] setFont:[NSFont fontWithName:@"Courier New" size:13.0]];
		}
		
		[displayBox setHidden:FALSE];
	}
	else {
		[displayBox setHidden:TRUE];
	}
	[screenSizeCombo selectItemAtIndex:screenSize-1];
	
	frame.origin.y = frame.origin.y + (frame.size.height - baseHeight + heightChange);
	frame.size.height = baseHeight - heightChange;
	[mainWindow setMinSize:frame.size];
	[mainWindow setFrame:frame display:YES animate:NO];
}

- (void)phidgetAdded:(id)nothing
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	NSRect frame = [mainWindow frame];
	int serial, version, i;
	const char *name;
	CPhidget_DeviceID devid;
	int heightChange;

	CPhidget_getSerialNumber((CPhidgetHandle)lcd, &serial);
	CPhidget_getDeviceVersion((CPhidgetHandle)lcd, &version);
	CPhidget_getDeviceName((CPhidgetHandle)lcd, &name);
	CPhidget_getDeviceID((CPhidgetHandle)lcd, &devid);
	CPhidgetTextLCD_getScreenCount(lcd, &numScreens);
	
	[connectedField setStringValue:[NSString stringWithCString:name]];
	[serialField setIntValue:serial];
	[versionField setIntValue:version];
	[numScreensField setIntValue:numScreens];
	
	[cursorCheck setState:0];
	[cursorBlinkCheck setState:0];
	
	[screenCombo removeAllItems];
	for(i=0;i<numScreens;i++)
	{
		[screenCombo addItemWithObjectValue:[NSNumber numberWithInt:i]];
	}
	[screenCombo setHidden:FALSE];
	[screenLabel setHidden:FALSE];
	[screenCombo selectItemAtIndex:0];
	CPhidgetTextLCD_setScreen(lcd, 0);
	
	int settingsBoxHeight = 126;
	
	switch(devid)
	{
		case PHIDID_TEXTLCD_ADAPTER:
			heightChange = frame.size.height - 351;
			
			[screenSizeCombo setEnabled:TRUE];
			
			[brightnessLabel setHidden:FALSE];
			[brightnessField setHidden:FALSE];
			[brightnessSlider setHidden:FALSE];
			break;
		case PHIDID_TEXTLCD_2x20_w_8_8_8:
			//This version has backlight defaulted to off, and supports backlight brightness
			if(version >= 200)
			{
				heightChange = frame.size.height - 351;
				
				[screenSizeCombo setEnabled:FALSE];
				
				[backlightCheck setState:0];
				
				[brightnessLabel setHidden:FALSE];
				[brightnessField setHidden:FALSE];
				[brightnessSlider setHidden:FALSE];
				break;
			}
		default:
			heightChange = frame.size.height - 330;
			settingsBoxHeight = 105;
			
			[screenSizeCombo setEnabled:FALSE];
			
			[backlightCheck setState:1];
	}
	
	NSSize settingsSize = [settingsBox frame].size;
	NSRect settingsFrame = [settingsBox frame];
	int displayBoxOriginShift = settingsSize.height - settingsBoxHeight;
	settingsSize.height = settingsBoxHeight;
	settingsFrame.origin.y = settingsFrame.origin.y + settingsFrame.size.height - settingsBoxHeight;
	settingsFrame.size.height = settingsBoxHeight;
	[settingsBox setFrame:settingsFrame];
	[settingsBox setFrameSize:settingsSize];
	
	NSRect displayBoxFrame = [displayBox frame];
	displayBoxFrame.origin.y = displayBoxFrame.origin.y + displayBoxOriginShift;
	[displayBox setFrame:displayBoxFrame];
	
	[settingsBox setHidden:FALSE];
	
	frame.origin.y += heightChange;
	frame.size.height -= heightChange;
	[mainWindow setMinSize:frame.size];
	[mainWindow setFrame:frame display:YES animate:NO];
	
	baseHeight = frame.size.height;
	
	[self fillForm];
	
	[self setPicture:version:devid];
	[pool release];
	[mainWindow display];
}

- (void)phidgetRemoved:(id)nothing
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	[connectedField setStringValue:@"Nothing"];
	[serialField setStringValue:@""];
	[versionField setStringValue:@""];
	[numScreensField setStringValue:@""];
	
	[screenCombo setHidden:TRUE];
	[screenLabel setHidden:TRUE];
	[settingsBox setHidden:TRUE];
	[displayBox setHidden:TRUE];
	
	[brightnessLabel setHidden:TRUE];
	[brightnessField setHidden:TRUE];
	[brightnessSlider setHidden:TRUE];
	
	NSRect frame = [mainWindow frame];
	int heightChange = frame.size.height - 196;
	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)setString:(NSString *)string
{
	CPhidgetTextLCD_setDisplayString(lcd, 0, (char *)[string UTF8String]);
}

- (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)lcd, serial, NULL, [[passwordField stringValue] UTF8String]);
	else
		CPhidget_open((CPhidgetHandle)lcd, serial);
}

/*
* This gets run when the GUI gets displayed
*/
- (void)awakeFromNib
{
	[mainWindow setDelegate:self];
	[displayStrings setDelegate:self];
	
	CPhidgetTextLCD_create(&lcd);
	
	CPhidget_set_OnAttach_Handler((CPhidgetHandle)lcd, gotAttach, self);
	CPhidget_set_OnDetach_Handler((CPhidgetHandle)lcd, gotDetach, self);
	CPhidget_set_OnError_Handler((CPhidgetHandle)lcd, gotError, self);
	
	CPhidget_set_OnWillSleep_Handler(gotSleep, self);
	CPhidget_set_OnWakeup_Handler(gotWakeup, self);
	
	[self openCmdLine];
}

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

- (void)controlTextDidChange:(NSNotification *)aNotification
{
	int index = [[aNotification object] selectedTag];
	NSString *str = [[[aNotification object] cellWithTag:index] stringValue];
	
	if([str length] > numCols)
		CPhidgetTextLCD_setDisplayString(lcd,index,(char *)[[str substringToIndex:numCols] UTF8String]);
	else
		CPhidgetTextLCD_setDisplayString(lcd,index,(char *)[str UTF8String]);
}

- (void)setPicture:(int)version:(CPhidget_DeviceID)devid
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	NSString *imgPath;
	
	switch(devid)
	{
		case PHIDID_TEXTLCD_2x20:
		case PHIDID_TEXTLCD_2x20_w_0_8_8:
			imgPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"lcd" ofType:@"icns"];
			break;
		case PHIDID_TEXTLCD_2x20_w_8_8_8:
			imgPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"1202_2" ofType:@"icns"];
			break;
		case PHIDID_TEXTLCD_ADAPTER:
			imgPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"1204_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)lcd);
			[NSApp runModalForWindow:passwordPanel];
			break;
		case EEPHIDGET_BADVERSION:
			CPhidget_close((CPhidgetHandle)lcd);
			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
