//  Created by Allen Ingling on Wed Mar 31 2004.
//  Copyright (c) 2004 New York University. All rights reserved.


/*
notes:

- The QuickDraw port created from the Core Graphics display using is only valide within the scope of the thread which creates it

*/


#import "HipsViewer.h"
#include <unistd.h>						//for usleep()
#include <CoreAudio/CoreAudio.h>		//for AudioGetCurrentHostTime()
#include <hipl_format.h>				//for HIPS
#include "ExternHIPS.h"					//for HIPS
#include "HipsHelpers.h"
#include "PrecisionTime.h"
#import  "CharTime.h"
#import  "KeyRecorderWindow.h"
#import  "PlayMovie.h"


@implementation HipsViewer
//____________________________________________________________________________________________________
//controls, except for openFileFromStdInput)


- (IBAction)frameSlider:(id)sender
{
	if(!threadLock){
		currentFrameNumber=[sender intValue]-1;
		[frameNumberTextOutlet setIntValue:currentFrameNumber+1];
		[self blitFrame];
	}else
		goMovieFlag=FALSE;
}


- (IBAction)openFile:(id)sender
{
	NSOpenPanel				*fileDialog;
	int						didUserGiveFilename;
	NSArray					*fileNameArray;
//	NSRect					movieRect;
	ScaleModeType			scaleMode;
	long					swapIntervalFrames;

//	NSAssert(hipsMovie==NULL, @"Attempt to open a new movie when one is already open.");
	fileDialog=[NSOpenPanel openPanel];
	[fileDialog setAllowsMultipleSelection:FALSE];
	[fileDialog setCanChooseFiles:TRUE];
	[fileDialog setCanChooseDirectories:FALSE];
	[fileDialog setResolvesAliases:TRUE];
	didUserGiveFilename=[fileDialog runModalForTypes:nil];
	//didUserGiveFilename=[fileDialog runModalForTypes:[NSArray arrayWithObject:@"hmv"]];
	if(didUserGiveFilename==NSOKButton){
		//get rid of the old movie object if it exists
		[self closeAllOpenStuff];
		//load the file
		fileNameArray=[fileDialog filenames];
		NSAssert([fileNameArray count] == 1, @"Missing file name");
		hipsMovie=[[HipsMovie alloc] init];
		[hipsMovie enableProgressBars:self window:progressWindow  bar:progressBar text:progressText];
		[hipsMovie loadFloatFramesBufferFromHipsFile:[fileNameArray objectAtIndex:0]];
		scaleMode=[self getScaleModeFromButtons];
		//Prepare both 8 and 32-bit frames.  We always use 32-bit textures for the NSOpenGL view embedded into the 
		// preview window because A) We are not much concerned about missing video frames when previewing and
		// B) The desktop is amost always in 32-bit mode and changing that would to 8-bit mode would be a nuisance for the user.
		// For fullscreen mode we prefer, for reasons of blit speed, 8-bit depth for black&white movies.
		[hipsMovie load8BitTexturesFromHipsFloatFrames:scaleMode];
		[hipsMovie load32BitTexturesFromHipsFloatFrames:scaleMode];
		if(fullscreenNSGLContext==nil){
			//set 8-bit mode flag, resize the preview window, set the  flip interval 
			use8BitMode=FALSE;
			[self setupPreviewWindow];
			[hipsMovie instantiate32BitTexturesIntoNSGLContext:previewNSGLContext frameSize:previewNSGLContextRect];
			[hipsMovie blitFrame32:currentFrameNumber];
			[previewNSGLContext makeCurrentContext];
			swapIntervalFrames=1;
			[previewNSGLContext setValues:&swapIntervalFrames forParameter:NSOpenGLCPSwapInterval];
			[previewNSGLContext update];
		}else{
			//instantiate the texture into the fullscreen window
			use8BitMode= ![hipsMovie getMovieColorFlag];
			if(use8BitMode){
				[hipsMovie instantiate8BitTexturesIntoNSGLContext:fullscreenNSGLContext frameSize:fullscreenNSGLContextRect];
				[hipsMovie blitFrame8:currentFrameNumber];
			}else{
				[hipsMovie instantiate32BitTexturesIntoNSGLContext:fullscreenNSGLContext frameSize:fullscreenNSGLContextRect];
				[hipsMovie blitFrame32:currentFrameNumber];
			}
		}
		//activiate the ui movie controls now that there is a movie to control.
		[self enableIntrinsicMovieControls];
		[self enableExternalMovieControls];
		[self enableBackgroundRadioButtons];
	}
}


