/* Copyright (c) 2004, Noah Sorscher
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 	¥ 	Redistributions of source code must retain the above copyright
 * 	notice, this list of conditions and the following disclaimer.
 * 	¥ 	Redistributions in binary form must reproduce the above copyright
 * 	notice, this list of conditions and the following disclaimer in the
 * 	documentation and/or other materials provided with the distribution.
 * 	¥ 	Neither the name of the Noah Sorscher nor the names of its
 * 	contributors may be used to endorse or promote products derived from
 * 	this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */
#import "tSprite.h"
//#include "Movies.h"
//#include "SpriteUtilities.h"
//#include "WiredSpriteUtilities.h"
//#import "tModel.h"
#import "tController.h"
//#include "EndianUtilities.h"
//#include "ComApplication.h"
//#include "MacFramework.h"



@implementation tSprite


- (IBAction)openSprites:(id)sender
{
    MHSprite *s = [MHSprite goWithMovie:[controller currentMovie]];
    if (first) {
	[s populateMenu:spriteMenu];
	first = NO;
    }
}

- (void)awakeFromNib
{
    first = YES;
}
/*

OSErr AddIconMovieSamplesToMedia (Media theMedia, PicHandle myPicture);
void QTWired_SetTrackProperties (Media theMedia, UInt32 theIdleFrequency);
StringPtr QTUtils_ConvertCToPascalString (char *theString);
//OSErr QTFrame_PutFile (ConstStr255Param thePrompt, ConstStr255Param theFileName, FSSpecPtr theFSSpecPtr, Boolean *theIsSelected, Boolean *theIsReplacing);
OSErr AddPICTImageToKeyFrameSample(QTAtomContainer theKeySample, PicHandle myPicture, RGBColor *theKeyColor, QTAtomID theID, FixedPoint *theRegistrationPoint, StringPtr theImageName);


- (IBAction)addSSMenu:(id)sender
{
    int width, height;
    NSMovie *theMovie = nil;
    theMovie = [movieView movie];
    if (nil == theMovie) return;
    Rect aRect;
    GetMovieBox([theMovie QTMovie], &aRect);
    width = aRect.right - aRect.left;
    height = aRect.bottom - aRect.top;
    float r, g, b, a;
    [[bgColor color] getRed:&r green:&g blue:&b alpha:&a];
    NSString *hex = [self HexFromR:r B:b G:g];
    NSString *header = [NSString stringWithFormat:@"<smil xmlns:qt=\"http://www.apple.com/quicktime/resources/smilextensions\" qt:time-slider=\"true\" qt:chapter-mode=\"all\">\n\t<head>\n\t\t<layout>\n\t\t\t<root-layout id=\"main\" width=\"%d\" height=\"%d\" background-color=\"#%@\"/>\n", width, height, hex];
    NSArray *chapters;// = [chap chaptersFromMovie:theMovie];
    if ([chapters count] == 0) return;
    // Set Regions Here
    int i, n = [chapters count];
    NSMutableString *regions = [NSMutableString stringWithCapacity:52 * n];
    for (i=0;i<n;i++) {
        [regions appendString:[NSString stringWithFormat:@"\t\t\t<region id=\"region%d\" width=\"%d%%\" height=\"%d%%\" left=\"%d%%\" top=\"%d%%\" />\n", i, 90, 100/n, 5, 100*i/n]];
    }
    // middle
    NSString *middle = @"\t\t</layout>\n\t</head>\n\t<body>\n\t\t<seq>\n\t\t\t<par dur=\"20\">\n";
    // pictures/links
    NSMutableString *links = [NSMutableString stringWithCapacity:100 * n];
    NSString *buffer;
    for (i=0;i<n;i++) {
        buffer = [self escapeString:[[chapters objectAtIndex:i] objectForKey:@"Content"]];
        [links appendString:[NSString stringWithFormat:@"\t\t\t\t<a href=\"#%@\" show=\"replace\">\n\t\t\t\t<text src=\"data:text/plain,%@\" region=\"region%d\" />\n\t\t\t\t</a>\n", buffer, buffer, i]];
    }
    NSString *middle2 = @"\t\t\t</par>\n";
    // content
    NSMutableString *content = [NSMutableString stringWithCapacity:125 * n];
    for (i=0;i<n;i++) {
        buffer = [self escapeString:[[chapters objectAtIndex:i] objectForKey:@"Content"]];
        [content appendString:[NSString stringWithFormat:@"\t\t\t<text region=\"region%d\" dur=\"60\" src=\"data:text/plain,%@\" fit=\"fill\" qt:chapter=\"%@\" />\n", i, buffer, buffer]];
    }
    NSString *end = @"\t\t</seq>\n\t</body>\n</smil>";
    NSString *all = [NSString stringWithFormat:@"%@%@%@%@%@%@%@", header, regions, middle, links, middle2, content, end];
    
    //write it
    NSFileManager *fm = [NSFileManager defaultManager];
    BOOL isDir;
    NSString *supportDir = [NSString stringWithFormat:@"%@/Metadata Hootenanny Support/", [fm currentDirectoryPath]];
    if (![fm fileExistsAtPath:supportDir isDirectory:&isDir])
        [fm createDirectoryAtPath:supportDir attributes:nil];
    [all writeToFile:[NSString stringWithFormat:@"%@smil.sml", supportDir] atomically:YES];
}

- (NSString *)escapeString:(NSString *)input
{
    int i, n = [input length];
    char ch;
    NSMutableString *output = [NSMutableString stringWithCapacity:2*n];
    for (i=0;i<n;i++) {
        ch = [input characterAtIndex:i];
        switch (ch) {
            case '"': case '\'': case '\\':
                [output appendString:[NSString stringWithFormat:@"\%c", ch]];
                break;
            default:
                [output appendString:[NSString stringWithFormat:@"%c", ch]];
                break;
        }
    }
    return output;
}

- (IBAction)addSTMenu:(id)sender
{
    NSMovie *theMovie = nil;
    theMovie = [movieView movie];
    if (nil == theMovie) return;
    Movie myMovie = [theMovie QTMovie];
    //OSType myType = FOUR_CHAR_CODE('none');
    //SetUserDataItem(GetMovieUserData(myMovie), &myType, sizeof(myType), kUserDataMovieControllerType, 1);
    
	//////////
	//
	// create the sprite track and media
	//
	//////////
	
	Fixed myWidth = Long2Fix(kIconSpriteTrackWidth);
	Fixed myHeight = Long2Fix(kIconSpriteTrackHeight);

	Track myTrack = NewMovieTrack(myMovie, myWidth, myHeight, kNoVolume);
	Media myMedia = NewTrackMedia(myTrack, SpriteMediaType, kSpriteMediaTimeScale, NULL, 0);

	OSErr myErr = BeginMediaEdits(myMedia);
	if (myErr != noErr) return;
            //goto bail;
        
	//////////
	//
	// add the appropriate samples to the sprite media
	//
	//////////
        
        
    // add images to the key frame sample
    //ImageDescriptionHandle myImageDesc = NULL;
    //Handle myCompressedPicture = NULL;
    //NSImage *anImage = [NSImage imageNamed:@"play.jpg"];
    //void *PicPtr = [[anImage TIFFRepresentation] bytes];
    TimeRecord currentTime;
    PicHandle picHandle = GetMoviePict(myMovie, GetMovieTime(myMovie, &currentTime));
        
	
	myErr = AddIconMovieSamplesToMedia(myMedia, picHandle);
	if (myErr != noErr) return;
		//goto bail;
	
	myErr = EndMediaEdits(myMedia);
	if (myErr != noErr) return;
		//goto bail;
	
	// add the media to the track
	InsertMediaIntoTrack(myTrack, 0, 0, GetMediaDuration(myMedia), fixed1);
		
	//////////
	//
	// set the sprite track properties
	//
	//////////
	
	QTWired_SetTrackProperties(myMedia, 1);
	
	//////////
	//
	// add the movie resource to the movie file
	//
	//////////
	
	//myErr = AddMovieResource(myMovie, myResRefNum, &myResID, myFile.name);
		
//bail:

	//if (myResRefNum != 0)
	//	CloseMovieFile(myResRefNum);

	//if (myMovie != NULL)
	//	DisposeMovie(myMovie);
		
	//free(myPrompt);
	//free(myFileName);

}

- (NSString *)HexFromR:(float)r B:(float)b G:(float)g
{
    NSMutableString *output = [[NSMutableString alloc] initWithCapacity:6];
    NSArray *digits = [NSArray arrayWithObjects:@"0", @"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", @"A", @"B", @"C", @"D", @"E", @"F", nil];
    int tens, ones;
    //Red
    tens = r * 255 / 16;
    ones = (int)(r * 255) % 16;
    [output appendString:[digits objectAtIndex:tens]];
    [output appendString:[digits objectAtIndex:ones]];
    //Green
    tens = g * 255 / 16;
    ones = (int)(g * 255) % 16;
    [output appendString:[digits objectAtIndex:tens]];
    [output appendString:[digits objectAtIndex:ones]];
    //Blue
    tens = b * 255 / 16;
    ones = (int)(b * 255) % 16;
    [output appendString:[digits objectAtIndex:tens]];
    [output appendString:[digits objectAtIndex:ones]];
    
    return output;
}

//////////
//
// QTWired_AddIconMovieSamplesToMedia
// Build the key frame for the icon sprite movie.
//
//////////

OSErr AddIconMovieSamplesToMedia (Media theMedia, PicHandle myPicture)
{
	QTAtomContainer			mySample = NULL;
	QTAtomContainer			mySpriteData = NULL;
	RGBColor				myKeyColor;
	Point					myLocation;
	short					isVisible, myIndex;
	FixedPoint				myPoint;
	OSErr					myErr = noErr;
	
	//////////
	//
	// create a key frame sample containing the sprite images
	//
	//////////

	// create a new, empty key frame sample
	myErr = QTNewAtomContainer(&mySample);
	if (myErr != noErr)
		goto bail;

	myKeyColor.red = myKeyColor.green = myKeyColor.blue = 0xffff;		// white
	
	myPoint.x = Long2Fix(kIconDimension / 2);
	myPoint.y = Long2Fix(kIconDimension / 2);

	// add images to the key frame sample
	AddPICTImageToKeyFrameSample(mySample, myPicture, &myKeyColor, 1, &myPoint, NULL);
	AddPICTImageToKeyFrameSample(mySample, myPicture, &myKeyColor, 2, &myPoint, NULL);

	//////////
	//
	// add the initial sprite properties to the key frame sample
	//
	//////////
	
	myErr = QTNewAtomContainer(&mySpriteData);
	if (myErr != noErr)
		goto bail;

	// the QT icon sprite
	myLocation.h 	= kIconDimension + (kIconDimension / 2);
	myLocation.v	= kIconDimension + (kIconDimension / 2);
	isVisible		= true;
	myIndex			= kNewQTIconImageIndex;
	
	SpriteUtils_SetSpriteData(mySpriteData, &myLocation, &isVisible, NULL, &myIndex, NULL, NULL, NULL);
	SpriteUtils_AddSpriteToSample(mySample, mySpriteData, kQTIconSpriteAtomID);
	//QTWired_MakeSpriteDraggable(mySample, kQTIconSpriteAtomID);
	//QTWired_AddCursorChangeToSprite(mySample, kQTIconSpriteAtomID);
	SpriteUtils_AddSpriteSampleToMedia(theMedia, mySample, kSpriteMediaFrameDurationIcon, true, NULL);	

bail:	
	if (mySample != NULL)
		QTDisposeAtomContainer(mySample);

	if (mySpriteData != NULL)
		QTDisposeAtomContainer(mySpriteData);
	
	return(myErr);
}

//////////
//
// QTWired_SetTrackProperties
// Set the track properties for the specified sample sprite movie.
//
//////////

void QTWired_SetTrackProperties (Media theMedia, UInt32 theIdleFrequency)
{
	QTAtomContainer		myTrackProperties;
	RGBColor			myBackgroundColor;
	Boolean				hasActions;
	UInt32				myFrequency;
	OSErr				myErr = noErr;
		
	// add a background color to the sprite track
	myBackgroundColor.red = EndianU16_NtoB(0xffff);
	myBackgroundColor.green = EndianU16_NtoB(0xffff);
	myBackgroundColor.blue = EndianU16_NtoB(0xffff);
	
	myErr = QTNewAtomContainer(&myTrackProperties);
	if (myErr == noErr) {
		QTInsertChild(myTrackProperties, 0, kSpriteTrackPropertyBackgroundColor, 1, 1, sizeof(myBackgroundColor), &myBackgroundColor, NULL);

		// tell the movie controller that this sprite track has actions
		hasActions = true;
		QTInsertChild(myTrackProperties, 0, kSpriteTrackPropertyHasActions, 1, 1, sizeof(hasActions), &hasActions, NULL);
	
		// tell the sprite track to generate QTIdleEvents
		myFrequency = EndianU32_NtoB(theIdleFrequency);
		QTInsertChild(myTrackProperties, 0, kSpriteTrackPropertyQTIdleEventsFrequency, 1, 1, sizeof(myFrequency), &myFrequency, NULL);

		SetMediaPropertyAtom(theMedia, myTrackProperties);
		
		QTDisposeAtomContainer(myTrackProperties);
	}
}
	



/ *
	short					myResRefNum = 0;
	//short					myResID = movieInDataForkResID;
	Movie					myMovie = NULL;
	Track					myTrack;
	Media					myMedia;
	FSSpec					myFile;
	//Boolean					myIsSelected = false;
	//Boolean					myIsReplacing = false;	
	StringPtr 				myPrompt = QTUtils_ConvertCToPascalString(kWiredSavePrompt);
	StringPtr 				myFileName = QTUtils_ConvertCToPascalString(kWiredSaveFileName);
	QTAtomContainer			mySample = NULL;
	QTAtomContainer			myActions = NULL;
	QTAtomContainer			myBeginButton, myPrevButton, myNextButton, myEndButton;
	QTAtomContainer			myPenguinOne, myPenguinTwo, myPenguinOneOverride;
	QTAtomContainer			myBeginActionButton, myPrevActionButton, myNextActionButton, myEndActionButton;
	QTAtomContainer			myPenguinOneAction, myPenguinTwoAction;
	RGBColor				myKeyColor;
	Point					myLocation;
	short					isVisible, myLayer, myIndex, myID, i, myDelta;
	Boolean					hasActions;
	long					myFlags = createMovieFileDeleteCurFile | createMovieFileDontCreateResFile;
	OSType					myType = FOUR_CHAR_CODE('none');
	UInt32					myFrequency;
	QTAtom					myEventAtom;
	long					myLoopingFlags;
	ModifierTrackGraphicsModeRecord		myGraphicsMode;
	OSErr					myErr = noErr;

	//////////
	//
	// create a new movie file and set its controller type
	//
	//////////
     / *
	// ask the user for the name of the new movie file
	QTFrame_PutFile(myPrompt, myFileName, &myFile, &myIsSelected, &myIsReplacing);
	if (!myIsSelected)
		goto bail;
    
        FSRef fsRef;
        NSString *newPath = @"/Users/nsorscher/Sprite.mov";
        if (![[NSFileManager defaultManager] fileExistsAtPath:newPath])
        [[NSString stringWithString:@"this file is empty"] writeToFile:newPath atomically:NO];
        //myErr = FSPathMakeRef([newPath fileSystemRepresentation],&fsRef, NULL / * isDirectory *///);
        //myErr = FSGetCatalogInfo(&fsRef, kFSCatInfoNone, NULL / *catalogInfo*/, NULL / *outName*/, &myFile, NULL / *parentRef*/);
        
    /*
	// create a movie file for the destination movie
	myErr = CreateMovieFile(&myFile, FOUR_CHAR_CODE('TVOD'), smSystemScript, myFlags, &myResRefNum, &myMovie);
	if (myErr != noErr)
		goto bail;
	
	// select the "no controller" movie controller
	myType = EndianU32_NtoB(myType);
	SetUserDataItem(GetMovieUserData(myMovie), &myType, sizeof(myType), kUserDataMovieControllerType, 1);
        
        //myMovie = [[movieView movie] QTMovie];
	//////////
	//
	// create the sprite track and media
	//
	//////////
	
	myTrack = NewMovieTrack(myMovie, ((long)kSpriteTrackWidth << 16), ((long)kSpriteTrackHeight << 16), kNoVolume);
	myMedia = NewTrackMedia(myTrack, SpriteMediaType, kSpriteMediaTimeScale, NULL, 0);

	//////////
	//
	// create a key frame sample containing six sprites and all of their shared images
	//
	//////////

	// create a new, empty key frame sample
	myErr = QTNewAtomContainer(&mySample);
	if (myErr != noErr)
		goto bail;

	myKeyColor.red = 0xffff;						// white
	myKeyColor.green = 0xffff;
	myKeyColor.blue = 0xffff;

	// add images to the key frame sample
        TimeRecord currentTime;
        PicHandle picHandle = GetMoviePict(myMovie, GetMovieTime(myMovie, &currentTime));
        
	AddPICTImageToKeyFrameSample(mySample, picHandle, &myKeyColor, kGoToBeginningButtonUpIndex, NULL, NULL);
	AddPICTImageToKeyFrameSample(mySample, picHandle, &myKeyColor, kGoToBeginningButtonDownIndex, NULL, NULL);
	AddPICTImageToKeyFrameSample(mySample, picHandle, &myKeyColor, kGoToEndButtonUpIndex, NULL, NULL);
	AddPICTImageToKeyFrameSample(mySample, picHandle, &myKeyColor, kGoToEndButtonDownIndex, NULL, NULL);
	AddPICTImageToKeyFrameSample(mySample, picHandle, &myKeyColor, kGoToPrevButtonUpIndex, NULL, NULL);
	AddPICTImageToKeyFrameSample(mySample, picHandle, &myKeyColor, kGoToPrevButtonDownIndex, NULL, NULL);
	AddPICTImageToKeyFrameSample(mySample, picHandle, &myKeyColor, kGoToNextButtonUpIndex, NULL, NULL);
	AddPICTImageToKeyFrameSample(mySample, picHandle, &myKeyColor, kGoToNextButtonDownIndex, NULL, NULL);
	AddPICTImageToKeyFrameSample(mySample, picHandle, &myKeyColor, kPenguinForwardIndex, NULL, NULL);
	AddPICTImageToKeyFrameSample(mySample, picHandle, &myKeyColor, kPenguinLeftIndex, NULL, NULL);
	AddPICTImageToKeyFrameSample(mySample, picHandle, &myKeyColor, kPenguinRightIndex, NULL, NULL);
	AddPICTImageToKeyFrameSample(mySample, picHandle, &myKeyColor, kPenguinClosedIndex, NULL, NULL);

	for (myIndex = kPenguinDownRightCycleStartIndex, myID = kWalkDownRightCycleStart; myIndex <= kPenguinDownRightCycleEndIndex; myIndex++, myID++)
		AddPICTImageToKeyFrameSample(mySample, picHandle, &myKeyColor, myIndex, NULL, NULL);
	
	// assign group IDs to the images
	SpriteUtils_AssignImageGroupIDsToKeyFrame(mySample);
	
	//////////
	//
	// add samples to the sprite track's media
	//
	//////////
	
	BeginMediaEdits(myMedia);

	// go to beginning button with no actions
	myErr = QTNewAtomContainer(&myBeginButton);
	if (myErr != noErr)
		goto bail;
	myLocation.h	= (1 * kSpriteTrackWidth / 8) - (kStartEndButtonWidth / 2);
	myLocation.v	= (4 * kSpriteTrackHeight / 5) - (kStartEndButtonHeight / 2);
	isVisible		= false;
	myLayer			= 1;
	myIndex			= kGoToBeginningButtonUpIndex;
	myErr = SpriteUtils_SetSpriteData(myBeginButton, &myLocation, &isVisible, &myLayer, &myIndex, NULL, NULL, myActions);
	if (myErr != noErr)
		goto bail;

	// go to previous button with no actions
	myErr = QTNewAtomContainer(&myPrevButton);
	if (myErr != noErr)
		goto bail;
	myLocation.h 	= (3 * kSpriteTrackWidth / 8) - (kNextPrevButtonWidth / 2);
	myLocation.v	= (4 * kSpriteTrackHeight / 5) - (kStartEndButtonHeight / 2);
	isVisible		= false;
	myLayer			= 1;
	myIndex			= kGoToPrevButtonUpIndex;
	myErr = SpriteUtils_SetSpriteData(myPrevButton, &myLocation, &isVisible, &myLayer, &myIndex, NULL, NULL, myActions);
	if (myErr != noErr)
		goto bail;

	// go to next button with no actions
	myErr = QTNewAtomContainer(&myNextButton);
	if (myErr != noErr)
		goto bail;
	myLocation.h 	= (5 * kSpriteTrackWidth / 8) - (kNextPrevButtonWidth / 2);
	myLocation.v	= (4 * kSpriteTrackHeight / 5) - (kStartEndButtonHeight / 2);
	isVisible		= false;
	myLayer			= 1;
	myIndex			= kGoToNextButtonUpIndex;
	myErr = SpriteUtils_SetSpriteData(myNextButton, &myLocation, &isVisible, &myLayer, &myIndex, NULL, NULL, myActions);
	if (myErr != noErr)
		goto bail;

	// go to end button with no actions
	myErr = QTNewAtomContainer(&myEndButton);
	if (myErr != noErr)
		goto bail;
	myLocation.h 	= (7 * kSpriteTrackWidth / 8) - (kStartEndButtonWidth / 2);
	myLocation.v	= (4 * kSpriteTrackHeight / 5) - (kStartEndButtonHeight / 2);
	isVisible		= false;
	myLayer			= 1;
	myIndex			= kGoToEndButtonUpIndex;
	myErr = SpriteUtils_SetSpriteData(myEndButton, &myLocation, &isVisible, &myLayer, &myIndex, NULL, NULL, myActions);
	if (myErr != noErr)
		goto bail;

	// first penguin sprite with no actions
	myErr = QTNewAtomContainer(&myPenguinOne);
	if (myErr != noErr)
		goto bail;
	myLocation.h 	= (3 * kSpriteTrackWidth / 8) - (kPenguinWidth / 2);
	myLocation.v 	= (kSpriteTrackHeight / 4) - (kPenguinHeight / 2);
	isVisible		= true;
	myLayer			= 2;
	myIndex			= kPenguinDownRightCycleStartIndex;
	myGraphicsMode.graphicsMode = blend;
	myGraphicsMode.opColor.red = myGraphicsMode.opColor.green = myGraphicsMode.opColor.blue = 0x8FFF;	// grey
	myErr = SpriteUtils_SetSpriteData(myPenguinOne, &myLocation, &isVisible, &myLayer, &myIndex, &myGraphicsMode, NULL, myActions);
	if (myErr != noErr)
		goto bail;
		
	// second penguin sprite with no actions
	myErr = QTNewAtomContainer(&myPenguinTwo);
	if (myErr != noErr)
		goto bail;
	myLocation.h 	= (5 * kSpriteTrackWidth / 8) - (kPenguinWidth / 2);
	myLocation.v 	= (kSpriteTrackHeight / 4) - (kPenguinHeight / 2);
	isVisible		= true;
	myLayer			= 3;
	myIndex			= kPenguinForwardIndex;
	myErr = SpriteUtils_SetSpriteData(myPenguinTwo, &myLocation, &isVisible, &myLayer, &myIndex, NULL, NULL, myActions);
	if (myErr != noErr)
		goto bail;

	//////////
	//
	// add actions to the six sprites
	//
	//////////

	// add go to beginning button
	myErr = QTCopyAtom(myBeginButton, kParentAtomIsContainer, &myBeginActionButton);
	if (myErr != noErr)
		goto bail;

	WiredUtils_AddSpriteSetImageIndexAction(myBeginActionButton, kParentAtomIsContainer, kQTEventMouseClick, 0, NULL, 0, 0, NULL, kGoToBeginningButtonDownIndex, NULL);
	WiredUtils_AddSpriteSetImageIndexAction(myBeginActionButton, kParentAtomIsContainer, kQTEventMouseClickEnd, 0, NULL, 0, 0, NULL, kGoToBeginningButtonUpIndex, NULL);
	WiredUtils_AddMovieGoToBeginningAction(myBeginActionButton, kParentAtomIsContainer, kQTEventMouseClickEndTriggerButton);
	WiredUtils_AddSpriteSetVisibleAction(myBeginActionButton, kParentAtomIsContainer, kQTEventMouseEnter, 0, NULL, 0, 0, NULL, true, NULL);
	WiredUtils_AddSpriteSetVisibleAction(myBeginActionButton, kParentAtomIsContainer, kQTEventMouseExit, 0, NULL, 0, 0, NULL, false, NULL);
	SpriteUtils_AddSpriteToSample(mySample, myBeginActionButton, kGoToBeginningSpriteID);	
	QTDisposeAtomContainer(myBeginActionButton);

	// add go to prev button
	myErr = QTCopyAtom(myPrevButton, kParentAtomIsContainer, &myPrevActionButton);
	if (myErr != noErr)
		goto bail;

	WiredUtils_AddSpriteSetImageIndexAction(myPrevActionButton, kParentAtomIsContainer, kQTEventMouseClick, 0, NULL, 0, 0, NULL, kGoToPrevButtonDownIndex, NULL);
	WiredUtils_AddSpriteSetImageIndexAction(myPrevActionButton, kParentAtomIsContainer, kQTEventMouseClickEnd, 0, NULL, 0, 0, NULL, kGoToPrevButtonUpIndex, NULL);
	WiredUtils_AddMovieStepBackwardAction(myPrevActionButton, kParentAtomIsContainer, kQTEventMouseClickEndTriggerButton);
	WiredUtils_AddSpriteSetVisibleAction(myBeginActionButton, kParentAtomIsContainer, kQTEventMouseEnter, 0, NULL, 0, 0, NULL, true, NULL);
	WiredUtils_AddSpriteSetVisibleAction(myBeginActionButton, kParentAtomIsContainer, kQTEventMouseExit, 0, NULL, 0, 0, NULL, false, NULL);
	SpriteUtils_AddSpriteToSample(mySample, myPrevActionButton, kGoToPrevSpriteID);
	QTDisposeAtomContainer(myPrevActionButton);

	// add go to next button
	myErr = QTCopyAtom(myNextButton, kParentAtomIsContainer, &myNextActionButton);
	if (myErr != noErr)
		goto bail;

	WiredUtils_AddSpriteSetImageIndexAction(myNextActionButton, kParentAtomIsContainer, kQTEventMouseClick, 0, NULL, 0, 0, NULL, kGoToNextButtonDownIndex, NULL);
	WiredUtils_AddSpriteSetImageIndexAction(myNextActionButton, kParentAtomIsContainer, kQTEventMouseClickEnd, 0, NULL, 0, 0, NULL, kGoToNextButtonUpIndex, NULL);
	WiredUtils_AddMovieStepForwardAction(myNextActionButton, kParentAtomIsContainer, kQTEventMouseClickEndTriggerButton);
	WiredUtils_AddSpriteSetVisibleAction(myBeginActionButton, kParentAtomIsContainer, kQTEventMouseEnter, 0, NULL, 0, 0, NULL, true, NULL);
	WiredUtils_AddSpriteSetVisibleAction(myBeginActionButton, kParentAtomIsContainer, kQTEventMouseExit, 0, NULL, 0, 0, NULL, false, NULL);
	SpriteUtils_AddSpriteToSample(mySample, myNextActionButton, kGoToNextSpriteID);
	QTDisposeAtomContainer(myNextActionButton);

	// add go to end button
	myErr = QTCopyAtom(myEndButton, kParentAtomIsContainer, &myEndActionButton);
	if (myErr != noErr)
		goto bail;

	WiredUtils_AddSpriteSetImageIndexAction(myEndActionButton, kParentAtomIsContainer, kQTEventMouseClick, 0, NULL, 0, 0, NULL, kGoToEndButtonDownIndex, NULL);
	WiredUtils_AddSpriteSetImageIndexAction(myEndActionButton, kParentAtomIsContainer, kQTEventMouseClickEnd, 0, NULL, 0, 0, NULL, kGoToEndButtonUpIndex, NULL);
	WiredUtils_AddMovieGoToEndAction(myEndActionButton, kParentAtomIsContainer, kQTEventMouseClickEndTriggerButton);
	WiredUtils_AddSpriteSetVisibleAction(myBeginActionButton, kParentAtomIsContainer, kQTEventMouseEnter, 0, NULL, 0, 0, NULL, true, NULL);
	WiredUtils_AddSpriteSetVisibleAction(myBeginActionButton, kParentAtomIsContainer, kQTEventMouseExit, 0, NULL, 0, 0, NULL, false, NULL);
	SpriteUtils_AddSpriteToSample(mySample, myEndActionButton, kGoToEndSpriteID);
	QTDisposeAtomContainer(myEndActionButton);

	// add penguin one
	myErr = QTCopyAtom(myPenguinOne, kParentAtomIsContainer, &myPenguinOneAction);
	if (myErr != noErr)
		goto bail;

	// show the buttons on mouse enter and hide them on mouse exit
	WiredUtils_AddSpriteSetVisibleAction(myPenguinOneAction, kParentAtomIsContainer, kQTEventMouseEnter, 0, NULL, 0, kTargetSpriteID, (void *)kGoToBeginningSpriteID, true, NULL);
	WiredUtils_AddSpriteSetVisibleAction(myPenguinOneAction, kParentAtomIsContainer, kQTEventMouseExit, 0, NULL, 0, kTargetSpriteID, (void *)kGoToBeginningSpriteID, false, NULL);
	WiredUtils_AddSpriteSetVisibleAction(myPenguinOneAction, kParentAtomIsContainer, kQTEventMouseEnter, 0, NULL, 0, kTargetSpriteID, (void *)kGoToPrevSpriteID, true, NULL);
	WiredUtils_AddSpriteSetVisibleAction(myPenguinOneAction, kParentAtomIsContainer, kQTEventMouseExit, 0, NULL, 0, kTargetSpriteID, (void *)kGoToPrevSpriteID, false, NULL);
	WiredUtils_AddSpriteSetVisibleAction(myPenguinOneAction, kParentAtomIsContainer, kQTEventMouseEnter, 0, NULL, 0, kTargetSpriteID, (void *)kGoToNextSpriteID, true, NULL);
	WiredUtils_AddSpriteSetVisibleAction(myPenguinOneAction, kParentAtomIsContainer, kQTEventMouseExit, 0, NULL, 0, kTargetSpriteID, (void *)kGoToNextSpriteID, false, NULL);
	WiredUtils_AddSpriteSetVisibleAction(myPenguinOneAction, kParentAtomIsContainer, kQTEventMouseEnter, 0, NULL, 0, kTargetSpriteID, (void *)kGoToEndSpriteID, true, NULL);
	WiredUtils_AddSpriteSetVisibleAction(myPenguinOneAction, kParentAtomIsContainer, kQTEventMouseExit, 0, NULL, 0, kTargetSpriteID, (void *)kGoToEndSpriteID, false, NULL);
	SpriteUtils_AddSpriteToSample(mySample, myPenguinOneAction, kPenguinOneSpriteID);
	//QTWired_AddCursorChangeOnMouseOver(mySample, kPenguinOneSpriteID);
	QTDisposeAtomContainer(myPenguinOneAction);

	// add penguin two
	myErr = QTCopyAtom(myPenguinTwo, kParentAtomIsContainer, &myPenguinTwoAction);
	if (myErr != noErr)
		goto bail;

	// blink when clicked on
	WiredUtils_AddSpriteSetImageIndexAction(myPenguinTwoAction, kParentAtomIsContainer, kQTEventMouseClick, 0, NULL, 0, 0, NULL, kPenguinClosedIndex, NULL);
	WiredUtils_AddSpriteSetImageIndexAction(myPenguinTwoAction, kParentAtomIsContainer, kQTEventMouseClickEnd, 0, NULL, 0, 0, NULL, kPenguinForwardIndex, NULL);

	WiredUtils_AddQTEventAtom(myPenguinTwoAction, kParentAtomIsContainer, kQTEventMouseClickEndTriggerButton, &myEventAtom);

	// toggle the movie rate and both of the birds' graphics modes
	//QTWired_AddPenguinTwoConditionalActions(myPenguinTwoAction, myEventAtom);

	//QTWired_AddWraparoundMatrixOnIdle(myPenguinTwoAction);

	SpriteUtils_AddSpriteToSample(mySample, myPenguinTwoAction, kPenguinTwoSpriteID);
	QTDisposeAtomContainer(myPenguinTwoAction);
	
	// add an action for when the key frame is loaded, to set the movie's looping mode to palindrome;
	// note that this will actually be triggered every time the key frame is reloaded,
	// so if the operation was expensive we could use a conditional to test if we've already done it
	myLoopingFlags = loopTimeBase | palindromeLoopTimeBase;
	WiredUtils_AddMovieSetLoopingFlagsAction(mySample, kParentAtomIsContainer, kQTEventFrameLoaded, myLoopingFlags);

	// add the key frame sample to the sprite track media
	//
	// to add the sample data in a compressed form, you would use a QuickTime DataCodec to perform the
	// compression; replace the call to the utility AddSpriteSampleToMedia with a call to the utility
	// AddCompressedSpriteSampleToMedia to do this
	
	SpriteUtils_AddSpriteSampleToMedia(myMedia, mySample, kSpriteMediaFrameDuration, true, NULL);	
	//SpriteUtils_AddCompressedSpriteSampleToMedia(myMedia, mySample, kSpriteMediaFrameDuration, true, zlibDataCompressorSubType, NULL);

	//////////
	//
	// add a few override samples to move penguin one and change its image index
	//
	//////////

	// original penguin one location
	myLocation.h 	= (3 * kSpriteTrackWidth / 8) - (kPenguinWidth / 2);
	myLocation.v 	= (kSpriteTrackHeight / 4) - (kPenguinHeight / 2);

	myDelta = (kSpriteTrackHeight / 2) / kNumOverrideSamples;
	myIndex = kPenguinDownRightCycleStartIndex;
	
	for (i = 1; i <= kNumOverrideSamples; i++) {
		QTRemoveChildren(mySample, kParentAtomIsContainer);
		QTNewAtomContainer(&myPenguinOneOverride);

		myLocation.h += myDelta;
		myLocation.v += myDelta;
		myIndex++;
		if (myIndex > kPenguinDownRightCycleEndIndex)
			myIndex = kPenguinDownRightCycleStartIndex;
			
		SpriteUtils_SetSpriteData(myPenguinOneOverride, &myLocation, NULL, NULL, &myIndex, NULL, NULL, NULL);
		SpriteUtils_AddSpriteToSample(mySample, myPenguinOneOverride, kPenguinOneSpriteID);
		SpriteUtils_AddSpriteSampleToMedia(myMedia, mySample, kSpriteMediaFrameDuration, false, NULL);	
		QTDisposeAtomContainer(myPenguinOneOverride);
	}

	EndMediaEdits(myMedia);
	
	// add the media to the track
	InsertMediaIntoTrack(myTrack, 0, 0, GetMediaDuration(myMedia), fixed1);
	
	//////////
	//
	// set the sprite track properties
	//
	//////////
	{
		QTAtomContainer		myTrackProperties;
		RGBColor			myBackgroundColor;
		
		// add a background color to the sprite track
		myBackgroundColor.red = EndianU16_NtoB(0x8000);
		myBackgroundColor.green = EndianU16_NtoB(0);
		myBackgroundColor.blue = EndianU16_NtoB(0xffff);
		
		QTNewAtomContainer(&myTrackProperties);
		QTInsertChild(myTrackProperties, 0, kSpriteTrackPropertyBackgroundColor, 1, 1, sizeof(RGBColor), &myBackgroundColor, NULL);

		// tell the movie controller that this sprite track has actions, Jackson
		hasActions = true;
		QTInsertChild(myTrackProperties, 0, kSpriteTrackPropertyHasActions, 1, 1, sizeof(hasActions), &hasActions, NULL);
	
		// tell the sprite track to generate QTIdleEvents
		myFrequency = EndianU32_NtoB(60);
		QTInsertChild(myTrackProperties, 0, kSpriteTrackPropertyQTIdleEventsFrequency, 1, 1, sizeof(myFrequency), &myFrequency, NULL);
		myErr = SetMediaPropertyAtom(myMedia, myTrackProperties);
		if (myErr != noErr)
			goto bail;

		QTDisposeAtomContainer(myTrackProperties);
	}
	
	//////////
	//
	// finish up
	//
	//////////
	
	// add the movie resource to the movie file
	//myErr = AddMovieResource(myMovie, myResRefNum, &myResID, myFile.name);
	
bail:
	free(myPrompt);
	free(myFileName);

	if (mySample != NULL)
		QTDisposeAtomContainer(mySample);

	if (myBeginButton != NULL)
		QTDisposeAtomContainer(myBeginButton);	
			
	if (myPrevButton != NULL)
		QTDisposeAtomContainer(myPrevButton);
				
	if (myNextButton != NULL)
		QTDisposeAtomContainer(myNextButton);
				
	if (myEndButton != NULL)
		QTDisposeAtomContainer(myEndButton);		
		
	if (myResRefNum != 0)
		CloseMovieFile(myResRefNum);

	if (myMovie != NULL)
		DisposeMovie(myMovie);
        
        
        [[controller getModel] saveMovieOfIndex:0 dir:@"/"];
		
}

*

OSErr AddPICTImageToKeyFrameSample(QTAtomContainer theKeySample, PicHandle myPicture, RGBColor *theKeyColor, QTAtomID theID, FixedPoint *theRegistrationPoint, StringPtr theImageName)
{
	Handle					myCompressedPicture = NULL;
	ImageDescriptionHandle			myImageDesc = NULL;
	OSErr					myErr = noErr;
	
	if (myPicture == NULL)
		myErr = resNotFound;

	if (myErr != noErr)
		goto bail;
	
	DetachResource((Handle)myPicture);
	
	// convert it to image data compressed by the animation compressor
	//myErr = ICUtils_RecompressPictureWithTransparency(myPicture, theKeyColor, NULL, &myImageDesc, &myCompressedPicture);
	//if (myErr != noErr)
	//	goto bail;
        myCompressedPicture = myPicture;

	// add it to the key sample
	HLock(myCompressedPicture);
	myErr = SpriteUtils_AddCompressedImageToKeyFrameSample(theKeySample, myImageDesc, GetHandleSize(myCompressedPicture), *myCompressedPicture, theID, theRegistrationPoint, theImageName);
	
bail:
	//if (myPicture != NULL)
	//	KillPicture(myPicture);
		
	//if (myCompressedPicture != NULL)
	//	DisposeHandle(myCompressedPicture);
		
	//if (myImageDesc != NULL)
	//	DisposeHandle((Handle)myImageDesc);
		
	return(myErr);

}

/ *

//////////
//
// QTUtils_ConvertCToPascalString
// Convert a C string into a Pascal string.
//
// The caller is responsible for disposing of the pointer returned by this function (by calling free).
//
//////////

StringPtr QTUtils_ConvertCToPascalString (char *theString)
{
	StringPtr	myString = malloc(strlen(theString) + 1);
	short		myIndex = 0;

	while (theString[myIndex] != '\0') {
		myString[myIndex + 1] = theString[myIndex];
		myIndex++;
	}
	
	myString[0] = (unsigned char)myIndex;
	
	return(myString);
}

//////////
//
// QTFrame_PutFile
// Save a file under the specified name. Return Boolean values indicating whether the user selected a file
// and whether the selected file is replacing an existing file.
//
//////////
/ *
OSErr QTFrame_PutFile (ConstStr255Param thePrompt, ConstStr255Param theFileName, FSSpecPtr theFSSpecPtr, Boolean *theIsSelected, Boolean *theIsReplacing)
{
#if TARGET_OS_WIN32
	StandardFileReply	myReply;
#endif
#if TARGET_OS_MAC
	NavReplyRecord		myReply;
	NavDialogOptions	myDialogOptions;
	NavEventUPP		myEventUPP = NewNavEventUPP(QTFrame_HandleNavEvent);
#endif
	OSErr				myErr = noErr;

	if ((theFSSpecPtr == NULL) || (theIsSelected == NULL) || (theIsReplacing == NULL))
		return(paramErr);
	
	// deactivate any frontmost movie window
	//QTFrame_ActivateController(QTFrame_GetFrontMovieWindow(), false);

	// assume we are not replacing an existing file
	*theIsReplacing = false;
	
#if TARGET_OS_WIN32
	StandardPutFile(thePrompt, theFileName, &myReply);
	*theFSSpecPtr = myReply.sfFile;
	*theIsSelected = myReply.sfGood;
	if (myReply.sfGood)
		*theIsReplacing = myReply.sfReplacing;
#endif

#if TARGET_OS_MAC
	// specify the options for the dialog box
	NavGetDefaultDialogOptions(&myDialogOptions);
	myDialogOptions.dialogOptionFlags += kNavNoTypePopup;
	myDialogOptions.dialogOptionFlags += kNavDontAutoTranslate;
	BlockMoveData(theFileName, myDialogOptions.savedFileName, theFileName[0] + 1);
	BlockMoveData(gAppName, myDialogOptions.clientName, gAppName[0] + 1);
	BlockMoveData(thePrompt, myDialogOptions.message, thePrompt[0] + 1);
	
	// prompt the user for a file
	myErr = NavPutFile(NULL, &myReply, &myDialogOptions, myEventUPP, MovieFileType, sigMoviePlayer, NULL);
	if ((myErr == noErr) && myReply.validRecord) {
		AEKeyword		myKeyword;
		DescType		myActualType;
		Size			myActualSize = 0;
		
		// get the FSSpec for the selected file
		if (theFSSpecPtr != NULL)
			myErr = AEGetNthPtr(&(myReply.selection), 1, typeFSS, &myKeyword, &myActualType, theFSSpecPtr, sizeof(FSSpec), &myActualSize);
	}
		
	*theIsSelected = myReply.validRecord;
	if (myReply.validRecord)
		*theIsReplacing = myReply.replacing;
		
	NavDisposeReply(&myReply);
	DisposeNavEventUPP(myEventUPP);
#endif

	return(myErr);
}
	
*/
/*
    NSMovie *theMovie = nil;
    theMovie = [movieView movie];
    if (theMovie == nil) return;
    Movie myMovie = [theMovie QTMovie];
    int myWidth = 320;
    int myHeight = 240;
    RGBColor myKeyColor;
    float r, g, b;
    OSErr myErr = noErr;
    QTAtomContainer mySample = NULL;
    QTAtomContainer myTestButton = NULL;
    QTAtomContainer myActions = NULL;
    Track myTrack = NewMovieTrack(myMovie, myWidth, myHeight, kNoVolume);
    Media myMedia = NewTrackMedia(myTrack, SpriteMediaType, 600, NULL, 0);
    Point myLocation;
    short isVisible, myLayer, myIndex, myID, i, myDelta;

    
    
    myErr = QTNewAtomContainer(&mySample);
    if (myErr != noErr) return;
    
    [[bgColor color] getRed:&r green:&g blue:&b alpha:nil];
    myKeyColor.red = r * 0xffff;
    myKeyColor.green = g * 0xffff;
    myKeyColor.blue = b * 0xffff;
    
    // add images to the key frame sample
    ImageDescriptionHandle myImageDesc = NULL;
    Handle myCompressedPicture = NULL;
    //NSImage *anImage = [NSImage imageNamed:@"play.jpg"];
    //void *PicPtr = [[anImage TIFFRepresentation] bytes];
    TimeRecord currentTime;
    PicHandle picHandle = GetMoviePict(myMovie, GetMovieTime(myMovie, &currentTime));
    // convert it to image data compressed by the animation compressor
    myErr = ICUtils_RecompressPictureWithTransparency(picHandle, &myKeyColor, NULL, &myImageDesc, &myCompressedPicture);
    // add it to the key sample
    HLock(myCompressedPicture);
    myErr = SpriteUtils_AddCompressedImageToKeyFrameSample(mySample, myImageDesc, GetHandleSize(myCompressedPicture), *myCompressedPicture, 1, NULL, NULL);
    // assign group IDs to the images
    //SpriteUtils_AssignImageGroupIDsToKeyFrame(mySample);
    
    BeginMediaEdits(myMedia);
    
    //SpriteUtils_AddPICTImageToKeyFrameSample(mySample, kGoToBeginningButtonUp, &myKeyColor, kGoToBeginningButtonUpIndex, NULL, NULL);
    
    // button with no actions
    myErr = QTNewAtomContainer(&myTestButton);
    if (myErr != noErr) return;
    
    myLocation.h	= 0;
    myLocation.v	= 0;
    isVisible		= true;
    myLayer		= 1;
    myIndex		= 1;
    myErr = SpriteUtils_SetSpriteData(myTestButton, &myLocation, &isVisible, &myLayer, &myIndex, NULL, NULL, myActions);
    if (myErr != noErr) return;
    
    // add the key frame sample to the sprite track media
    //
    // to add the sample data in a compressed form, you would use a QuickTime DataCodec to perform the
    // compression; replace the call to the utility AddSpriteSampleToMedia with a call to the utility
    // AddCompressedSpriteSampleToMedia to do this
    
    //SpriteUtils_AddSpriteToSample(mySample, myTestButton, 1);
    SpriteUtils_AddSpriteSampleToMedia(myMedia, mySample, 20, true, NULL);	
    //SpriteUtils_AddCompressedSpriteSampleToMedia(myMedia, mySample, kSpriteMediaFrameDuration, true, zlibDataCompressorSubType, NULL);

    
    EndMediaEdits(myMedia);
	
    // add the media to the track
    InsertMediaIntoTrack(myTrack, 0, 0, GetMediaDuration(myMedia), fixed1);
    
    RgnHandle rhandle;
    rhandle = GetTrackClipRgn(myTrack);
    ScaleTrackSegment(myTrack, 0, GetTrackDuration(myTrack), 300);
}
*/

@end