
/* Generated by Interface Builder */

#import "ViscaController.h"
#import <appkit/Application.h>
#import <appkit/Form.h>
#import <appkit/TextField.h>
#import <appkit/Button.h>
#import <appkit/PopUpList.h>
#import <appkit/Panel.h>

@implementation ViscaController
void checkSelf(teNum, now, moi) 
DPSTimedEntry teNum;
double now;
id moi;
{
	[moi updateSelf];
	return;
}


void checkClock(teNum, now, moi) 
DPSTimedEntry teNum;
double now;
id moi;
{
	[moi clockInquiry: moi];
	return;
}

void checkPosition(teNum, now, moi) 
DPSTimedEntry teNum;
double now;
id moi;
{
	[moi positionInquiry: moi];
	return;
}

void checkMode(teNum, now, moi) 
DPSTimedEntry teNum;
double now;
id moi;
{
	[moi modeInquiry: moi];
	return;
}


unsigned char bcd( int val )
{	
	unsigned char tmp;
	
	tmp = (val / 10) * 0x10 +  (val % 10);
	
	fprintf(stderr," BCDing %d == %02X\n", val, tmp);
	return tmp;
}
	

- appDidInit: sender
{
	warnUser = YES;
	strcpy(errorMessage, ERRMSG_NOERROR );
	
	visca = [[VISCA alloc] init];
	
	[visca setPort: (char *) [portText stringValue]];
	[visca open];
	[visca setAddressBroadcastFrom: 0];
	[visca setWhenNow];
	[visca v_address];
	
	checkTE =    DPSAddTimedEntry(0.1, &checkSelf, self, 
		NX_MODALRESPTHRESHOLD);

	clockAuto = positionAuto = modeAuto = NO;
	[self clockAuto: self];
	[self positionAuto: self];
	[self modeAuto: self];

	[self perform: @selector( deviceInquiry: )
		with: self
		afterDelay: 100
		cancelPrevious: YES];
	[self perform: @selector( channelInquiry: )
		with: self
		afterDelay: 110
		cancelPrevious: YES];
	[self perform: @selector( editControlInquiry: )
		with: self
		afterDelay: 120
		cancelPrevious: YES];
	[self perform: @selector( mediaInquiry: )
		with: self
		afterDelay: 130
		cancelPrevious: YES];
	[self perform: @selector( inputSelectionInquiry: )
		with: self
		afterDelay: 130
		cancelPrevious: YES];
	[self perform: @selector( configureInquiry: )
		with: self
		afterDelay: 130
		cancelPrevious: YES];
	
	searchType = CT_HMS;
	return self;
	
}

- free
{
	fprintf(stderr, "Freeing!!!\n");
	[visca close];
	[visca free];
	DPSRemoveTimedEntry(checkTE);
	if( clockAuto )
		DPSRemoveTimedEntry(clockTE);
	return [super free];
}	

- updateSelf
{
	[visca readStatus];
	return self;
}
	
	
- clockInquiry: sender
{
	int reply;
	unsigned char completionMessage[128];
	static char time[20];
	
	reply = [visca md_interfaceInquiry: INQ_CLOCK];
	
	if( reply >= 100)
		{
		if(  [visca copyCompletionMessage: completionMessage] >= 6 )
			{
			sprintf(time, "%02X:%02X:%02X:%02X%01X",
				completionMessage[0],
				completionMessage[1],
				completionMessage[2],
				completionMessage[3],
				completionMessage[4],
				completionMessage[5]);
			[timeField setStringValue:time];
			}
				
		}
	
	return self;
}

	
- clockAuto: sender
{
	if( sender == clockRateText)
		{
		if( positionAuto)
			{
			DPSRemoveTimedEntry(clockTE);	
			clockTE =    DPSAddTimedEntry( 
				[clockRateText doubleValue], &checkClock, 
				self, NX_MODALRESPTHRESHOLD);
			}
		return self;
		}	
				
	if( [clockAutoButton state])
		{
		if( !clockAuto )
			{
			clockTE =    DPSAddTimedEntry( 
				[clockRateText doubleValue], &checkClock, 
				self, NX_MODALRESPTHRESHOLD);
			clockAuto = YES;
			}
		}
	else
		{
		if( clockAuto )
			{
			DPSRemoveTimedEntry(clockTE);	
			clockAuto = NO;
			}	
		}
		
	return self;
}


