/*	LDRemoteControl.m  
	15 February 1993
	Eric Celeste / AppTech / 5 Exeter Street / Belmont, MA 02178
	efc@mit.edu
	Please send me any improvements.
	
	This object is designed to be instantiated in Interface Builder
	and connected to a whole bunch of controls. From that point on, it
	simply acts as a messanger for the LDPlayer that it creates.
	
	We also keep track of some "state" information here, since the 
	LDPlayers really don't bother. Once the LDPlayers have a status
	call implemented, getting the real status of the player might 
	replace some of this statekeeping (which can easily get out of 
	sync with the player anyway).
	
    ////////////////////////////////////////// History
	930210	efc  first cobbled together to test SonyLDP1450
	930213	efc  cleaned up to match new nib
	930215	efc  changed error reporting to a delegate task
*/
#import "LDRemoteControl.h"
#import "SonyLDP1450.h"

////////////////////////////////////////////// Private Defines
#define LD_NONE 0
/////// values for direction
	/*	we need to keep track of the direction of we are
		playing so that when the user switches the speed
		we can continue playing at the new speed in the
		same direction... see speed: below */
#define LD_FORWARD 1
#define LD_BACK 2
#define LD_STILL 3
/////// values for speed
	/*	We keep track of speed so that when the user switches
		direction on us, we can continue to play at the same
		speed we'd been playing... see forward: and back: below.
		These values correspond with tags in the nib... see
		speed: below for the use of these tags. */
#define LD_SCAN 4
#define LD_FAST 3
#define LD_SLOW 2
#define LD_FRAME 1
/////// values for format
	/*	Certain settings should be disabled during CLV playback... 
		These values correspond with tags in the nib...
		see setFormat: below */
#define LD_CAV 1
#define LD_CLV 0

////////////////////////////////////////////// Private Variables
id player;
BOOL allOK;
int direction = LD_STILL;
int format = LD_CLV;
int currentChapter = 0;
////////////////////////////////////////////// IMPLEMENTATION
@implementation LDRemoteControl
////////////////////////////////////////////// Private Methods
- currentFrameValid:(BOOL)yes
 {
 	if (yes) {
		[currentFrame setTextGray:NX_BLACK];
	} else {
 		[currentFrame setTextGray:NX_DKGRAY];
	}
	return self;
 }

- setFormat:(int)cav
 {
	[[speedChoice findCellWithTag:LD_FAST] setEnabled:cav];
	[[speedChoice findCellWithTag:LD_SLOW] setEnabled:cav];
	[[speedChoice findCellWithTag:LD_FRAME] setEnabled:cav];
	[pauseButton setEnabled:cav];
 	if (cav) {
		[firstFrame selectText:self];
	} else {
		[speedChoice selectCellWithTag:LD_SCAN];
		[chapter selectText:self];
	}
 	return self;
 }

- reportStatus:(const char *)string
 {
 	[self getCurrentFrame:self];
 	[message setSel:[message textLength] :0];
	[message replaceSel:"("];
	[message replaceSel:[currentFrame stringValue]];
	[message replaceSel:") "];
	[message replaceSel:string];
	[message replaceSel:"\n"];
 	[message scrollSelToVisible];
	return self;
 }

////////////////////////////////////////////// Target Methods
- back:sender
 {
	[self reportStatus:"Back"];
	direction = LD_BACK;
	[self currentFrameValid:NO];
	switch ([[speedChoice selectedCell] tag]) {
		case LD_SCAN:
			[player scanBack];
			break;
		case LD_FAST:
			[player fastBack];
			break;
		case LD_SLOW:
			[player slowBack];
			break;
		case LD_FRAME:
			[player frameBack];
			direction = LD_STILL;
			[self getCurrentFrame:self];
			break;
		default:
			[self reportStatus:"Unknown speed."];
	}
    return self;
 }

- channelOneToggle:sender
 {
 	BOOL on = (BOOL)[sender intValue];
	
	allOK = YES;
	[self reportStatus:"Toggling Channel 1"];	
	[player channelOne:on];
	if (!allOK) [sender setIntValue:(int)(!on)];
	return self;
 }

- channelTwoToggle:sender
 {
 	BOOL on = (BOOL)[sender intValue];
	
	allOK = YES;
	[self reportStatus:"Toggling Channel 2"];	
	[player channelTwo:on];
	if (!allOK) [sender setIntValue:(int)(!on)];
	return self;
 }

- chapterBack:sender
 {
 	allOK = YES;
	[self reportStatus:"Chapter Back"];
 	if (currentChapter > 1) {
		[player searchForChapter:(currentChapter-1)];
		if (allOK) [chapter setIntValue:(--currentChapter)];
	} else {
		[self reportStatus:"Already at Earliest Chapter"];
	}
	[chapter selectText:self];
	return self;
 }

- chapterForward:sender
 {
 	allOK = YES;
	[self reportStatus:"Chapter Forward"];
	[player searchForChapter:(currentChapter+1)];
 	if (allOK) [chapter setIntValue:(++currentChapter)];
	[chapter selectText:self];
	return self;
 }

- chapterJump:sender
 {
 	allOK = YES;
	[self reportStatus:"Chapter Jump"];
	[player searchForChapter:[chapter intValue]];
 	if (allOK) {
		currentChapter = [chapter intValue];
	} else {
		[chapter setIntValue:currentChapter];
	}
	[chapter selectText:self];
	return self;
 }