- (void) openFileFromStdInput
{

//	NSRect  movieRect;
	BOOL				isMovieColor;
	ScaleModeType		scaleMode;
	int					numDisplays;
	int					middleDisplayNumber, lastDisplayNumber;
//	id					foo;
	long				swapIntervalFrames;

	
	NSAssert(hipsMovie==NULL, @"Attempt to open a new movie when one is already open.");
	
	enableInterfaceCoupling=FALSE;		//so we can set UI controls to match command line parameters without invoking the commands which those controls normally issue.
	hipsMovie=[[HipsMovie alloc] init];
	[hipsMovie enableProgressBars:self window:progressWindow  bar:progressBar text:progressText];
	[hipsMovie loadFloatFramesBufferFromHipsFile:[NSString stringWithCString:commandFlags.fileName]];
	isMovieColor=[hipsMovie getMovieColorFlag];
	scaleMode=[self getScaleModeFromButtons];
	//enable the control panels
	[self enableIntrinsicMovieControls];
	[self enableExternalMovieControls];
	[self enableBackgroundRadioButtons];
	//set the display number indicated by the input parameters
	numDisplays=[screenNumberMenuOutlet numberOfItems]-1;  //not sure where the where the extra entry comes from.  Maybe the first entry is the name of the menu itself.
	NSAssert(!(commandFlags.displayNumberPresent && commandFlags.displayNamePresent), @"Unexpected failure of mutex enforcement on command flags");
	if(commandFlags.displayNumberPresent){
		//passively ignore display numbers outside of bounds
		if(commandFlags.displayNumber < 0) 
			commandFlags.displayNumber=0;
		if(commandFlags.displayNumber > numDisplays-1)
			commandFlags.displayNumber= numDisplays-1;
		[screenNumberMenuOutlet selectItemAtIndex:commandFlags.displayNumber+1];
	}
	if(commandFlags.displayNamePresent){
		lastDisplayNumber=numDisplays-1;
		middleDisplayNumber= numDisplays==1 ? 0 : lastDisplayNumber - 1;
		if(!strcmp(commandFlags.displayName, "first"))
			commandFlags.displayNumber=0;
		else if(!strcmp(commandFlags.displayName, "middle"))
			commandFlags.displayNumber=middleDisplayNumber;
		else if(!strcmp(commandFlags.displayName, "last"))
			commandFlags.displayNumber=lastDisplayNumber;
		else
			commandFlags.displayNumber=0;
		[screenNumberMenuOutlet selectItemAtIndex:commandFlags.displayNumber+1];
	}
	[self populateDisplayModeMenu];
	//set the palindrome switch 
	if(commandFlags.palindromeFlag){
		[palindromeSwitchOutlet setState:NSOnState];
	}
	//set the continuous play switch
	if(commandFlags.continuousFlag){
		[loopSwitchOutlet setState:NSOnState];
		if(commandFlags.numberOfLoops > 0)
			limitNumLoopPasses=commandFlags.numberOfLoops;
		else
			limitNumLoopPasses=0;  
	}
	//set the play direction
	NSAssert(!(commandFlags.forwardFlag && commandFlags.reverseFlag),  @"Unexpected failure of mutex enforcement on command flags");
	frameIncrement=1;
	if(commandFlags.reverseFlag){
		frameIncrement=-1;
		if(limitNumLoopPasses)			// hack 
			++limitNumLoopPasses;		// hack
	}
	//set the terminate after play flag
	if(commandFlags.terminateFlag)
		exitAfterPlay=TRUE;
	//open the movie onto the display
	[hipsMovie load8BitTexturesFromHipsFloatFrames:scaleMode];
	[hipsMovie load32BitTexturesFromHipsFloatFrames:scaleMode];
	if(!commandFlags.usePreviewWindowFlag){
	//use fullscreen window
		if(isMovieColor){
			use8BitMode=FALSE;
			[fullscreenButtonOutlet setState:NSOnState];
			[self fullscreenCreateOrDestroy:TRUE];
			[hipsMovie instantiate32BitTexturesIntoNSGLContext:fullscreenNSGLContext frameSize:fullscreenNSGLContextRect];
			[hipsMovie blitFrame32:currentFrameNumber];
		} else {
			use8BitMode=TRUE;
			[fullscreenButtonOutlet setState:NSOnState];
			[self fullscreenCreateOrDestroy:TRUE];
			[hipsMovie instantiate8BitTexturesIntoNSGLContext:fullscreenNSGLContext frameSize:fullscreenNSGLContextRect];
			[hipsMovie blitFrame8:currentFrameNumber];
		}
		//set the background color
		if(commandFlags.backgroundPresent){
			if(!strcmp(commandFlags.backgroundColorName, "black")){
				[backgroundColorBlackButtonOutlet setState:NSOnState];
				[self setBackgroundColor:khpsBackgroundBlack blit:TRUE];
			}else if(!strcmp(commandFlags.backgroundColorName, "white")){
				[backgroundColorWhiteButtonOutlet setState:NSOnState];
				[self setBackgroundColor:khpsBackgroundWhite blit:TRUE];
			}else if(!strcmp(commandFlags.backgroundColorName, "gray")){
				[backgroundColorMidgrayButtonOutlet setState:NSOnState];
				[self setBackgroundColor:khpsBackgroundMidgray blit:TRUE];
			}else if(!strcmp(commandFlags.backgroundColorName, "mean")){
				[backgroundColorMeanButtonOutlet setState:NSOnState];
				[self setBackgroundColor:khpsBackgroundMean blit:TRUE];
			}else if(!strcmp(commandFlags.backgroundColorName, "edgemean")){
				[backgroundColorEdgeMeanButtonOutlet setState:NSOnState];
				[self setBackgroundColor:khpsBackgroundEdgeMean blit:TRUE];
			}
		}
	}else{
	//use preview window
		use8BitMode=FALSE;
		[self setupPreviewWindow];
		[hipsMovie instantiate32BitTexturesIntoNSGLContext:previewNSGLContext frameSize:previewNSGLContextRect];
		[hipsMovie blitFrame32:currentFrameNumber];
		[previewNSGLContext makeCurrentContext];
		swapIntervalFrames=1;
		[previewNSGLContext setValues:&swapIntervalFrames forParameter:NSOpenGLCPSwapInterval];
		[previewNSGLContext update];
	}
	
	//setup the control panel window to gather key presses
	[controlPanelWindowOutlet makeKeyAndOrderFront:self];
	if(commandFlags.getKeysFlag){
		[frameNumberTextOutlet setEnabled:FALSE];
		[controlPanelWindowOutlet makeFirstResponder:controlPanelWindowOutlet];
		recordKeysFlag=TRUE;
		[controlPanelWindowOutlet startQueue];
	}

	//restore coupling of UI controls to viewer actions
	enableInterfaceCoupling=TRUE;
	//play the movie forward
	frameIncrement=1;
	[hipsMovie waitForBlank];
//	goMovieFlag=TRUE;
	threadLock=FALSE;					//setting this to TRUE disables the buttons on the player.
	goMovieFlag=TRUE;
	//The reference to the player is set by the callback from the player to the viewer.   The callback is executed asynchronously by the player thread's event loop.
	//The player my not have been created yet, so test periodicaly until the player pointer is set then launch the movie.     
	autoRunTimer= [NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval)0.20 target:self selector:@selector(startAutoPlay) userInfo:nil repeats:TRUE];
}

- (void) startAutoPlay
{	
	if(player!=nil){
		//defers priority elevation until immediatly prior to play and lowers immediatly after.  raise prioririty for both viewer and player threads.
		[player activateRealtimeDeferred:TRUE];
		[player play:self];
		[autoRunTimer invalidate]; 
	}
}


//only invoked in command line mode so we may refer to commandFlags structure fields without first testing.
- (void) printKeysAndExit
{
	NSMutableArray				*keyQueue;
	const char					*keyCString;
	double						timeStamp;
	int							i, queueLength;
	CharTime					*charTime;
	NSMutableString				*keyString;

	[controlPanelWindowOutlet stopQueue];
	keyQueue=[[controlPanelWindowOutlet getQueue] retain];
	queueLength=(int)[keyQueue count];
	printf("%d keys:\n\n", queueLength);
	for(i=0;i<queueLength;i++){
		charTime=[keyQueue objectAtIndex:(unsigned)i];
		keyString=[charTime getKeyString];
		keyCString=[keyString UTF8String];
		timeStamp=(double)[charTime getTimeStamp];
		printf("char: %s\ttime: %f\n", keyCString, timeStamp);
	}
	[keyQueue release];
		
	if(exitAfterPlay)
		[NSApp terminate:self];
}


- (IBAction)displayKeypressListButton:(id)sender
{
	NSMutableArray				*keyQueue;
	const char					*keyCString;
	double						timeStamp;
	int							i, queueLength;
	CharTime					*charTime;
	NSMutableString				*keyString;

	[controlPanelWindowOutlet stopQueue];
	keyQueue=[controlPanelWindowOutlet getQueue];
	[keyQueue retain];
	queueLength=(int)[keyQueue count];
	printf("%d keys:\n\n", queueLength);
	for(i=0;i<queueLength;i++){
		charTime=[keyQueue objectAtIndex:(unsigned)i];
		keyString=[charTime getKeyString];
		keyCString=[keyString UTF8String];
		timeStamp=(double)[charTime getTimeStamp];
		printf("char: %s\ttime: %f\n", keyCString, timeStamp);
	}
	[keyQueue release];
}