- positionInquiry: sender
{
	int reply, len;
	unsigned char completionMessage[128];
	static char counter[15];
	static char clock[15];
	
	reply = [visca md_positionInquiry];
	
	if( reply >= 100)
		{
		len = [visca copyCompletionMessage: completionMessage];
		
		if(  [visca copyCompletionMessage: completionMessage] >= 10 )
			{
			sprintf(counter, "%02X:%02X:%02X:%02X",
				completionMessage[1],
				completionMessage[2],
				completionMessage[3],
				completionMessage[4]);
			[positionCounterText setStringValue:counter];
			
			sprintf(clock, "%02X:%02X:%02X:%02X%01X",
				completionMessage[5],
				completionMessage[6],
				completionMessage[7],
				completionMessage[8],
				completionMessage[9]);
			[positionClockText setStringValue:clock];
			
			}
		}

	return self;
}

- positionAuto: sender
{
	if( sender == positionRateText)
		{
		if( positionAuto)
			{
			DPSRemoveTimedEntry( positionTE);	
			positionTE =    DPSAddTimedEntry( 
				[positionRateText doubleValue], &checkPosition, 
				self, NX_MODALRESPTHRESHOLD);
			}
		return self;
		}	
				
	if( [positionAutoButton state])
		{
		if( !positionAuto )
			{
			positionTE =    DPSAddTimedEntry( 
				[positionRateText doubleValue], &checkPosition, 
				self, NX_MODALRESPTHRESHOLD);
			positionAuto = YES;
			}
		}
	else
		{
		if( positionAuto )
			{
			DPSRemoveTimedEntry(positionTE);	
			positionAuto = NO;
			}	
		}
		
	return self;
}

- deviceInquiry: sender
{
	int reply, len;
	unsigned char completionMessage[128];
	static char dev[20];
	
	reply = [visca md_interfaceInquiry: INQ_DEVICETYPE];
	
	if( reply >= 100)
		{
		len = [visca copyCompletionMessage: completionMessage];

		sprintf(dev, "%02X %02X, %02X %02X, %02X %02X",
				completionMessage[0],
				completionMessage[1],
				completionMessage[2],
				completionMessage[3],
				completionMessage[4],
				completionMessage[5]);
		[deviceField setStringValue:dev];
		}

	return self;
}

- channelInquiry: sender
{
	int reply, len;
	unsigned char completionMessage[128];
	static char channel[20];
	
	reply = [visca md_channelInquiry];
	
	if( reply >= 100)
		{
		len = [visca copyCompletionMessage: completionMessage];

		sprintf(channel, "%01X%01X%01X",
				completionMessage[0],
				completionMessage[1],
				completionMessage[2]);
		[channelField setStringValue:channel];
		}

	return self;
}

- editControlInquiry: sender
{
	int reply, len;
	unsigned char completionMessage[128];
	static char control[20];
	
	reply = [visca md_editControlInquiry];
	
	if( reply >= 100)
		{
		len = [visca copyCompletionMessage: completionMessage];

		sprintf(control, completionMessage[0] == 0x00 ?
			"None" : "Type 1 Capability");
		[editControlField setStringValue:control];
		}

	return self;
}

- mediaInquiry: sender
{
	int reply, len;
	unsigned char completionMessage[128];
	static char media1[60], media2[60],
		 *tmp1, *tmp2, *tmp3, *tmp4, *tmp5, *tmp6;
	
	reply = [visca md_mediaInquiry];
	
	if( reply >= 100)
		{
		len = [visca copyCompletionMessage: completionMessage];

		switch( completionMessage[0] )
			{
			case 0x01:
				tmp1 = "8mm";
				break;
			case 0x02:
				tmp1 = "VHS";
				break;
			case 0x03:
				tmp1 = "S-VHS";
				break;
			case 0x41:
				tmp1 = "Hi-8";
				break;
			case 0x42:
				tmp1 = "S-VHS";
				break;
			case 0x43:
				tmp1 = "ED-Beta";
				break;
			default:
				tmp1 = "Unknown";
				break;
			}

		switch( completionMessage[1] )
			{
			case 0x01:
				tmp2 = "SP";
				break;
			case 0x02:
				tmp2 = "LP";
				break;
			case 0x03:
				tmp2 = "EP";
				break;
			default:
				tmp2 = "Unknown";
				break;
			}
			
		if( completionMessage[2] & 0x08 ) // bit 3
			tmp3 = "High Grade";
		else
			tmp3 = "Standard Grade";
			
		if( completionMessage[2] & 0x04 ) // bit 2
			tmp4 = "Thick";
		else
			tmp4 = "Thin";

		if( completionMessage[2] & 0x02 ) // bit 1
			tmp5 = "ME";
		else
			tmp5 = "MP";

		if( completionMessage[2] & 0x01 ) // bit 0
			tmp6 = " Playback Only";
		else
			tmp6 = "Recordable";

		sprintf(media1, "%s,  %s,  %s",
			tmp1, tmp2, tmp3);
		sprintf(media2, "%s,  %s,  %s",
			tmp4, tmp5, tmp6);
		
		[mediaField1 setStringValue: media1];
		[mediaField2 setStringValue: media2];
		}

	return self;
}

