//
//  MyMovieText.m
//  Cocoa - SGDataProc
//
//  Created by wilson on Fri Aug 27 2004.
//  Copyright (c) 2004 __MyCompanyName__. All rights reserved.
//

#import "MyMovieText.h"


@implementation MyMovieText

#define BailErr(x) {err = x; if(err != noErr) return err;}

#define kMyErrorCode		-22222
#define kCaptionDuration	1			// duration of caption in seconds
#define kInvalidFileRefNum	-1			// an invalid file reference number
#define kGetFirstMovie		0
#define kGetFirstTrack		1
#define kTextTrackHeight	20			// default height for text track (in pixels)
#define kTrackOffset		0
#define kMediaOffset		0

-(OSErr)addCaptionToMovie:(NSMutableArray *)theCaption filename:(NSString *)movieFilename
{
    Movie theMovie;
    short myRefNum = kInvalidFileRefNum;
    OSErr err;

    NSLog(@"inside addCaptionToMovie, %@", movieFilename);
    //NSLog(@"inside addCaptionToMovie");

    //NSRunAlertPanel(@"Error", movieFilename, @"OK", nil, nil);

    if(!movieFilename)
	NSLog(@"movieFilename is nil");
    
    err = [self myOpenMovie:&theMovie filename:movieFilename refNum:&myRefNum];
    [self checkError:err message:@"myOpenMovie failed"];
    //if (err != noErr)
	//return err;

    if (err == noErr)
    {
	err = [self myCreateVideoTrack:theMovie caption:theCaption];
	[self checkError:err message:@"myCreateVideoTrack failed"];
	//if (err != noErr)
	  //  return err;
    }

    err = [self myCloseMovie:&theMovie refNum:myRefNum];
    [self checkError:err message:@"myCloseMovie failed"];
    //if (err != noErr)
	/////return err;

    return err;
}

-(OSErr)myOpenMovie:(Movie *)theMovie filename:(NSString *)movieFilename refNum:(short *)theRefNum
{
    MyVideo *myVideo;
    FSSpec myFSSpec;
    //short theRefNum = kInvalidFileRefNum;
    OSErr err;
    //short myResID = kGetFirstMovie;
    short myResID = movieInDataForkResID;

    myVideo = [[MyVideo alloc] init];
    if (!myVideo)
    {
	NSRunAlertPanel(@"Error", @"MyVideo not created", @"OK", nil, nil);
	BailErr(kMyErrorCode);
    }

    err = [MyVideo myMakeFSSpec:&myFSSpec fromPath:movieFilename];
    [self checkError:err message:@"myMakeFSSpec failed"];
    BailErr(err);

    // Open file with exclusive read & write permission
    err = OpenMovieFile(&myFSSpec, theRefNum, fsRdWrPerm);
    [self checkError:err message:@"OpenMovieFile failed"];
    BailErr(err);

    // Create a new movie from the movie file we just opened
    err = NewMovieFromFile(theMovie, *theRefNum, &myResID, NULL, newMovieActive, NULL);
    [self checkError:err message:@"NewMovieFromFile failed"];
    BailErr(err);

    NSLog(@"End of myOpenMovie");
    return err;
}

-(OSErr)myCloseMovie:(Movie *)theMovie refNum:(short)theRefNum
{
    short resId = movieInDataForkResID;
    OSErr err = noErr;

    if (theRefNum != kInvalidFileRefNum)
    {
	//err = AddMovieResource(*theMovie, theRefNum, &resId, nil);
	err = UpdateMovieResource(*theMovie, theRefNum, resId, nil);
	[self checkError:err message:@"AddMovieResource failed"];
	//if (err != noErr)
	  //  return err;
    
	err = CloseMovieFile(theRefNum);
	[self checkError:err message:@"CloseMovieFile failed"];
	//if (err != noErr)
	  //  return err;
    
	DisposeMovie(*theMovie);
	err = GetMoviesError();
	[self checkError:err message:@"DisposeMovie failed"];
	//NSRunAlertPanel(@"Error", @"DisposeMovie() in MovieText" , @"OK", nil, nil);
	//if (err != noErr)
	  //  return err;
    }

    return err;
}
    