/*                                                             *  
 * Old version of movie play controls changed in version 0.8   *	
 *                                                             *

- (IBAction)pause:(id)sender
{
	goMovieFlag=FALSE;
}


- (IBAction)playForward:(id)sender
{
	if(enableInterfaceCoupling){
		if([sender state]==NSOnState){
			if(!threadLock){
				threadLock=TRUE;
				frameIncrement=1;
				[hipsMovie waitForBlank];
				goMovieFlag=TRUE;
				[player play:self];
				//[player playTest:self];
			}else{
				if(frameIncrement==-1 && [palindromeSwitchOutlet state]!=NSOnState) 
					frameIncrement=1;
				else goMovieFlag=FALSE;
			}
		}
	}
}


- (IBAction)playBack:(id)sender
{
	if([sender state]==NSOnState){
		if(!threadLock){
			threadLock=TRUE;
			frameIncrement=-1;
			[hipsMovie waitForBlank];
			goMovieFlag=TRUE;
			[player play:self];
			//[player playTest:self];
		}else{
			if(frameIncrement==1 && [palindromeSwitchOutlet state]!=NSOnState) 
				frameIncrement= -1;
			else goMovieFlag=FALSE;	
		}
	}
}


- (IBAction)playOrLoop:(id)sender
{
}


- (IBAction)stepForward:(id)sender
{
	int x;
	
	x=[hipsMovie getNumFrames];
	
	if([sender state]==NSOnState){
		if(!threadLock){
			if([loopNotPlayRadioOutlet state]==NSOnState)
				currentFrameNumber=(currentFrameNumber+1) % ([hipsMovie getNumFrames] - 1);
			else{
				if(currentFrameNumber+1 >= [hipsMovie getNumFrames]){
					[sliderBoundsAlertSound play];
					currentFrameNumber=[hipsMovie getNumFrames] -1;
				}else
					currentFrameNumber=currentFrameNumber+1;
			}
			[frameSliderOutlet setIntValue:currentFrameNumber+1];
			[frameNumberTextOutlet setIntValue:currentFrameNumber+1];
			[self blitFrame];
		}else
			goMovieFlag=FALSE;
	}
}


- (IBAction)stepBack:(id)sender
{

	if([sender state]==NSOnState){
		if(!threadLock){
			if([loopNotPlayRadioOutlet state]==NSOnState){
				if(currentFrameNumber == 0) 
					currentFrameNumber=[hipsMovie getNumFrames];
				else
					currentFrameNumber=currentFrameNumber-1;
			}else{
				if(currentFrameNumber <= 0){
					currentFrameNumber=0;
					[sliderBoundsAlertSound play];
				}else
					currentFrameNumber=currentFrameNumber-1;
			}
			[frameSliderOutlet setIntValue:currentFrameNumber + 1];
			[frameNumberTextOutlet setIntValue:currentFrameNumber+ 1];
			[self blitFrame];
		}else
			goMovieFlag=FALSE;
	}
}


- (IBAction)playNotLoopRadio:(id)sender
{
	//we don't need to do anything here.  The loop-or-play radio button is defined
	//as an outlet.  The button maintains its own state which we query via the outlet.
}

- (IBAction)loopNotPlayRadio:(id)sender
{
	//we don't need to do anything here.  The loop-or-play radio button is defined
	//as an outlet.  The button maintains its own state which we query via the outlet.
}

- (IBAction)palindromeSwitch:(id)sender
{
	if(enableInterfaceCoupling)
		palindromeBounceFlag=[sender state]==NSOnState;
}


*/

// ***** BEGIN new movie controls for version 0.8 *****

//player buttons

- (IBAction)stepToEndButtonAction:(id)sender
{
	if([sender state]==NSOnState){
		if(!threadLock){
			currentFrameNumber=[hipsMovie getNumFrames] -1;
			[frameSliderOutlet setIntValue:currentFrameNumber+1];
			[frameNumberTextOutlet setIntValue:currentFrameNumber+1];
			[self blitFrame];
		}else
			goMovieFlag=FALSE;
		[sender setState:NSOffState];
	}
}


- (IBAction)stepToStartButtonAction:(id)sender
{
	if([sender state]==NSOnState){
		if(!threadLock){
			currentFrameNumber=0;
			[frameSliderOutlet setIntValue:currentFrameNumber+1];
			[frameNumberTextOutlet setIntValue:currentFrameNumber+1];
			[self blitFrame];
		}else
			goMovieFlag=FALSE;
		[sender setState:NSOffState];
	}


}


- (IBAction)playOrPauseButtonAction:(id)sender
{
	if(enableInterfaceCoupling){
		if([sender state]==NSOnState){
			if(!threadLock){
				threadLock=TRUE;
				if([reverseSwitchOutlet state]==NSOnState)
					frameIncrement=-1;
				else
					frameIncrement=1;
				[hipsMovie waitForBlank];
				goMovieFlag=TRUE;
				[player play:self];
				//[player playTest:self];
			}
		}else  //user toggled the button off
			goMovieFlag=FALSE;
	
	}
}


- (IBAction)stepBackwardButtonAction:(id)sender
{
	if([sender state]==NSOnState){
		if(!threadLock){
			if([loopSwitchOutlet state]==NSOnState){
				if(currentFrameNumber == 0) 
					currentFrameNumber=[hipsMovie getNumFrames];
				else
					currentFrameNumber=currentFrameNumber-1;
			}else{
				if(currentFrameNumber <= 0){
					currentFrameNumber=0;
					[sliderBoundsAlertSound play];
				}else
					currentFrameNumber=currentFrameNumber-1;
			}
			[frameSliderOutlet setIntValue:currentFrameNumber + 1];
			[frameNumberTextOutlet setIntValue:currentFrameNumber+ 1];
			[self blitFrame];
		}else
			goMovieFlag=FALSE;
		[sender setState:NSOffState];
	}
}


- (IBAction)stepForwardButtonAction:(id)sender
{
	if([sender state]==NSOnState){
		if(!threadLock){
			if([loopSwitchOutlet state]==NSOnState)
				currentFrameNumber=(currentFrameNumber+1) % ([hipsMovie getNumFrames] - 1);
			else{
				if(currentFrameNumber+1 >= [hipsMovie getNumFrames]){
					[sliderBoundsAlertSound play];
					currentFrameNumber=[hipsMovie getNumFrames] -1;
				}else
					currentFrameNumber=currentFrameNumber+1;
			}
			[frameSliderOutlet setIntValue:currentFrameNumber+1];
			[frameNumberTextOutlet setIntValue:currentFrameNumber+1];
			[self blitFrame];
		}else
			goMovieFlag=FALSE;
		[sender setState:NSOffState];
	}

}

// switches 

- (IBAction)reverseSwitchAction:(id)sender
{
}

- (IBAction)loopSwitchAction:(id)sender
{
}

- (IBAction)palindromeSwitchAction:(id)sender
{
	if(enableInterfaceCoupling)
		palindromeBounceFlag=[sender state]==NSOnState;
}


// ***** END new movie controls for version 0.8 *****
	
- (IBAction)quitButton:(id)sender
{
	[NSApp terminate:self];
}


- (IBAction)viewHeader:(id)sender
{
	[headerWindow orderFront:self];
	[headerTextView	setString:[hipsMovie getHeaderString]];
	
}



- (IBAction)scaleLEnable:(id)sender
{
	ScaleModeType   clampState;

	if([sender state] == NSOnState){
		[self enableScalingSwitches];
		if([scaleLClampToZeroRadioOutlet state] == NSOnState)
			clampState=khpsClampToZero;
		else if([scaleLClampToMeanRadioOutlet state] == NSOnState)
			clampState=khpsClampToMean;
		else if([scaleLFloatingZeroRadioOutlet state] == NSOnState)
			clampState=khpsFloat;
	}else{
		[self disableScalingSwitches];
		clampState=khpsNoScale;
	}
	[hipsMovie load32BitTexturesFromHipsFloatFrames:clampState];
	[self blitFrame];
}

- (IBAction)scaleLClampToZeroRadio:(id)sender
{
	[hipsMovie load32BitTexturesFromHipsFloatFrames:khpsClampToZero];
	[self blitFrame];
}

- (IBAction)scaleLClampToMeanRadio:(id)sender
{
	[hipsMovie load32BitTexturesFromHipsFloatFrames:khpsClampToMean];
	[self blitFrame];
}