- inputSelectionInquiry: sender
{
	int reply, len;
	unsigned char completionMessage[128];
	static char output[20];
	static char *type[8] = { 	"Unrecognized",	// 0
					"Tuner",	// 1
					"Unrecognized",	// 2
					"Line",		// 3
					"Unrecognized",	// 4
					"Unrecognized",	// 5
					"Unrecognized",	// 6
					"Other"};	// 7
	
	reply = [visca md_inputSelectInquiry];
	
	if( reply >= 100)
		{
		len = [visca copyCompletionMessage: completionMessage];

		sprintf(output, "Video == %s;  Audio == %s",
			type[ completionMessage[0]],
			type[ completionMessage[1]]);
			
		[inputSelectionField setStringValue:output];
		}

	return self;
}



- configureInquiry: sender;
{
	int reply, len;
	unsigned char completionMessage[128];
	static char output[60], *tmp1;
	
	reply = [visca md_configureInquiry];
	
	if( reply >= 100)
		{
		len = [visca copyCompletionMessage: completionMessage];

		switch( completionMessage[2] )
			{
			case 0x00:
				tmp1 = "None";
				break;
			case 0x01:
				tmp1 = "Synchronous";
				break;
			case 0x02:
				tmp1 = "F500";
				break;
			default:
				tmp1 = "Unknown";
				break;
			}
		sprintf(output, "%02X fps;  %s;  %s",
			completionMessage[0],
			completionMessage[1] == 0x01 ? "NTSC" : "Unknown",
			tmp1);	
		[configureField setStringValue:output];
		}
	return self;
}



- modeInquiry: sender
{
	int reply;
	unsigned char completionMessage[128];
	static char mode[20];
	
	reply = [visca md_modeInquiry];

	[self disableFlushWindow];
	
	[stopButton setState: NO];
	[rewindButton setState: NO];
	[fastForwardButton setState: NO];
	[ejectButton setState: NO];
	[pauseButton setState: NO];
	[playButton setState: NO];
	[recordButton setState: NO];

	if( reply >= 100)
		{
		[visca copyCompletionMessage: completionMessage];
		
		switch( completionMessage[0] )
			{
			case 0x00:
				sprintf(mode, "Stop");
				[stopButton setState: YES];
				break;
			case 0x02:
				sprintf(mode, "Stop -- tape top");
				[stopButton setState: YES];
				break;
			case 0x04:
				sprintf(mode, "Stop -- tape end");
				[stopButton setState: YES];
				break;
			case 0x06:
				sprintf(mode, "Stop -- emergency");
				[stopButton setState: YES];
				break;
			case 0x08:
				sprintf(mode, "Fast Forward");
				[fastForwardButton setState: YES];
				break;
			case 0x10:
				sprintf(mode, "Rewind");
				[rewindButton setState: YES];
				break;
			case 0x18:
				sprintf(mode, "Eject");
				[ejectButton setState: YES];
				break;
			case 0x20:
				sprintf(mode, "Slow 2");
				[playButton setState: YES];
				[pauseButton setState: YES];
				break;
			case 0x24:
				sprintf(mode, "Pause");
				[playButton setState: YES];
				[pauseButton setState: YES];
				break;

			case 0x28:
				sprintf(mode, "Play");
				[playButton setState: YES];
				break;
			case 0x2E:
				sprintf(mode, "Cue");
				[playButton setState: YES];
				[fastForwardButton setState: YES];
				break;
			case 0x3E:
				sprintf(mode, "Review");
				[playButton setState: YES];
				[rewindButton setState: YES];
				break;
			case 0x48:
				sprintf(mode, "Record");
				[recordButton setState: YES];
				break;
			default:
				sprintf(mode, "Unrecognized: %02X",
					 completionMessage[0]);
			}
		[modeText setStringValue: mode];
			
		}

	reply = [visca md_powerInquiry];
	
	if( reply >= 100 )
		{
		[visca copyCompletionMessage: completionMessage];
		switch( completionMessage[0]  )
			{
			case 0x02:
				[powerButton setState: YES];
				break;
			case 0x03:
				[powerButton setState: NO];
				break;
			default:
				fprintf(stderr,"Unrecognized power "
					"setting %d\n", completionMessage[0]);
				break;
			}
		}


	[self reenableFlushWindow];
	[self flushWindowIfNeeded];
	
	return self;
}

	
- modeAuto: sender
{
	if( sender == modeRateText )
		{
		if( modeAuto)
			{
			DPSRemoveTimedEntry(modeTE);	
			modeTE =    DPSAddTimedEntry( 
				[modeRateText doubleValue], &checkMode, 
				self, NX_MODALRESPTHRESHOLD);
			}
		return self;
		}	
				
	if( [modeAutoButton state])
		{
		if( !modeAuto )
			{
			modeTE =    DPSAddTimedEntry( 
				[modeRateText doubleValue], &checkMode, 
				self, NX_MODALRESPTHRESHOLD);
			modeAuto = YES;
			}
		}
	else
		{
		if( modeAuto )
			{
			DPSRemoveTimedEntry(modeTE);	
			clockAuto = NO;
			}	
		}
		
	return self;
}