/*****************************************************************************
*
* FUNCTION: myCreateVideoTrack
* PURPOSE : Creates a text track and adds text samples to a movie
* INPUT   : 1. theMovie		- The movie for which the text track is created
*			2. theCaption   - Contains the text samples to be added to the movie
* NOTE    : This function is based on qttext, which can be found at
*			http://developer.apple.com/samplecode/qttext/qttext.html
*
**********************************************************************************/
-(OSErr)myCreateVideoTrack:(Movie)theMovie caption:(NSMutableArray *)theCaption
{
    OSErr 		err = noErr;
    Track 		myVideoTrack = NULL;
    Track		myTextTrack = NULL;
    Media 		myMedia = NULL;
    //MediaHandler 	myHandler = NULL;
    Fixed 		myWidth;
    Fixed 		myHeight;
    TimeScale 		myTimeScale;
    MatrixRecord	myMatrix;
    
    NSLog(@"inside myCreateVideoTrack");
	
    // Get the first track of the type Video
    myVideoTrack = GetMovieIndTrackType(theMovie,
										kGetFirstTrack,		// Get the first track 
										VideoMediaType,		// of the type VIDEO
										movieTrackMediaType);	// look for media type only
    if (myVideoTrack == NULL)
		goto bail;
	
    GetTrackDimensions(myVideoTrack, &myWidth, &myHeight);
    myTimeScale = GetMediaTimeScale(GetTrackMedia(myVideoTrack));
	
	
    /***********************************************
		*
		*  Create the text track and media
		*
		************************************************/
    
    myTextTrack = NewMovieTrack(theMovie, myWidth, FixRatio(kTextTrackHeight, 1), kNoVolume);
    if (myTextTrack == NULL)
		goto bail;
	
    myMedia = NewTrackMedia(myTextTrack, TextMediaType, myTimeScale, NULL, 0);
    if (myMedia == NULL)
		goto bail;
	
	/*
    myHandler = GetMediaHandler(myMedia);
    if (myHandler == NULL)
		goto bail;
	*/
	
    // Figure out the text track geometry
    GetTrackMatrix(myTextTrack, &myMatrix);
    TranslateMatrix(&myMatrix, 0, myHeight);
	
    SetTrackMatrix(myTextTrack, &myMatrix);
    SetTrackEnabled(myTextTrack, TRUE);
	
    err = BeginMediaEdits(myMedia);
    if (err == noErr)
    {
		Rect 		myBounds;
		//short 		myIndex;
		//TimeValue 	myVideoSampleDuration;
		//TimeRecord	myTimeRecord;
		//NSDate		*key;

		
		myBounds.top = 0;
		myBounds.left = 0;
		myBounds.right = Fix2Long(myWidth);
		myBounds.bottom = Fix2Long(myHeight);
		
		
		// Get the sample duration, ignore other data
		/*
		err = GetMediaSample(GetTrackMedia(myVideoTrack),
					   NULL,		// don't return data
					   0,
					   NULL,              // don't return # of bytes
					   0,
					   NULL,
					   &myVideoSampleDuration,
					   NULL,
					   NULL,
					   0,
					   NULL,
					   NULL);
		[self checkError:err message:@"GetMediaSample failed"];
		if (err != noErr)
			goto bail;
		 */
		
		//NSEnumerator *enumerator = [theCaption keyEnumerator];
		
		//NSLog(@"before add text sample");
		unsigned arrayLength = 0;
		unsigned i;
		
		arrayLength = [theCaption count];
		//while ((key = (NSDate *) [enumerator nextObject]))
		for (i = 0; i < arrayLength; i++)
		{
			//Str255 		myPascalStr;
			TimeValue		myTextSampleDuration;
			NSTimeInterval	pauseDuration = 0.0;
			//NSString 		*caption;
			
			//char 		*myCStr;
			
			/* code that uses the returned key */
			//NSLog(@"date = %@ and text = %@", key, [theCaption objectForKey:key]);
			
			UserText *textData = (UserText *)[theCaption objectAtIndex:i];
			pauseDuration = [textData duration] - (NSTimeInterval)kCaptionDuration;
			NSLog(@"pauseDuration = %f, caption duration = %f",  pauseDuration, [textData duration]);
			if (pauseDuration > 0)
			{
				NSLog(@"adding pause");
				myTextSampleDuration = (TimeValue)(pauseDuration * (NSTimeInterval)myTimeScale);
				NSLog(@"sample duration = %d", myTextSampleDuration);
				// Add a text containing only spaces to create the effect of pauses
				[self myAddTextSample:&theMovie media:&myMedia bounds:&myBounds
					   text:@" " duration:myTextSampleDuration];
			}
			
			myTextSampleDuration = kCaptionDuration * myTimeScale;
			// Add user-typed text into movie
			[self myAddTextSample:&theMovie media:&myMedia bounds:&myBounds
					text:[textData text] duration:myTextSampleDuration];
		
			
				// set the time scale of the media to that of the movie
	//myTextSampleDuration = myVideoSampleDuration * 20;
				
				/*
				myTextSampleDuration = myTimeScale * (TimeScale)kCaptionDuration;
				myTimeRecord.value.lo = myTextSampleDuration;
				myTimeRecord.value.hi = 0;
				myTimeRecord.scale = GetMovieTimeScale(theMovie);
				NSLog(@"movie timescale = %d", myTimeRecord.scale);
				ConvertTimeScale(&myTimeRecord, GetMediaTimeScale(myMedia));
				NSLog(@"media timescale = %d", GetMediaTimeScale(myMedia));
				myTextSampleDuration = myTimeRecord.value.lo;
				
				//caption = (NSString *)[theCaption objectForKey:key];
				NSLog(@"current caption = %@", caption);
				//myCStr = [caption UTF8String];
				[self QTText_CopyCStringToPascal:[caption UTF8String] dest:myPascalStr];
				
				err = TextMediaAddTextSample(myHandler,
								 (Ptr)(&myPascalStr[1]),
								 myPascalStr[0],	// first element of a Pascal str specifies its length
								 0,
								 0,
								 0,
								 NULL,
								 NULL,
								 teCenter,
								 &myBounds,
								 dfClipToTextBox,
								 0,
								 0,
								 0,
								 NULL,
								 myTextSampleDuration,
								 NULL);
				[self checkError:err message:@"TextMediaAddTextSample failed"];
				if (err != noErr)
					goto bail;
				 */
		}			
    }
	
    NSLog(@"after add text sample");
	
    err = EndMediaEdits(myMedia);
    [self checkError:err message:@"EndMediaEdits failed"];
    if (err != noErr)
		goto bail;
	
    // Insert text media into the text track
    err = InsertMediaIntoTrack(myTextTrack,
							   kTrackOffset,
							   kMediaOffset,
							   GetMediaDuration(myMedia),
							   fixed1);
    NSLog(@"media duration = %d", GetMediaDuration(myMedia));
    [self checkError:err message:@"InsertMediaIntoTrack failed"];
    if (err != noErr)
		goto bail;
	
bail:	
		
		return err;
}