- (IBAction)scaleLFloatingZeroRadio:(id)sender
{
	[hipsMovie load32BitTexturesFromHipsFloatFrames:khpsFloat];
	[self blitFrame];
}


- (IBAction)frameNumberText:(id)sender
{
	int		inputNumber;
	
	inputNumber=[sender intValue];
	if(inputNumber<1){
		currentFrameNumber=0;
		[sender setIntValue:currentFrameNumber+1];
	}else if(inputNumber > [hipsMovie getNumFrames]){
		currentFrameNumber= [hipsMovie getNumFrames]-1;
		[sender setIntValue:currentFrameNumber+1];
	}else
		currentFrameNumber=inputNumber-1;
	[frameSliderOutlet setIntValue:currentFrameNumber+1];
	[self blitFrame];
}



- (IBAction)fullscreenButton:(id)sender
{
	if(enableInterfaceCoupling){
		if([fullscreenButtonOutlet state]==NSOnState && [screenNumberMenuOutlet indexOfSelectedItem] -1 != fullscreenNumber && fullscreenNSGLContext != nil || [fullscreenButtonOutlet state]==NSOffState)
			[self fullscreenCreateOrDestroy:FALSE];
		if([fullscreenButtonOutlet state]==NSOnState)
			[self fullscreenCreateOrDestroy:TRUE];
	}
}



- (void)fullscreenCreateOrDestroy:(BOOL)create
{
	#define MAX_NUM_DISPLAYS		32
	CGDisplayCount					numDisplays;
	CGDirectDisplayID				displayIDArray[MAX_NUM_DISPLAYS];
	CGDisplayErr					error;
	long							swapIntervalFrames;
	NSOpenGLPixelFormat				*pixelFormat;
	CGLPixelFormatObj				pixelFormatCG;
	NSOpenGLPixelFormatAttribute	glDisplayMask, pixelDepth, alphaSize;
	int								displayModeIndex;
	
	int								foo;
	
	//tear down the current context because we are switching displays or because we are just closing the onscreen display.
	if(!create){
		 if(fullscreenNSGLContext!=nil){
			if(hipsMovie!=nil)
				[hipsMovie releaseTexturesFromContext]; 
			glClearColor(0.0, 0.0, 0.0, 0.0);
			glClear(GL_COLOR_BUFFER_BIT);
			[fullscreenNSGLContext flushBuffer];
			glClear(GL_COLOR_BUFFER_BIT);
			[fullscreenNSGLContext flushBuffer];
			[NSOpenGLContext clearCurrentContext];
			[fullscreenNSGLContext clearDrawable];
			[fullscreenNSGLContext release];
			if(CGDisplayIsCaptured(fullscreenDisplayID))
				CGDisplayRelease(fullscreenDisplayID);
			fullscreenNSGLContext=nil;
			fullscreenNumber=[screenNumberMenuOutlet indexOfSelectedItem]-1;
			CGRestorePermanentDisplayConfiguration();
		}
	}else{
		fullscreenNumber=[screenNumberMenuOutlet indexOfSelectedItem] -1;
		error=CGGetActiveDisplayList((CGDisplayCount)MAX_NUM_DISPLAYS, displayIDArray, &numDisplays);
		NSAssert(!error, @"Failed to enumarate Core Graphics displays");
		fullscreenDisplayID=displayIDArray[fullscreenNumber];
		//set the display mode;  x,y,z and f.
		displayModeIndex=[[displayModeMenuOutlet selectedItem] tag];
		glDisplayMask=CGDisplayIDToOpenGLDisplayMask(fullscreenDisplayID);
		pixelDepth= use8BitMode ? 8 : 24;
		alphaSize=use8BitMode ? 0 : 8;
		NSOpenGLPixelFormatAttribute formatAttributes[] = {
			NSOpenGLPFAFullScreen,
			NSOpenGLPFAScreenMask, (NSOpenGLPixelFormatAttribute)glDisplayMask,
			NSOpenGLPFAColorSize, (NSOpenGLPixelFormatAttribute)pixelDepth,
			NSOpenGLPFAAlphaSize, (NSOpenGLPixelFormatAttribute)alphaSize,
			NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute) 0,
			NSOpenGLPFAStencilSize, (NSOpenGLPixelFormatAttribute) 0,
			NSOpenGLPFAAccumSize, (NSOpenGLPixelFormatAttribute) 0,
			NSOpenGLPFADoubleBuffer,
			NSOpenGLPFANoRecovery,
			NSOpenGLPFAAccelerated, 
			(NSOpenGLPixelFormatAttribute)0  //terminator
		};
		pixelFormat=[[NSOpenGLPixelFormat alloc] initWithAttributes:formatAttributes];
		pixelFormatCG=(CGLPixelFormatObj)[pixelFormat CGLPixelFormatObj];
		swapIntervalFrames=1;
		if(captureDisplay)
			CGDisplayCapture(fullscreenDisplayID);
		error=CGDisplaySwitchToMode(fullscreenDisplayID, CFArrayGetValueAtIndex(displayModeList, (CFIndex)displayModeIndex));
		NSAssert(!error, @"Error switching to display mode");
		fullscreenNSGLContext=nil;
		fullscreenNSGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
		[pixelFormat release];
		NSAssert(fullscreenNSGLContext!=nil,@"Failed to created fullscreen context.");
		//customize the gl context for drawing.
		[fullscreenNSGLContext setFullScreen];
		[fullscreenNSGLContext makeCurrentContext];
		[fullscreenNSGLContext update];
		[fullscreenNSGLContext setValues:&swapIntervalFrames forParameter:NSOpenGLCPSwapInterval];
		fullscreenNSGLContextRect.origin.x=0;
		fullscreenNSGLContextRect.origin.y=0;
		fullscreenNSGLContextRect.size.width=(float)CGDisplayPixelsWide(fullscreenDisplayID);
		fullscreenNSGLContextRect.size.height=(float)CGDisplayPixelsHigh(fullscreenDisplayID);
		gluOrtho2D((double)0, (double)(fullscreenNSGLContextRect.size.width), (double)0, (double)(fullscreenNSGLContextRect.size.height));
		//if a movie is loaded then blit the first frame of the move to the display
		if(hipsMovie!=nil){
			if(use8BitMode){
				[hipsMovie instantiate8BitTexturesIntoNSGLContext:fullscreenNSGLContext frameSize:fullscreenNSGLContextRect];
				foo=currentFrameNumber;
				[hipsMovie blitFrame8:currentFrameNumber];
			}else{
				[hipsMovie instantiate32BitTexturesIntoNSGLContext:fullscreenNSGLContext frameSize:fullscreenNSGLContextRect]; 
				[hipsMovie blitFrame32:currentFrameNumber];
			}
			//activiate the ui movie controls now that there is a movie to control.
			[self enableIntrinsicMovieControls];
			[self enableExternalMovieControls];
			[self enableBackgroundRadioButtons];
		}
		[self setBackgroundColor:[self getFullscreeBackgroundModeFromButtons] blit:TRUE];
	}
}


- (IBAction)screenNumberMenu:(id)sender
{
	if(enableInterfaceCoupling)
		[self populateDisplayModeMenu];
}

- (IBAction)backgroundColorBlackButton:(id)sender
{
	if(enableInterfaceCoupling && [backgroundColorBlackButtonOutlet state]==NSOnState)
		[self setBackgroundColor:khpsBackgroundBlack blit:TRUE];
}