- deviceChanged: sender
{
	return self;
}	
	
	
- pause:sender
{
	[sender setState: YES];
	[visca md_modeControl_1: MC1_PAUSE];
    return self;
}

- eject:sender
{
	[sender setState: YES];
	[visca md_modeControl_1: MC1_EJECT];
    return self;
}

- play:sender
{
	[sender setState: YES];
	[visca md_modeControl_1: MC1_PLAY];
    return self;
}

- stop:sender
{
 	[sender setState: YES];
	[visca md_modeControl_1: MC1_STOP];
   return self;
}

- power:sender
{
	[visca md_power: [sender state] ? POWER_ON: POWER_OFF];
    return self;
}

- record:sender
{
	[sender setState: YES];
 	[visca md_modeControl_1: MC1_RECORD];
    return self;
}

- fast_forward:sender
{
 	[sender setState: YES];
 	[visca md_modeControl_1: MC1_FAST_FORWARD];
   return self;
}

- rewind:sender
{
	[sender setState: YES];
  	[visca md_modeControl_1: MC1_REWIND];
    return self;
}

- search: sender
{
	union counterType pos;
	
	pos.hmsf.hh = bcd( [searchFields intValueAt: 0] );
	pos.hmsf.mm = bcd( [searchFields intValueAt: 1] );
	pos.hmsf.ss = bcd( [searchFields intValueAt: 2] );
	pos.hmsf.ff = bcd( [searchFields intValueAt: 3] );;
	[visca md_search:searchType counter: &pos];
	
	return self;
}


- searchTypeChanged: sender
{
	switch( [[sender selectedCell] tag] )
		{
		case 0:	// Top-Mid-end
			fprintf(stderr,"search -- tme\n");
			searchType = CT_TME;
			break; 
		case 1: // hms
			fprintf(stderr,"search -- hms\n");
			searchType = CT_HMS;
			break;
		case 2: // hmsf
			fprintf(stderr,"search -- hmsf\n");
			searchType = CT_HMSF;
			break;
		case 3: // time-code
			fprintf(stderr,"search -- timecode\n");
			searchType = CT_TIMECODE;
			break;
		default:
			NXRunAlertPanel("Not recognized", "Search "
				"tag no recognized. Contacter developer",
				"OK", NULL, NULL);
			break;
		}
	
	return self;
}


- zoomIn: sender
{
	status = [visca md_cameraZoom: (int) ZOOM_TELE];
	if( status == CMD_ERROR )
		return [self handleError];
	else
		return self;
}



- zoomOut: sender
{
	status = [visca md_cameraZoom: (int) ZOOM_WIDE];
	if( status == CMD_ERROR )
		return [self handleError];
	else
		return self;
	return self;
}

- focusNear: sender
{
	status = [visca md_cameraFocus: (int) FOCUS_NEAR];
	if( status == CMD_ERROR )
		return [self handleError];
	else
		return self;
	return self;
}