-(OSErr)myAddTextSample:(Movie *)theMovie media:(Media *)theMedia bounds:(Rect *)theBounds
							   text:(NSString *)theText duration:(TimeScale)theDuration 
{
	MediaHandler 	myHandler = NULL;
	TimeRecord		myTimeRecord;
	TimeScale		mediaTimeScale;
	//Rect			myBounds;
	Str255			myPascalStr;
	TimeValue		myTextSampleDuration;
	OSErr			err = noErr;

    myHandler = GetMediaHandler(*theMedia);
    if (myHandler == NULL)
	{
		err = kMyErrorCode;
		goto bail;
	}
	
	/*
	theBounds->top = 0;
	theBounds->left = 0;
	theBounds->right = Fix2Long(myWidth);
	theBounds->bottom = Fix2Long(myHeight);
	*/
	
	mediaTimeScale = GetMediaTimeScale(*theMedia);
	//myTextSampleDuration = mediaTimeScale * (TimeScale)kCaptionDuration;
	//myTimeRecord.value.lo = myTextSampleDuration;
	myTimeRecord.value.lo = theDuration;
	myTimeRecord.value.hi = 0;
	myTimeRecord.scale = GetMovieTimeScale(*theMovie);
	//ConvertTimeScale(&myTimeRecord, GetMediaTimeScale(*theMedia));
	ConvertTimeScale(&myTimeRecord, mediaTimeScale);
	myTextSampleDuration = myTimeRecord.value.lo;
	
	//caption = (NSString *)[theCaption objectForKey:key];
	NSLog(@"current caption = %@", theText);
	//myCStr = [caption UTF8String];
	[self QTText_CopyCStringToPascal:[theText UTF8String] dest:myPascalStr];
	
	err = TextMediaAddTextSample(myHandler,
							  (Ptr)(&myPascalStr[1]),
							  myPascalStr[0],	// first element of a Pascal str specifies its length
							  0,
							  0,
							  0,
							  NULL,
							  NULL,
							  teCenter,
							  theBounds,
							  dfClipToTextBox,
							  0,
							  0,
							  0,
							  NULL,
							  myTextSampleDuration,
							  NULL);
	[self checkError:err message:@"TextMediaAddTextSample failed"];
	
bail:
	return err;
}