- (IBAction)backgroundColorWhiteButton:(id)sender
{
	if(enableInterfaceCoupling && [backgroundColorWhiteButtonOutlet state]==NSOnState)
		[self setBackgroundColor:khpsBackgroundWhite blit:TRUE];
}

- (IBAction)backgroundColorMidgrayButton:(id)sender
{
	if(enableInterfaceCoupling && [backgroundColorMidgrayButtonOutlet state]==NSOnState)
		[self setBackgroundColor:khpsBackgroundMidgray blit:TRUE];
}

- (IBAction)backgroundColorMeanButton:(id)sender
{
	if(enableInterfaceCoupling && [backgroundColorMeanButtonOutlet state]==NSOnState)
		[self setBackgroundColor:khpsBackgroundMean blit:TRUE];
}

- (IBAction)backgroundColorEdgeMeanButton:(id)sender
{
	if(enableInterfaceCoupling && [backgroundColorEdgeMeanButtonOutlet state]==NSOnState)
		[self setBackgroundColor:khpsBackgroundEdgeMean blit:TRUE];
}


- (IBAction)viewBlitTimesButton:(id)sender
{
	unsigned long   i, totalStringLength, numTimeSampleDiffs;
	NSString		*timesString;
	Str255			scratchString;
	char			*bigString, *strPosition;
	double			*timeSampleDiffs;
	
	timeSampleDiffs=(double*)malloc(numTimeSamples * sizeof(double));
	numTimeSampleDiffs=numTimeSamples-1;
	for(i=0;i<numTimeSampleDiffs;i++)
		timeSampleDiffs[i]=blitTimesArray[i+1]-blitTimesArray[i];
	totalStringLength=0;
	for(i=0;i<numTimeSampleDiffs;i++)
		totalStringLength=totalStringLength + sprintf(scratchString, "%f\n", timeSampleDiffs[i]);
	totalStringLength=totalStringLength+1;
	bigString=malloc(totalStringLength * sizeof(char));
	strPosition=bigString;
	for(i=0;i<numTimeSampleDiffs;i++)
		 strPosition= strPosition + sprintf(strPosition, "%f\n", timeSampleDiffs[i]);
	*strPosition='\0';
	timesString=[NSString stringWithCString:bigString length:totalStringLength];
	//[timesString autorelease];
	[blitTimesWindowOutlet orderFront:self];
	[blitTimeTextViewOutlet setString:timesString];
	free((void*)bigString);
	free((void*)timeSampleDiffs);
	
}

- (IBAction)synchToBlankSwitch:(id)sender
{
}

	

- (IBAction)displayModeMenu:(id)sender
{
	CFDictionaryRef		displayModeN;
	double				displayWidth, displayHeight, displayDepthBits, displayFrequencyHz;
	CFNumberRef			cfX;
	int					displayModeIndex;			
	

	//Get the index into our list of display modes for selected mode. The index is an int tagged to the menu entry as accessory information. 
	displayModeIndex=[[displayModeMenuOutlet selectedItem] tag];
	
	//Sanity check our choice to make sure that it matches the textual definition on the menu entry.
	printf("Mode index: %d\n", displayModeIndex);
	displayModeN= (CFDictionaryRef)CFArrayGetValueAtIndex(displayModeList, displayModeIndex);
	//width
	cfX= CFDictionaryGetValue(displayModeN, kCGDisplayWidth);
	CFNumberGetValue(cfX, kCFNumberDoubleType, &displayWidth);
	//height
	cfX= CFDictionaryGetValue(displayModeN, kCGDisplayHeight);
	CFNumberGetValue(cfX, kCFNumberDoubleType, &displayHeight);
	//depth
	cfX= CFDictionaryGetValue(displayModeN, kCGDisplayBitsPerPixel);
	CFNumberGetValue(cfX, kCFNumberDoubleType, &displayDepthBits);
	//frequency
	cfX= CFDictionaryGetValue(displayModeN, kCGDisplayRefreshRate);
	CFNumberGetValue(cfX, kCFNumberDoubleType, &displayFrequencyHz);
	printf("width %5.0f height %5.0f: depth %3.0f freq %4.0f\n", displayWidth, displayHeight, displayDepthBits, displayFrequencyHz);
	
	//if there is a window open the tear it down and rebuild it
	if(fullscreenNSGLContext!=nil){
		[self fullscreenCreateOrDestroy:FALSE];
		[self fullscreenCreateOrDestroy:TRUE];
	}
	

}


//____________________________________________________________________________________________________
//other methods

//do this when we startup and whenever the display number changes
-(void)populateDisplayModeMenu
{
	CGDirectDisplayID   displayID;
	CGDirectDisplayID   displayIDArray[MAX_NUM_DISPLAYS];
	CGDisplayErr		error;
	CGDisplayCount		numDisplays;
	CFIndex				numModes;
	CFDictionaryRef		displayModeN, defaultMode;
	int					i, screenNumber, defaultModeMenuIndex, displayModeListOriginalModeIndex;
	CFNumberRef			cfX;
	double				displayWidth, displayHeight, displayDepthBits, displayFrequencyHz;
	NSString			*menuEntryString;
//	id					menuItem;
	
	//get the display ID for the currently selected menu display
	screenNumber=[screenNumberMenuOutlet indexOfSelectedItem] -1;
	error=CGGetActiveDisplayList((CGDisplayCount)MAX_NUM_DISPLAYS, displayIDArray, &numDisplays);
	NSAssert(!error, @"Failed to enumarate Core Graphics displays");
	displayID=displayIDArray[screenNumber];
	//get information about the current  display mode so that we can match it to a list index then and later set initial pop menu selection to indicate  of current mode
	defaultMode=CGDisplayCurrentMode(displayID);
	//get the list of display mode which it supports
	displayModeList=CGDisplayAvailableModes(displayID);
	NSAssert(displayModeList!=NULL, @"Failed to enumerate display modes, probably because of an invalid displayID");
	numModes=CFArrayGetCount(displayModeList);
	//iterate over the display mode list and add display mode strings to the display mode pop up menu
	[displayModeMenuOutlet removeAllItems];
	for(i=0; i<numModes; i++){
		displayModeN= (CFDictionaryRef)CFArrayGetValueAtIndex(displayModeList, i);
		if(displayModeN==defaultMode)
			displayModeListOriginalModeIndex=i;
		//width
		cfX= CFDictionaryGetValue(displayModeN, kCGDisplayWidth);
		CFNumberGetValue(cfX, kCFNumberDoubleType, &displayWidth);
		//height
		cfX= CFDictionaryGetValue(displayModeN, kCGDisplayHeight);
		CFNumberGetValue(cfX, kCFNumberDoubleType, &displayHeight);
		//depth
		cfX= CFDictionaryGetValue(displayModeN, kCGDisplayBitsPerPixel);
		CFNumberGetValue(cfX, kCFNumberDoubleType, &displayDepthBits);
		//frequency
		cfX= CFDictionaryGetValue(displayModeN, kCGDisplayRefreshRate);
		CFNumberGetValue(cfX, kCFNumberDoubleType, &displayFrequencyHz);
		if(displayDepthBits==32){
			if(displayFrequencyHz==0)
				menuEntryString=[NSString localizedStringWithFormat:@"%5.0f x %5.0f", displayWidth, displayHeight];
			else
				menuEntryString=[NSString localizedStringWithFormat:@"%5.0f x %5.0f %4.0fHz", displayWidth, displayHeight, displayFrequencyHz, (double)i];
			[displayModeMenuOutlet addItemWithTitle:menuEntryString];
			[[displayModeMenuOutlet lastItem] setTag:i];
		}
	}
	defaultModeMenuIndex=[displayModeMenuOutlet indexOfItemWithTag:displayModeListOriginalModeIndex];
	[displayModeMenuOutlet selectItemAtIndex:defaultModeMenuIndex];
}