- focusFar: sender
{
	status = [visca md_cameraFocus: (int) FOCUS_FAR];
	if( status == CMD_ERROR )
		return [self handleError];
	else
		return self;
}

- zoomFocusStop: sender
{

	status = [visca md_cameraFocus: (int) FOCUS_STOP];
	if( status == CMD_ERROR )
		return [self handleError];
	status = [visca md_cameraZoom: (int) ZOOM_STOP];
	if( status == CMD_ERROR )
		return [self handleError];
	else
		return self;
}

- frameForward: sender
{
	status = [visca md_modeControl_2:  MC2_FRAME_FORWARD];
	if( status == CMD_ERROR )
		return [self handleError];
	else
		return self;
}
	
- frameReverse: sender
{
	status = [visca md_modeControl_2:  MC2_FRAME_REVERSE];
	if( status == CMD_ERROR )
		return [self handleError];
	else
		return self;
}


- resetCounter: sender
{
	status = [visca md_subControl:  SC_COUNTER_RESET];
	if( status == CMD_ERROR )
		return [self handleError];
	else
		return self;
}
	
- realCounterMode: sender
{
	status = [visca md_subControl:  SC_REAL_COUNTER];
	if( status == CMD_ERROR )
		return [self handleError];
	else
		return self;
}

- relativeCounterMode: sender
{
	status = [visca md_subControl:  SC_RELATIVE_COUNTER];
	if( status == CMD_ERROR )
		return [self handleError];
	else
		return self;
}

- toggleAudio: sender
{
	status = [visca md_subControl:  SC_TOGGLE_AUDIO];
	if( status == CMD_ERROR )
		return [self handleError];
	else
		return self;
}

- toggleSpeed: sender
{
	status = [visca md_subControl:  SC_TOGGLE_SPEED];
	if( status == CMD_ERROR )
		return [self handleError];
	else
		return self;
}

- toggleDisplay: sender
{
	status = [visca md_subControl:  SC_TOGGLE_DISPLAY];
	if( status == CMD_ERROR )
		return [self handleError];
	else
		return self;
}


- cycleVideo: sender
{
	status = [visca md_subControl:  SC_CYCLE_VIDEO_IN];
	if( status == CMD_ERROR )
		return [self handleError];
	else
		return self;
}

- handleError
{
	static char warnMessage[256];
	
	if( status != CMD_ERROR  )
		return self;
	
	errorCode = [visca errorCode];
	
	fprintf(stderr,"handleError: Error code = %02Xh.\n",
		errorCode);

	switch( errorCode )
		{	
		case 0x01:
			strcpy(errorMessage,"Message len error");
			break;
		case 0x02:
			strcpy(errorMessage,"Syntax error");
			break;
		case 0x03:
			strcpy(errorMessage,"Command buffer full");
			break;
		case 0x04:
			strcpy(errorMessage,"Command Cancelled");
			break;
		case 0x05:
			strcpy(errorMessage,"No socket");
			break;
		case ERROR_POWER:
			strcpy(errorMessage, ERRMSG_POWER);
			break;
		case ERROR_TIMEOUT:
			strcpy(errorMessage, ERRMSG_TIMEOUT);
			break;
		case ERROR_SEARCH:
			strcpy(errorMessage, ERRMSG_SEARCH);
			break;
		case ERROR_CONDITION:
			strcpy(errorMessage, ERRMSG_CONDITION);
			break;
		case ERROR_CAMERAMODE:
			strcpy(errorMessage, ERRMSG_CAMERAMODE);
			break;
		case ERROR_VCRMODE:
			strcpy(errorMessage, ERRMSG_VCRMODE);
			break;
		case ERROR_COUNTERTYPE:
			strcpy(errorMessage, ERRMSG_COUNTERTYPE);
			break;
		case ERROR_TUNER:
			strcpy(errorMessage, ERRMSG_TUNER);
			break;
		case ERROR_EMERGENCYSTOP:
			strcpy(errorMessage, ERRMSG_EMERGENCYSTOP);
			break;
		case ERROR_NOMEDIA:
			strcpy(errorMessage, ERRMSG_NOMEDIA);
			break;
		}			
		 	
	sprintf(warnMessage,"Error %02Xh in socket %d ==> %s\n",
		errorCode, [visca socket], errorMessage);
	
	NXRunAlertPanel( "Error occured", warnMessage, "OK", NULL, NULL);

	return self;
		
}

@end