- eject:sender
 {
	[self reportStatus:"Ejecting"];
	[self currentFrameValid:NO];
	[player eject];
    return self;
 }

- forward:sender
 {
	[self reportStatus:"Forward"];
	direction = LD_FORWARD;
	[self currentFrameValid:NO];
	switch ([[speedChoice selectedCell] tag]) {
		case LD_SCAN:
			[player scanForward];
			break;
		case LD_FAST:
			[player fastForward];
			break;
		case LD_SLOW:
			[player slowForward];
			break;
		case LD_FRAME:
			[player frameForward];
			direction = LD_STILL;
			[self getCurrentFrame:self];
			break;
		default:
			[self reportStatus:"Unknown speed."];
	}
    return self;
 }

- frame:sender
 {
	allOK = YES;
    if ([repeats intValue]) {
		//// in this case we play a clip of the disc
		if ([repeats intValue] > 9) [repeats setIntValue:9];
		[self reportStatus:"Playing Clip"];
		[player 
			playFrom:[firstFrame intValue]
			to:[lastFrame intValue]
			repeating:[repeats intValue]
		];
		[lastFrame selectText:self];
	} else {
		//// in this case we just jump to a given frame
		[self reportStatus:"Jumping to Frame"];
		[player searchForFrame:[firstFrame intValue]];
		[firstFrame selectText:self];
	}
	return self;
 }

- getCurrentFrame:sender
 {
 	[currentFrame setIntValue:[player currentFrame]];
	[self currentFrameValid:(direction == LD_STILL)];
    return self;
 }

- indexToggle:sender
 {
 	BOOL on = (BOOL)[sender intValue];
	
	allOK = YES;
	[self reportStatus:"Toggling Index"];
	[player index:on];
	if (!allOK) [sender setIntValue:(int)(!on)];
	return self;
 }

- muteToggle:sender
 {
 	BOOL on = (BOOL)[sender intValue];
	
	allOK = YES;
	[self reportStatus:"Toggling Scan/Fast/Slow Mute"];
	[player mute:on];
	if (!allOK) [sender setIntValue:(int)(!on)];
	return self;
 }

- noiseReductionToggle:sender
 {
 	BOOL on  = (BOOL)[sender intValue];
	
	allOK = YES;
	[self reportStatus:"Toggling Noise Reduction"];
	[player noiseReduction:on];
	if (allOK) [sender setIntValue:(int)(!on)];
	return self;
 }

- openSerialPort:sender
 {
 	char myDevice[100];
	int myBaud;
	
	switch ([[serialChoice selectedCell] tag]) {
		case 1:
			strcpy(myDevice, "/dev/ttya");
			break;
		case 2:
			strcpy(myDevice, "/dev/ttyb");
			break;
		default:
			[self reportStatus:"Unknown Port"];
			return self;
	}
	
	switch ([[baudChoice selectedCell] tag]) {
		case 1:
			myBaud = B1200;
			break;
		case 2:
			myBaud = B2400;
			break;
		case 3:
			myBaud = B4800;
			break;
		case 4:
			myBaud = B9600;
			break;
		default:
			[self reportStatus:"Unknown Baud Rate"];
			return self;
	}
	
	switch ([[brandChoice selectedCell] tag]) {
		case 1:
 			[player free]; //// in case we already were talking to a player
		 	player = [[SonyLDP1450 alloc] initDevice:myDevice baud:myBaud];
			break;
		default:
			[self reportStatus:"Unknown Brand LDP"];
			return self;
	}
	
	if (player) {
		[player setDelegate:self];
	} else {
		NXRunAlertPanel(
			[NXApp appName],
			"Could not get the player connected!",
			"Sigh",NULL, NULL
		);
	}
 	return self;
 }

- pause:sender
 {
 	allOK = YES;
	[player still];
 	if (allOK) {
		[self reportStatus:"Pausing"];
		direction = LD_STILL;
		[self getCurrentFrame:self];
	}
    return self;
 }

- play:sender
 {
  	allOK = YES;
	[self reportStatus:"Playing"];
	[player playForward];
	if (allOK) {
		direction = LD_FORWARD;
		[self currentFrameValid:NO];
	}
    return self;
 }

- reset:sender
 {
 	[self setFormat:[[sender selectedCell] tag]];
	
	allOK = YES;
	[self reportStatus:"Reseting"];
	[player clearAll];
 	if (allOK) {
		[self getCurrentFrame:self];
	}
    return self;
 }

- speed:sender
 {
	switch (direction) {
		case LD_STILL:
			break;
		case LD_BACK:
			[self back:self];
			break;
		case LD_FORWARD:
		default:
			[self forward:self];
			break;
	}
    return self;
 }

- stop:sender
 {
 	allOK = YES;
	[self reportStatus:"Stoping"];
	[player halt];
 	if (allOK) {
		direction = LD_STILL;
		[self getCurrentFrame:self];
	}
    return self;
 }

////////////////////////////////////////////// Player Delegation
- ldpProblem:sender
 {
 	allOK = NO;
 	[self reportStatus:[sender problemString]];
 	return self;
 }

////////////////////////////////////////////// Application Delegation
- appDidInit:sender
 {
 	char verString[100];
	
	sprintf(verString, "%.4f", VER_DATE);
 	[version setStringValue:verString];
	
 	[self openSerialPort:self];
	[self setFormat:format];
 	return self;
 }
- appWillTerminate:sender
 {
 	[player free];
 	return self;
 }

@end