-(void)awakeFromNib
{
	NSArray *launchArguments;
	//for launching PlayMovie object's thread
/*  NSConnection *connectionToTransfer;
	NSPort *port1;
	NSPort *port2;
    NSArray *portArray;
*/

	[self initMovieControls];
	[self disableMovieControls];
	[self enableBackgroundRadioButtons];
	recordKeysFlag=FALSE;
	isMovieThreadPlaying=FALSE;
	exitAfterPlay=FALSE;	
	enableInterfaceCoupling=TRUE;
	use8BitMode=TRUE;
	hipsMovie = nil;
	limitNumLoopPasses=0;
	fullscreenNSGLContext=nil;
	previewNSGLContext=nil;
	currentFrameNumber=0;
	captureDisplay=TRUE;	
	currentFrameRate=60;   //this should be inited with the video frame rate
	maximumFrameRate=120;
	minimumFrameRate=1;
	sliderBoundsAlertSound=[NSSound soundNamed:@"Sosumi"];
	launchArguments=[[NSProcessInfo processInfo] arguments];
	frameIncrement=1;
	threadLock=FALSE;
	fullscreenNumber=0;
	numTimeSamples=0;
	sampleBlitTimes=FALSE;
	blitTimesArray= (double*)malloc(MAXIMUM_BLIT_TIME_SAMPLES * sizeof(double));
	[self populateScreenMenu];
	[self populateDisplayModeMenu];
	
/*
	//launch the player thread
    port1 = [NSPort port];
    port2 = [NSPort port];
    connectionToTransfer = [[NSConnection alloc] initWithReceivePort:port1 sendPort:port2];
    [connectionToTransfer setRootObject:self];
    portArray = [NSArray arrayWithObjects:port2, port1, nil];
    [NSThread detachNewThreadSelector:@selector(connectWithPorts:) toTarget:[PlayMovie class] withObject:portArray];
*/	
	//if launched from the command line then go load and play the file specified by command line arguments.
	if(commandFlags.useCommandLine)
		[self openFileFromStdInput];
}

- (void)disableMovieControls
{
	[maxFrameLabel setStringValue:@""];
	[minFrameLabel setStringValue:@""];
	[frameSliderOutlet setEnabled:FALSE];

	//new player controls in v 0.8
	[stepToEndButtonOutlet setEnabled:FALSE]; 
	[stepToStartButtonOutlet setEnabled:FALSE]; 
	[playOrPauseButtonOutlet setEnabled:FALSE]; 
    [stepBackwardButtonOutlet setEnabled:FALSE]; 
	[stepForwardButtonOutlet setEnabled:FALSE]; 
	[reverseSwitchOutlet setEnabled:FALSE]; 
	[loopSwitchOutlet setEnabled:FALSE]; 
	[palindromeSwitchOutlet setEnabled:FALSE]; 

	[viewHeaderButtonOutlet setEnabled:FALSE];
	[frameLabel setStringValue:@""];
	[palindromeSwitchOutlet setEnabled:FALSE];	
	[fileNameValueOutlet setStringValue:@""];
	[frameNumberTextOutlet setEnabled:FALSE];
	//scaling switches
	[scaleLEnableOutlet setEnabled:FALSE];
	[scaleLClampToZeroRadioOutlet setEnabled:FALSE];
	[scaleLClampToMeanRadioOutlet setEnabled:FALSE];
	[scaleLFloatingZeroRadioOutlet setEnabled:FALSE];

}


- (void)initMovieControls	
{
//	unichar stepForwardKey=NSRightArrowFunctionKey;
//	unichar stepBackwardKey=NSLeftArrowFunctionKey;
//	unichar playOrPauseKey=0x0020;  //unicode for the space character.  
	
//	[stepForwardOutlet setKeyEquivalent:[NSString stringWithCharacters:&stepForwardKey length:1]];
//	[stepBackOutlet setKeyEquivalent:[NSString stringWithCharacters:&stepBackwardKey length:1]];
//	[playOrPauseButtonOutlet setKeyEquivalent:[NSString stringWithCharacters:&playOrPauseKey length:1]];
}


- (void)enableExternalMovieControls	//parameters not intrinsic to the movie file.
{

	[frameSliderOutlet setEnabled:TRUE];

	// New player controls in vesion 0.8
	[stepToEndButtonOutlet setEnabled:TRUE]; 
	[stepToStartButtonOutlet setEnabled:TRUE]; 
	[playOrPauseButtonOutlet setEnabled:TRUE]; 
    [stepBackwardButtonOutlet setEnabled:TRUE]; 
	[stepForwardButtonOutlet setEnabled:TRUE]; 
	[reverseSwitchOutlet setEnabled:TRUE]; 
	[loopSwitchOutlet setEnabled:TRUE]; 
	[palindromeSwitchOutlet setEnabled:TRUE]; 

	[frameLabel setStringValue:@"Frame"];
	[frameNumberTextOutlet setEnabled:TRUE];
	[palindromeSwitchOutlet setEnabled:TRUE];
	//scaling rules
	[scaleLEnableOutlet setEnabled:TRUE];
	[scaleLClampToZeroRadioOutlet setEnabled:TRUE];
	[scaleLClampToMeanRadioOutlet setEnabled:TRUE];
	[scaleLFloatingZeroRadioOutlet setEnabled:TRUE];
	
}


- (void)enableIntrinsicMovieControls  //parameters intrinsic to the movie file and returned or constrained by the movie object.
{
	currentFrameNumber=0;
	NSAssert(hipsMovie!=NULL, @"Attempt to set movie controls with no movie loaded");
	[minFrameLabel  setIntValue:1];
	[maxFrameLabel  setIntValue:[hipsMovie getNumFrames]];
	[frameSliderOutlet setMinValue:1];
	[frameSliderOutlet setMaxValue:[hipsMovie getNumFrames]];
	[frameSliderOutlet setIntValue:currentFrameNumber+1];
	[frameSliderOutlet setAltIncrementValue:(double)1];
	[frameNumberTextOutlet setIntValue:currentFrameNumber+1];
	[fileNameValueOutlet setStringValue:[[hipsMovie getFullFileName] lastPathComponent]];
	[viewHeaderButtonOutlet setEnabled:TRUE];
	//set the scaling buttons  to match the movie state
	[self setButtonsFromScaleMode:[hipsMovie getScalingMode]];
}


- (void)populateScreenMenu
{
	int		numScreens, i;

	numScreens=[[NSScreen screens] count];
	for(i=0;i<numScreens;i++){
		[screenNumberMenuOutlet addItemWithTitle:[NSString localizedStringWithFormat:@"%hi",i]];
	}
	fullscreenNumber=numScreens-1;
	[screenNumberMenuOutlet selectItemWithTitle:[NSString localizedStringWithFormat:@"%hi",fullscreenNumber]];
} 

