/*
 * Puppeteer 1.1
 *
 * Copyright (c) 1994 Primitive Software Ltd.  All rights reserved.
 *
 * Author: Dave Griffiths <dave@prim.demon.co.uk>
 */

#import "Controller.h"
#import "Puppeteer.h"
#import "WindowInfo.h"
#import "RemoteView.h"

id	puppet;			// Puppet on a string
BOOL	bufferKeystrokes;	// YES if key strokes are buffered until flushed
int	selectedWindow;		// The currently selected window

@implementation Controller

unsigned short
PVEditorFilter(unsigned short theChar, int flags, unsigned short charSet)
/*
 * This filter is called for each character that is typed. If keyboard buffering is
 * turned off (default), send keydown and keyup events for each character.
 */
{
	if (!bufferKeystrokes) {
		if (flags & NX_COMMANDMASK)
			/*
			 * If it's a command key, make the application active. This
			 * has the effect of enabling menu items that depend on the
			 * key window.
			 */
			[puppet postActivate:YES];
		[puppet postKeyboardEvent:NX_KEYDOWN window:selectedWindow flags:flags 
			charCode:theChar];
		[puppet postKeyboardEvent:NX_KEYUP window:selectedWindow flags:flags 
			charCode:theChar];
		if (flags & NX_COMMANDMASK)
			[puppet postActivate:NO];
	}
	
	return NXEditorFilter(theChar, flags, charSet);
}

- appDidInit:sender
{
	selectedWindow = NX_KEYWINDOW;
	[textObject setCharFilter:PVEditorFilter];
	[mainWindow makeKeyAndOrderFront:self];
	
	return self;
}

- appWillTerminate:sender
{
	[puppet releaseStrings];
	
	return self;
}

- reloadPopupList
/*
 * Refresh the popupList with the current window list.
 */
{
	id winList, popupList, win, matrix;
	int i, count, localWindowNumber;
	NXRect frame;
	char title[256];

	/*
	 * First remove all except the first three items.
	 */
	popupList = [chooseWindowButton target];
	matrix = [popupList itemList];
	count = [popupList count];
	for (i=3; i<count; i++)
		[popupList removeItemAt:i];
	
	/*
	 * Now load the new list. The local window number is stored as the tag
	 * to identify the selected window.
	 */
	winList = [puppet windowList];
	count = [winList count];
	for (i=0; i<count; i++) {
		win = [winList objectAt:i];
		localWindowNumber = [win localWindowNumber];
		[win getFrame:&frame];
		sprintf(title, "%d (%.0f x %.0f)", localWindowNumber, 
			frame.size.width, frame.size.height);
		[popupList addItem:title];
		[matrix setTag:localWindowNumber at:i+3:0];
	}
	[popupList setTarget:self];
	[popupList setAction:@selector(chooseWindow:)];
	
	return self;
}

- attachStrings:sender
{
	if (puppet) {
		[puppet releaseStrings];
		[puppet free];
		puppet = nil;
	} else {	
		puppet = [Puppeteer connectToApp:[appNameField stringValueAt:0] 
			launch:NO];
		if (!puppet) {
			NXRunAlertPanel(0, "Could not connect to %s", 0, 0, 0,
				[appNameField stringValueAt:0]);
			return self;
		}	
		[puppet attachStrings];
		[remoteView setWindow:[puppet mainWindow]];
		[self reloadPopupList];
	}
	
	return self;
}

- flushKeyboardBuffer:sender
/*
 * Flush the text in the text object as if it were a sequence of keystrokes.
 */
{
	int i, textLength = [textObject textLength];
	char *text;
	
	text = (char *)malloc(textLength+1);
	[textObject getSubstring:text start:0 length:textLength];
	for (i=0; i<textLength; i++) {
		[puppet postKeyboardEvent:NX_KEYDOWN window:selectedWindow flags:0 
			charCode:text[i]];
		[puppet postKeyboardEvent:NX_KEYUP window:selectedWindow flags:0 
			charCode:text[i]];
	}
	
	return self;
}

- bufferOn:sender
/*
 * Turn on keyboard buffering. Keystrokes are only sent when the "Flush" button is
 * pressed.
 */
{
	bufferKeystrokes = YES;
	
	return self;
}

- bufferOff:sender
/*
 * Turn off keyboard buffering. Keystrokes are sent as they arrive.
 */
{
	bufferKeystrokes = NO;
	
	return self;
}	

- chooseWindow:sender
{
	id winList, win;
	int i, count, localWindowNumber;
	
	selectedWindow = [[sender selectedCell] tag];
	switch (selectedWindow) {
	case NX_KEYWINDOW:
		[remoteView setWindow:[puppet keyWindow]];
		break;
	case NX_MAINWINDOW:
		[remoteView setWindow:[puppet mainWindow]];
		break;
	case NX_MAINMENU:
		[remoteView setWindow:[puppet mainMenu]];
		break;
	default:
		winList = [puppet windowList];
		count = [winList count];
		for (i=0; i<count; i++) {
			win = [winList objectAt:i];
			localWindowNumber = [win localWindowNumber];
			if (localWindowNumber == selectedWindow) {
				[remoteView setWindow:win];
				break;
			}
		}
		break;
	}
	
	return self;
}

- (int)selectedWindow
{
	return selectedWindow;
}

- (BOOL)printMouseClicks
{
	return printMouseClicks;
}

- printMouseClicks:sender
{
	printMouseClicks = !printMouseClicks;
	
	return self;
}
	
@end