//////////
//
// QTText_CopyCStringToPascal
// Convert the source C string to a destination Pascal string as it's copied.
//
// The destination string will be truncated to fit into a Str255 if necessary.
// If the C string pointer is NULL, the Pascal string's length is set to zero.
//
// This routine is borrowed from CGlue.c, by Nick Kledzik.
//
//////////
//void QTText_CopyCStringToPascal (const char *theSrc, Str255 theDst)
-(void)QTText_CopyCStringToPascal:(const char *)theSrc dest:(Str255)theDst
{
    short	myLength = 0;

    // handle case of overlapping strings
    if ((void *)theSrc == (void *)theDst)
    {
	unsigned char		*myCurDst = &theDst[1];
	unsigned char		myChar;
	myChar = *(const unsigned char *)theSrc++;
	while (myChar != '\0')
	{
	    unsigned char	myNextChar;
	    // use myNextChar so we don't overwrite what we are about to read
	    myNextChar = *(const unsigned char *)theSrc++;
	    *myCurDst++ = myChar;
	    myChar = myNextChar;
	    if (++myLength >= 255)
		break;
	}
    }
    else if (theSrc != NULL)
    {
	unsigned char		*myCurDst = &theDst[1];
	short 			myOverflow = 255;		// count down, so test it loop is faster
	register char		myTemp;

	// we can't do the K&R C thing of “while (*s++ = *t++)” because it will copy the trailing zero,
	// which might overrun the Pascal buffer; instead, we use a temp variable
	while ((myTemp = *theSrc++) != 0)
	{
	    *(char *)myCurDst++ = myTemp;
	    if (--myOverflow <= 0)
		break;
	}
	myLength = 255 - myOverflow;
    }
    
    // set the length of the destination Pascal string
    theDst[0] = myLength;
}

-(void) checkError:(OSErr)error message:(NSString *)msg
{
    if (error != noErr)
    {
	NSLog(@"Error code = %d", error);
	NSRunAlertPanel(@"Error", msg , @"OK", nil, nil);
    }
}
@end