- (BackgroundColorModeType)getFullscreeBackgroundModeFromButtons
{
	if([backgroundColorBlackButtonOutlet state]==NSOnState)
		return(khpsBackgroundBlack);
	else if([backgroundColorWhiteButtonOutlet state]==NSOnState)
		return(khpsBackgroundWhite);
	else if([backgroundColorMidgrayButtonOutlet state]==NSOnState)
		return(khpsBackgroundMidgray);
	else if([backgroundColorMeanButtonOutlet state]==NSOnState)
		return(khpsBackgroundMean);
	else if([backgroundColorEdgeMeanButtonOutlet state]==NSOnState)
		return(khpsBackgroundEdgeMean);
	NSAssert(FALSE, @"Unrecognized state for background color radio buttons");
	return(0);  //make the compiler happy
}


- (void)setBackgroundColor:(BackgroundColorModeType)backgroundColorMode blit:(BOOL)blitFlag
{
	float				redColor, greenColor, blueColor, alphaColor;
	long				tempSwapInterval, originalSwapInterval;
	
//	if([fullscreenButtonOutlet state]==NSOnState){
	if(fullscreenNSGLContext != nil){
		switch(backgroundColorMode){
			case khpsBackgroundBlack: 
				redColor=0; greenColor=0;   blueColor=0;	alphaColor=1;
				break;
			case khpsBackgroundWhite:
				redColor=1; greenColor=1; blueColor=1; alphaColor=1;
				break;
			case khpsBackgroundMidgray:
				redColor=0.5; greenColor=0.5;   blueColor=0.5;	alphaColor=1;
				break;
			case khpsBackgroundMean:
				NSAssert(hipsMovie!=nil,@"Attempt to set background to movie mean when no movie is loaded.");
				redColor=[hipsMovie getMeanPixelValue] / (float)255;
				greenColor=redColor;
				blueColor=redColor;
				alphaColor=1;
				break;
			case khpsBackgroundEdgeMean:
				NSAssert(hipsMovie!=nil,@"Attempt to set background to movie mean when no movie is loaded.");
				redColor=[hipsMovie getMeanEdgePixelValue] / (float)255;
				greenColor=redColor;
				blueColor=redColor;
				alphaColor=1;
				break;
		}
		
		if(blitFlag){
			//draw the background onto both front and back buffers.
			tempSwapInterval=0;
			[fullscreenNSGLContext getValues:&originalSwapInterval forParameter:NSOpenGLCPSwapInterval];
			[fullscreenNSGLContext setValues:&tempSwapInterval forParameter:NSOpenGLCPSwapInterval];
			glClearColor(redColor, greenColor, blueColor, 1);
			glClear(GL_COLOR_BUFFER_BIT);
			[fullscreenNSGLContext flushBuffer];
			glClearColor(redColor, greenColor, blueColor, 1);
			glClear(GL_COLOR_BUFFER_BIT);
			[fullscreenNSGLContext flushBuffer];		//not really necessary
			[fullscreenNSGLContext setValues:&originalSwapInterval forParameter:NSOpenGLCPSwapInterval];
			if(hipsMovie!=nil){ 
				[self blitFrame];
			}
		} else{
			glClearColor(redColor, greenColor, blueColor, 1);
			glClear(GL_COLOR_BUFFER_BIT);
		}
	}
}

- (void)enableBackgroundRadioButtons
{
	//selectively enable background buttons according to what the application state allows
	if(hipsMovie == nil){
		[backgroundColorBlackButtonOutlet setEnabled:TRUE];
		[backgroundColorWhiteButtonOutlet setEnabled:TRUE];
		[backgroundColorMidgrayButtonOutlet setEnabled:TRUE];
		[backgroundColorMeanButtonOutlet setEnabled:FALSE];
		[backgroundColorEdgeMeanButtonOutlet setEnabled:FALSE];
	}else{
		[backgroundColorBlackButtonOutlet setEnabled:TRUE];
		[backgroundColorWhiteButtonOutlet setEnabled:TRUE];
		[backgroundColorMidgrayButtonOutlet setEnabled:TRUE];
		[backgroundColorMeanButtonOutlet setEnabled:TRUE];
		[backgroundColorEdgeMeanButtonOutlet setEnabled:TRUE];
	}
}

- (ScaleModeType)getScaleModeFromButtons
{
	BOOL				isEnabled;
	
	isEnabled=[scaleLEnableOutlet isEnabled];
	[scaleLEnableOutlet setEnabled:TRUE];
	if([scaleLEnableOutlet state]==NSOffState){
		[scaleLEnableOutlet setEnabled:isEnabled];
		return(khpsNoScale);
	}
		
	isEnabled=[scaleLClampToMeanRadioOutlet isEnabled];
	[scaleLClampToMeanRadioOutlet setEnabled:TRUE];
	if([scaleLClampToMeanRadioOutlet state]==NSOnState){
		[scaleLClampToMeanRadioOutlet setEnabled:isEnabled];
		return(khpsClampToMean);
	}
	
	isEnabled=[scaleLClampToZeroRadioOutlet isEnabled];
	[scaleLClampToZeroRadioOutlet setEnabled:TRUE];
	if([scaleLClampToZeroRadioOutlet state]==NSOnState){
		[scaleLClampToZeroRadioOutlet setEnabled:isEnabled];
		return(khpsClampToZero);
	}
	
	isEnabled=[scaleLFloatingZeroRadioOutlet isEnabled];
	[scaleLFloatingZeroRadioOutlet setEnabled:TRUE];
	if([scaleLFloatingZeroRadioOutlet state]==NSOnState){
		[scaleLFloatingZeroRadioOutlet setEnabled:isEnabled];
		return(khpsFloat);
	}

	return(khpsNoneSpecified);
}


- (void)setButtonsFromScaleMode:(ScaleModeType)ScaleMode
{
	if(ScaleMode == khpsNoScale){
		[scaleLEnableOutlet setState:NSOffState];
		[self disableScalingSwitches];
	}if(ScaleMode == khpsClampToZero){
		[scaleLEnableOutlet setState:NSOnState];
		[self enableScalingSwitches];
		[scaleLClampToZeroRadioOutlet setState:NSOnState];	
	}if(ScaleMode == khpsClampToMean){
		[scaleLEnableOutlet setState:NSOnState];
		[self enableScalingSwitches];
		[scaleLClampToMeanRadioOutlet setState:NSOnState];	
	}if(ScaleMode == khpsFloat){
		[scaleLEnableOutlet setState:NSOnState];
		[self enableScalingSwitches];
		[scaleLFloatingZeroRadioOutlet setState:NSOnState];	
	}	

}


- (void)disableScalingSwitches
{
	[scaleLClampToZeroRadioOutlet setEnabled:FALSE];
	[scaleLClampToMeanRadioOutlet setEnabled:FALSE];
	[scaleLFloatingZeroRadioOutlet setEnabled:FALSE];
	
}


- (void)enableScalingSwitches
{
	[scaleLClampToZeroRadioOutlet setEnabled:TRUE];
	[scaleLClampToMeanRadioOutlet setEnabled:TRUE];
	[scaleLFloatingZeroRadioOutlet setEnabled:TRUE];
}


// It would be more tidy to sublcass the NSWindow and put this there.  (Or should we subclass NSOpenGLView?
// Probably NSOpenGL view because we can take advantage of the prepareOpenGL call to setup OpenGL context).
- (void)setupPreviewWindow
{
	NSRect					movieRect;
	NSOpenGLPixelFormat		*pixelFormat;
	
	// the default NSOpenGLContext containded by the NSOpenGLView created by interface builder is not double buffered.  Therefore,
	// we need to  tell the NSOpenGLView to release its current NSOpenGLContext, then set its pixel format to one specifying double buffers,
	// then tell it to create a new NSOpenGLcontext. 
	
	//resize the preview window to exactly fit the movie
	movieRect=[hipsMovie getMovieRect];
	[previewWindowOutlet setContentSize:movieRect.size];
	[previewViewOutlet setFrame:[hipsMovie getMovieRect]];

	
	//reset the pixel format
	[previewViewOutlet clearGLContext];
	NSOpenGLPixelFormatAttribute formatAttributes[] = {
		NSOpenGLPFAColorSize, (NSOpenGLPixelFormatAttribute)24,
		NSOpenGLPFAAlphaSize, (NSOpenGLPixelFormatAttribute)8,
		NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute) 0,
		NSOpenGLPFAStencilSize, (NSOpenGLPixelFormatAttribute) 0,
		NSOpenGLPFAAccumSize, (NSOpenGLPixelFormatAttribute) 0,
		NSOpenGLPFADoubleBuffer,
		(NSOpenGLPixelFormatAttribute)0  //terminator
	};
	pixelFormat=[[NSOpenGLPixelFormat alloc] initWithAttributes:formatAttributes];
	[previewViewOutlet setPixelFormat:pixelFormat];
	[pixelFormat release];
    pixelFormat = nil;
	previewNSGLContext=[previewViewOutlet openGLContext];
	[previewNSGLContext makeCurrentContext];
	previewNSGLContextRect=[hipsMovie getMovieRect];
	//We could use glViewPort here instead of gluOrtho2D.
	gluOrtho2D((double)0, (double)(previewNSGLContextRect.size.width), (double)0, (double)(previewNSGLContextRect.size.height));
	

	//internal sanity check, that a movie is loaded first.  We scale X&Y to match movie X&Y.
	NSAssert(hipsMovie!=nil, @"Attempt to resize window to movie frame size when no movie is loaded.");
	
	
	// bring the window with the NSOpenGL view to the foreground and 
	// scale it to hold the movie with frame size contentRect.
	[previewWindowOutlet  orderFront:self];
	[previewWindowOutlet setTitle:[[hipsMovie getFullFileName] lastPathComponent]];
}


//____________________________________________________________________________________________________
//methods for access to the HipsViewer object by the PlayMovie object 

- (void)setServer:(id)anObject
{
    [anObject setProtocolForProxy:@protocol(PlayMovieInterface)];
    player = (id <PlayMovieInterface>)[anObject retain];
    return;
}


- (BOOL)getPalindromeSwitchOutletState
{
	return([palindromeSwitchOutlet state]==NSOnState);
}

- (int)getFrameIncrement
{
	return(frameIncrement);
}

- (void)setFrameIncrement:(int)inc
{
	frameIncrement=inc;
}


- (BOOL)getLoopSwitchOutletState
{
	return([loopSwitchOutlet state]==NSOnState);	
}

- (void)blitFrame
{
	//[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:(NSTimeInterval)0.016]];
	if(use8BitMode)
		[hipsMovie blitFrame8:currentFrameNumber];
	else
		[hipsMovie blitFrame32:currentFrameNumber];
	// the recordBlitTimes flag depends both on the playMovie object setting
	//it, depending on the gui checkbox, at the onset of movie play. 
	if(sampleBlitTimes){
		if(numTimeSamples==MAXIMUM_BLIT_TIME_SAMPLES)
			numTimeSamples=0;
		blitTimesArray[numTimeSamples]=GetSecs();
		++numTimeSamples;
	}
}

- (void)setFrameNumberControls
{
	[frameSliderOutlet setIntValue:currentFrameNumber+1];
	[frameNumberTextOutlet setIntValue:currentFrameNumber+1];
}

- (int)getNumFrames
{
	return([hipsMovie getNumFrames]);
}

- (int)getNumPlayLoops
{
	//zero means no limit.  This is only set by a command line flag, not from the gui. 
	return(limitNumLoopPasses);
}

- (void)enableNonPlaytimeControls:(BOOL)enableOn
{
	[fullscreenButtonOutlet setEnabled:enableOn];
	[screenNumberMenuOutlet setEnabled:enableOn];
	[displayModeMenuOutlet setEnabled:enableOn];
	[scaleLEnableOutlet setEnabled:enableOn];
	[luminanceClampRadioMatrixOutlet setEnabled:enableOn];
	[backgroundColorRadioMatrixOutlet setEnabled:enableOn];
	[synchToBlankSwitchOutlet setEnabled:enableOn];
	[sampleBlitTimesSwitchOutlet setEnabled:enableOn];
	[viewBlitTimesButtonOutlet setEnabled:enableOn];
	[displayKeypressListButtonOutlet setEnabled:enableOn];
}

- (int)getFrameNumber
{
	return(currentFrameNumber);
}

- (void)setThreadLock:(BOOL)lockPlay
{
	threadLock=lockPlay;
}

- (void)setFrameNumber:(int)num
{
	currentFrameNumber=num;
}

- (BOOL)getRealtimeMode
{
	return([fullscreenButtonOutlet state]==NSOnState);
}

- (void)setNumPlayLoopPasses:(int)numPasses
{
	limitNumLoopPasses=numPasses;
}

- (BOOL)getGoMovieFlag
{
	return(goMovieFlag);
}

- (void)activateRealtimeImmediate:(BOOL)priorityOn
{
	if(priorityOn)
		SetRealtimePriority(4);
	else
		SetRealtimePriority(0);
}

- (BOOL)checkForKeypress
{
	int		numKeys;
	
	numKeys=[controlPanelWindowOutlet getQueueLength];
	return((BOOL)(numKeys > 0));
}

- (BOOL)getExitOnKeypress
{
	return((BOOL)(commandFlags.useCommandLine && commandFlags.exitOnKeyFlag));

}

- (void)turnOffPlayButton
{
	[playOrPauseButtonOutlet setState:NSOffState];
	[self fullscreenCreateOrDestroy:FALSE];
}

- (int)getSampleBlitTimesSwitch
{
	return([sampleBlitTimesSwitchOutlet state]);
}

- (void)setSampleBlitTimesFlag:(BOOL)value
{
	sampleBlitTimes=value;
}


//____________________________________________________________________________________________________
//new for PlayMovie object 


- (IBAction)displayAboutWindow:(id)sender
{
	[aboutWindowOutlet makeKeyAndOrderFront:self];
}

- (void)closeAllOpenStuff
{
	//get rid of the old movie in preparation for opening a new one.  Close open windows.
	if(hipsMovie!=nil){
		[hipsMovie release];
		hipsMovie=nil;
		currentFrameNumber=0;
	}
	 
	[self fullscreenCreateOrDestroy:FALSE];
	[previewWindowOutlet  orderOut:self];
}


//____________________________________________________________________________________________________
//override methods

 - (void)dealloc
{
	free((void*)blitTimesArray);
	[hipsMovie release];
	[super dealloc];
}

- (id)init
{
	//for launching PlayMovie object's thread
    NSConnection *connectionToTransfer;
	NSPort *port1;
	NSPort *port2;
    NSArray *portArray;

    self = [super init];
    if (self != nil){
		//launch the player thread
		port1 = [NSPort port];
		port2 = [NSPort port];
		connectionToTransfer = [[NSConnection alloc] initWithReceivePort:port1 sendPort:port2];
		[connectionToTransfer setRootObject:self];
		portArray = [NSArray arrayWithObjects:port2, port1, nil];
		[NSThread detachNewThreadSelector:@selector(connectWithPorts:) toTarget:[PlayMovie class] withObject:portArray];
    }
    return (self);
}

@end
