/* 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.
 */
//
//  mhsTrack.m
//  Hootenanny
//
//  Created by Noah Sorscher on Sun Sep 28 2003.
//  Copyright (c) 2003 __MyCompanyName__. All rights reserved.
//

#import "mhsTrack.h"


FSSpec fsSpecFromPath(NSString *path);
/*
void QTWired_SetTrackProperties (Media theMedia, UInt32 theIdleFrequency, RGBColor myBackgroundColor);
OSErr SpriteUtils_AddPICTImageToKeyFrameSample (QTAtomContainer theKeySample, PicHandle myPicture, FSSpec *theFSSpec, RGBColor *theKeyColor, QTAtomID theID, FixedPoint *theRegistrationPoint, StringPtr theImageName);
OSErr QTWired_AddCursorChangeToSprite (QTAtomContainer theContainer, QTAtomID theID);
void QTTextCopyCStringToPascal (const char *theSrc, Str255 theDst);
StringPtr QTUtils_ConvertCToPascalString (char *theString);
*/
@implementation mhsTrack


- (void) setOffset:(long)n
{
    offset = n;
}

- (mhsTrack *)initWithMovie:(NSMovie *)movie
{
    theMovie = movie;
    //srcMovie = src;
    picIndex = spriteIndex = 1;
    theKeyFrameSample = nil;
    [self createTrackAndMedia:[movie QTMovie]];
    return [super init];
}

- (void)addSprites:(NSArray *)sprites sender:(id)sender
{
    BOOL scenes = NO, audio = NO, text = NO;
    int i, n = [sprites count];
    NSString *value;
    NSDictionary *sprite;
    MHSpriteSpec spec;
    Rect newBox, origBox;
    TimeValue tv;
    for (i=0;i<n;i++) {
        sprite = [sprites objectAtIndex:i];
        // Get Sprite Size
        newBox.left = newBox.top = 0;
        newBox.right = [[sprite objectForKey:@"Width"] intValue];
        if (!newBox.right)
            newBox.right = 32;
        newBox.bottom = [[sprite objectForKey:@"Height"] intValue];
        if (!newBox.bottom)
            newBox.bottom = 24;
        GetMovieBox([theMovie QTMovie], &origBox);
        //SetMovieBox([theMovie QTMovie], &newBox);
        spec = [self newSpec];
        spec.point.x = [[sprite objectForKey:@"X"] intValue];
        spec.point.y = [[sprite objectForKey:@"Y"] intValue];
        value = [sprite objectForKey:@"Image"];
        if (value) {
            [sender postUpdate:[NSString stringWithFormat:@"Creating Sprite: %@", value] done:(double)i / (double)n];
            if ([value hasPrefix:@"/"])
                spec.fileImage = value;
            else {
                SetMovieBox([theMovie QTMovie], &newBox);
                tv = [value intValue] + offset;
                spec.picImage = GetMoviePict([theMovie QTMovie], tv);
                SetMovieBox([theMovie QTMovie], &origBox);
            }
        }
        value = [sprite objectForKey:@"Rollover"];
        if (value) {
            if ([value hasPrefix:@"/"])
                spec.fileRollImage = value;
            else {
                SetMovieBox([theMovie QTMovie], &newBox);
                tv = [value intValue] + offset;
                spec.picRollImage = GetMoviePict([theMovie QTMovie], tv);
                SetMovieBox([theMovie QTMovie], &origBox);
            }
        }
        value = [sprite objectForKey:@"Click"];
        if (value) {
            if ([value hasPrefix:@"/"])
                spec.fileClickImage = value;
            else {
                SetMovieBox([theMovie QTMovie], &newBox);
                tv = [value intValue] + offset;
                spec.picClickImage = GetMoviePict([theMovie QTMovie], tv);
                SetMovieBox([theMovie QTMovie], &origBox);
            }
        }
        value = [sprite objectForKey:@"Action"];
        if (value)
            spec.action = [value intValue];
        value = [sprite objectForKey:@"value"];
        if (value) {
            switch (spec.action) {
                case gotoTimeAndPlay:
                case setAudioTrack:
                case setTextTrack:
                case gotoTime: spec.longValue = [value intValue]; break;
                case gotoTimeByName:
                case setAudioTrackByName:
                case setTextTrackByName: spec.stringValue = value; break;
                default: break;
            }
            switch (spec.action) {
                case gotoTimeAndPlay:
                case gotoTimeByName: scenes = YES; break;
                case setAudioTrack:
                case setAudioTrackByName: audio = YES; break;
                case setTextTrack:
                case setTextTrackByName: text = YES;
                default: break;
            }
        }
        value = [sprite objectForKey:@"keyColor"];
        if (value)
            spec.keyColor = [NSUnarchiver unarchiveObjectWithData:(NSData *)value];
        [self addWiredSprite:spec];
    }
    NSMutableString *name = [NSMutableString stringWithString:@""];
    if (scenes)
        [name appendString:@"Scene"];
    if (audio) {
        if ([name length])
            [name appendString:@"/"];
        [name appendString:@"Audio"];
    }
    if (text) {
        if ([name length])
            [name appendString:@"/"];
        [name appendString:@"Text"];
    }
    if ([name length])
        [name appendString:@" Selection"];
    else
        [name appendString:@"Sprites"];
    char *buffer = malloc(sizeof(char) * ([name length] + 1));
    [name getCString:buffer];
    SetUserDataItem(GetTrackUserData(theTrack), buffer, [name length], kUserDataName, 1);
    free(buffer);
}

- (void)setBGSource:(NSString *)imageSource
{
    MHSpriteSpec spec = [self newSpec];
    if ([imageSource hasPrefix:@"/"])
        if ([imageSource hasSuffix:@".mov"]) {
            spec.loopingMovie = [[NSMovie alloc] initWithURL:[NSURL fileURLWithPath:imageSource] byReference:NO];
            spec.picImage = GetMoviePict([spec.loopingMovie QTMovie], 0);
        } else
            spec.fileImage = imageSource;
    else
        spec.picImage = GetMoviePict([theMovie QTMovie], [imageSource intValue] + offset);
    [self addWiredSprite:spec];
    if (spec.loopingMovie) {
        InsertMovieSegment([spec.loopingMovie QTMovie], GetTrackMovie(theTrack), 0, GetMovieDuration([spec.loopingMovie QTMovie]), 0);
    }
}

- (void)setBGColor:(NSColor *)color
{
    theColor = color;
}

- (RGBColor)RGBColor
{
    return [self rgbColor:theColor];
}

- (RGBColor)rgbColor:(NSColor *)aColor
{
    RGBColor color;
    NSColor *newColor = [aColor colorUsingColorSpaceName:@"NSCalibratedRGBColorSpace"];
    color.red = [newColor redComponent] * (double)0xffff;
    color.green = [newColor greenComponent] * (double)0xffff;
    color.blue = [newColor blueComponent] * (double)0xffff;
    return color;
}

+ (void)insertSprite:(NSDictionary *)theSprite intoMovie:(NSMovie *)movie
{
    
    
}

+ (void)addSprite:(NSDictionary *)theSprite overMovie:(NSMovie *)movie
{

}

- (MHSpriteSpec)newSpec
{
    MHSpriteSpec spec;
    spec.point = NSMakePoint(0, 0);
    spec.visible = YES;
    spec.layer = 1;
    spec.cursor = -1;
    spec.picImage = nil;
    spec.fileImage = nil;
    spec.picRollImage = nil;
    spec.fileRollImage = nil;
    spec.picClickImage = nil;
    spec.fileClickImage = nil;
    spec.loopingMovie = nil;
    spec.action = -1;
    spec.longValue = 0;
    spec.stringValue = nil;
    spec.keyColor = nil;
    
    return spec;
}

- (BOOL) setTrackEnabledAction:(QTAtomContainer)theSprite trackType:(OSType)theType ident:(id)theIdent
{
    Track aTrack, targetTrack = nil;
    int i, n = GetMovieTrackCount([theMovie QTMovie]);
    BOOL enabled, byNumber;
    OSType aType;
    NSString *aTrackName;
    char *buffer;
    Handle h;
    OSErr myErr = noErr;
    void *theTrackTarget;
    long theTrackTargetType;
    if ([theIdent isKindOfClass:[NSNumber class]]) {
        byNumber = YES;
        targetTrack = GetMovieIndTrack([theMovie QTMovie], [theIdent intValue]);
    } else
        byNumber = NO;
    for (i=1; i<n; i++) {
        aTrack = GetMovieIndTrack([theMovie QTMovie], i);
        GetMediaHandlerDescription(GetTrackMedia(aTrack), &aType, 0, 0);
        if (aType == theType) {
            if (byNumber) { // by number
                if (aTrack == targetTrack)
                    enabled = YES;
                else
                    enabled = NO;
                theTrackTarget = (void *)i;
                theTrackTargetType = kTargetTrackID;
            } else { // by name
                h = NewHandleClear(0);
                if (![theIdent isKindOfClass:[NSString class]]) return NO;
                GetUserData(GetTrackUserData(aTrack), h, kUserDataName, 1);
                //buffer = malloc(sizeof(char) * GetHandleSize(h));
                //BlockMoveData(h, &buffer, GetHandleSize(h));
                buffer = (char *)*h;
                aTrackName = [NSString stringWithCString:buffer length:GetHandleSize(h)];
                if (aTrackName)
                    enabled = [theIdent isEqualToString:aTrackName];
                else
                    enabled = NO;
                theTrackTarget = (void *) QTUtils_ConvertCToPascalString(buffer);
                theTrackTargetType = kTargetTrackName;
                //DisposeHandle(h);
                //NSLog(@"set track %@ enabled: %d", aTrackName, enabled);
            }
            myErr = WiredUtils_AddTrackSetEnabledAction(theSprite, kParentAtomIsContainer, kQTEventMouseClickEnd, theTrackTargetType, theTrackTarget, 0, enabled);
            if (myErr) return NO;
        }
    }
    return YES;
}


- (void)createTrackAndMedia:(Movie)mov
{
    theTrack = [mhsTrack newTrackInMovie:mov];
    OSErr myErr = QTNewAtomContainer(&theKeyFrameSample);
    long index;
    TimeValue timevalue = TRACK_DURATION;
    Track aTrack = GetMovieIndTrack(mov, 1);
    for (index = 2; aTrack != nil; index++) {
        if (aTrack != theTrack)
            SetTrackOffset(aTrack, timevalue + GetTrackOffset(aTrack));
        aTrack = GetMovieIndTrack(mov, index);
    }
}

+ (Track)newTrackInMovie:(Movie)mov
{
    Track videoTrack = GetMovieIndTrackType(mov, 1, VideoMediaType, movieTrackMediaType);
    Fixed myWidth, myHeight;
    GetTrackDimensions(videoTrack, &myWidth, &myHeight);
        
    Track newTrack = NewMovieTrack(mov, myWidth, myHeight, kNoVolume);
    Media myMedia = NewTrackMedia(newTrack, SpriteMediaType, GetMovieTimeScale(mov), NULL, 0);
    return newTrack;
}

- (OSErr)addWiredSprite:(MHSpriteSpec)spec
{
    Media 				myMedia;
    OSErr 				myErr = noErr;
    RGBColor				myKeyColor;
    Point				myLocation;
    short				isVisible, myIndex;
    QTAtomID				mainID, rollID, clickID;
    BOOL 				mainImage = NO, rollover = NO, clicked = NO, looping = NO;
    
    myMedia = GetTrackMedia(theTrack);
        
    //myKeyColor.red = myKeyColor.green = myKeyColor.blue = 0xffff;		// white
    myKeyColor = [self rgbColor:spec.keyColor];
    
    FSSpec fsSpec;
    if (spec.picImage || spec.fileImage) {
            mainImage = YES;
            mainID = picIndex++;
            if (spec.fileImage)
                fsSpec = fsSpecFromPath(spec.fileImage);
            SpriteUtils_AddPICTImageToKeyFrameSample(theKeyFrameSample, spec.picImage, &fsSpec, &myKeyColor, mainID, NULL, NULL);
    }
    if (spec.picRollImage || spec.fileRollImage) {
            rollover = YES;
            rollID = picIndex++;
            if (spec.fileRollImage)
                fsSpec = fsSpecFromPath(spec.fileRollImage);
            SpriteUtils_AddPICTImageToKeyFrameSample(theKeyFrameSample, spec.picRollImage, &fsSpec, &myKeyColor, rollID, NULL, NULL);
    }
    if (spec.picClickImage || spec.fileClickImage) {
            clicked = YES;
            clickID = picIndex++;
            if (spec.fileClickImage)
                fsSpec = fsSpecFromPath(spec.fileClickImage);
            SpriteUtils_AddPICTImageToKeyFrameSample(theKeyFrameSample, spec.picClickImage, &fsSpec, &myKeyColor, clickID, NULL, NULL);
    }
    if (spec.loopingMovie) {
        looping = YES;
    }
    //if (!mainImage && !rollover && !clicked)
    //    goto bail;
	// assign group IDs to the images
	//SpriteUtils_AssignImageGroupIDsToKeyFrame(theKeyFrameSample);
        
        // add samples to the sprite track's media
        BeginMediaEdits(myMedia);
        QTAtomContainer myButton, myActionButton, myActions = NULL;
        myIndex = mainID;
        myErr = QTNewAtomContainer(&myButton);
        if (myErr) return myErr;
        
        myLocation.h = spec.point.x;
        myLocation.v = spec.point.y;
        isVisible = spec.visible;
        myErr = SpriteUtils_SetSpriteData(myButton, &myLocation, &isVisible, &spec.layer, &myIndex, NULL, NULL, myActions);
        if (myErr) return myErr;
        
        //if (theCursor != -1)
            //QTWired_AddCursorChangeToSprite(myButton, spriteIndex);
        
        //if (rollover || clicked || theAction != -1) {
            myErr = QTCopyAtom(myButton, kParentAtomIsContainer, &myActionButton);
            if (myErr) return myErr;
            if (rollover) {
                // add rollover atoms
                WiredUtils_AddSpriteSetImageIndexAction(myActionButton, kParentAtomIsContainer, kQTEventMouseEnter, 0, NULL, 0, 0, NULL, rollID, NULL);
                if (mainImage) {
                    WiredUtils_AddSpriteSetImageIndexAction(myActionButton, kParentAtomIsContainer, kQTEventMouseExit, 0, NULL, 0, 0, NULL, mainID, NULL);
                } else { // if there's a rollover and no main, we have to make you visible on enter and vice versa
                    WiredUtils_AddSpriteSetVisibleAction(myActionButton, kParentAtomIsContainer, kQTEventMouseEnter, 0, NULL, 0, 0, NULL, true, NULL);
                    WiredUtils_AddSpriteSetVisibleAction(myActionButton, kParentAtomIsContainer, kQTEventMouseExit, 0, NULL, 0, 0, NULL, false, NULL);
                }
            }
            if (clicked) {
                if (mainImage) {
                    // add clicked image atoms
                    WiredUtils_AddSpriteSetImageIndexAction(myActionButton, kParentAtomIsContainer, kQTEventMouseClick, 0, NULL, 0, 0, NULL, clickID, NULL);
                    if (rollover) {
                        WiredUtils_AddSpriteSetImageIndexAction(myActionButton, kParentAtomIsContainer, kQTEventMouseClickEnd, 0, NULL, 0, 0, NULL, rollID, NULL);
                    } else if (mainImage) {
                        WiredUtils_AddSpriteSetImageIndexAction(myActionButton, kParentAtomIsContainer, kQTEventMouseClickEnd, 0, NULL, 0, 0, NULL, mainID, NULL);
                    } else { // if there's a clicked and no main or rollover, we have to make you visible on click and vice versa
                        WiredUtils_AddSpriteSetVisibleAction(myActionButton, kParentAtomIsContainer, kQTEventMouseClick, 0, NULL, 0, 0, NULL, true, NULL);
                        WiredUtils_AddSpriteSetVisibleAction(myActionButton, kParentAtomIsContainer, kQTEventMouseClickEnd, 0, NULL, 0, 0, NULL, false, NULL);
                    }
                }
            }
            if (looping) {
                WiredUtils_AddMovieGoToBeginningAction(theKeyFrameSample, kParentAtomIsContainer, kQTEventFrameLoaded);
                WiredUtils_AddMovieSetRateAction(theKeyFrameSample, kParentAtomIsContainer, kQTEventFrameLoaded, fixed1);
            }
            if (spec.action != -1) {
                // add the real actions
                Str255 tmpStr;
                switch (spec.action) {
                    case gotoTime:
                                WiredUtils_AddMovieGoToTimeAction(myActionButton, kParentAtomIsContainer, kQTEventMouseClickEnd, spec.longValue);
                                
                                //NSLog(@"frame loaded");
                                //WiredUtils_AddMovieStepForwardAction(theKeyFrameSample, kParentAtomIsContainer, kQTEventFrameLoaded);
                                
                                break;
                    case gotoTimeAndPlay:
                                WiredUtils_AddMovieGoToTimeAction(myActionButton, kParentAtomIsContainer, kQTEventMouseClickEnd, spec.longValue);
                                WiredUtils_AddMovieSetRateAction(myActionButton, kParentAtomIsContainer, kQTEventMouseClickEnd, fixed1);
                                break;
                    case gotoTimeByName:
                                if (!spec.stringValue || ![spec.stringValue isKindOfClass:[NSString class]])
                                    break;
                                QTTextCopyCStringToPascal([spec.stringValue cString], tmpStr);
                                WiredUtils_AddMovieGoToTimeByNameAction(myActionButton, kParentAtomIsContainer, kQTEventMouseClickEnd, tmpStr);
                                WiredUtils_AddMovieSetRateAction(myActionButton, kParentAtomIsContainer, kQTEventMouseClickEnd, fixed1);
                                break;
                    case setAudioTrack:
                                [self setTrackEnabledAction:myActionButton trackType:SoundMediaType ident:[NSNumber numberWithInt:spec.longValue]];
                                break;
                    case setAudioTrackByName: 
                                [self setTrackEnabledAction:myActionButton trackType:SoundMediaType ident:spec.stringValue];
                                break;
                    case setTextTrack: 
                                [self setTrackEnabledAction:myActionButton trackType:TextMediaType ident:[NSNumber numberWithInt:spec.longValue]];
                                break;
                    case setTextTrackByName: 
                                [self setTrackEnabledAction:myActionButton trackType:TextMediaType ident:spec.stringValue];
                                break;
                    case gotoBeginning:
                                WiredUtils_AddMovieGoToBeginningAction(myActionButton, kParentAtomIsContainer, kQTEventMouseClickEnd);              
                                break;
                    case gotoEnd:
                                WiredUtils_AddMovieGoToEndAction(myActionButton, kParentAtomIsContainer, kQTEventMouseClickEnd);
                                break;
                    case stepForward:
                                WiredUtils_AddMovieStepForwardAction(myActionButton, kParentAtomIsContainer, kQTEventMouseClickEnd);
                                break;
                    case stepBackward:
                                WiredUtils_AddMovieStepBackwardAction(myActionButton, kParentAtomIsContainer, kQTEventMouseClickEnd);
                                break;
                    default: break;
                }
            }
            SpriteUtils_AddSpriteToSample(theKeyFrameSample, myActionButton, spriteIndex);
            QTDisposeAtomContainer(myActionButton);
        //}
        
        //if (first)
            SpriteUtils_AddSpriteSampleToMedia(myMedia, theKeyFrameSample, TRACK_DURATION, true, NULL);
        
        myErr = EndMediaEdits(myMedia);
	if (myErr != noErr)
		return myErr;
        
	// add the media to the track
	//if (first) {
        //TimeValue tv = GetTrackDuration(theTrack);
        
            DeleteTrackSegment(theTrack, 0, GetTrackDuration(theTrack));
            
        //tv = GetTrackDuration(theTrack);
        
    bail:
            InsertMediaIntoTrack(theTrack, 0, 0, GetMediaDuration(myMedia), fixed1);
            
        TimeValue tv = GetTrackDuration(theTrack);
        tv = tv - tv / spriteIndex;
        //tv = (spriteIndex - 1) * GetTrackDuration(theTrack);
        //tv = (spriteIndex - 1) * theDuration;
        
            DeleteTrackSegment(theTrack, 0, tv);	
        
        //tv = GetTrackDuration(theTrack);
            
	// set the sprite track properties
            QTWired_SetTrackProperties(myMedia, 1, [self RGBColor]);
        //}
        
        spriteIndex++;
                
	return(myErr);
}

- (OSErr)addLoopingMovie:(MHSpriteSpec)spec
{
    OSErr myErr = noErr;
    Media myMedia = GetTrackMedia(theTrack);
    RGBColor myKeyColor = [self rgbColor:spec.keyColor];
    
    if (!spec.loopingMovie) return myErr;
    BeginMediaEdits(myMedia);
    QTAtomContainer myButton, myActionButton, myActions = NULL;
    myErr = QTNewAtomContainer(&myButton);
    if (myErr) return myErr;
    Point myLocation;
    myLocation.h = spec.point.x;
    myLocation.v = spec.point.y;
    short isVisible = spec.visible;
    myErr = SpriteUtils_SetSpriteData(myButton, &myLocation, &isVisible, &spec.layer, NULL, NULL, NULL, myActions);
    if (myErr) return myErr;
    myErr = QTCopyAtom(myButton, kParentAtomIsContainer, &myActionButton);
    if (myErr) return myErr;
    WiredUtils_AddMovieGoToBeginningAction(myActionButton, kParentAtomIsContainer, kQTEventFrameLoaded);
    SpriteUtils_AddSpriteToSample(theKeyFrameSample, myActionButton, spriteIndex);
    QTDisposeAtomContainer(myActionButton);
    SpriteUtils_AddSpriteSampleToMedia(myMedia, theKeyFrameSample, TRACK_DURATION, true, NULL);
    myErr = EndMediaEdits(myMedia);
    if (myErr) return myErr;
    InsertMediaIntoTrack(theTrack, 0, 0, GetMediaDuration(myMedia), fixed1);
    QTWired_SetTrackProperties(myMedia, 1, [self RGBColor]);
    spriteIndex++;
    SetTrackOffset(theTrack, GetMovieDuration([theMovie QTMovie]));
    return myErr;
}


FSSpec fsSpecFromPath(NSString *path)
{
    FSRef fsRef;
    FSSpec fsSpec;
    OSErr myErr;
    (OSStatus)myErr = FSPathMakeRef([path fileSystemRepresentation],&fsRef, NULL /* isDirectory */);
    myErr = FSGetCatalogInfo(&fsRef, kFSCatInfoNone, NULL /*catalogInfo*/, NULL /*outName*/, &fsSpec, NULL /*parentRef*/);
    return fsSpec;
}
/*
//////////
//
// SpriteUtils_AddPICTImageToKeyFrameSample
// Compress a PICT with the animation compressor and add the image data to a sprite key sample's images container atom.
//
//////////

OSErr SpriteUtils_AddPICTImageToKeyFrameSample (QTAtomContainer theKeySample, PicHandle myPicture, FSSpec *theFSSpec, RGBColor *theKeyColor, QTAtomID theID, FixedPoint *theRegistrationPoint, StringPtr theImageName)
{
	//PicHandle				myPicture = NULL;
	Handle					myCompressedPicture = NULL;
	ImageDescriptionHandle			myImageDesc = NULL;
	OSErr					myErr = noErr;
	
	DetachResource((Handle)myPicture);
	
	// convert it to image data compressed by the animation compressor
        if (myPicture)
            myErr = ICUtils_RecompressPictureWithTransparency(myPicture, theKeyColor, NULL, &myImageDesc, &myCompressedPicture);
        else if (theFSSpec)
            myErr = ICUtils_RecompressPictureFileWithTransparency(theFSSpec, theKeyColor, NULL, &myImageDesc, &myCompressedPicture);
        else goto bail;
	if (myErr != noErr)
		goto bail;

	// 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);
}


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

void QTWired_SetTrackProperties (Media theMedia, UInt32 theIdleFrequency, RGBColor myBackgroundColor)
{
	QTAtomContainer		myTrackProperties;
	//RGBColor			myBackgroundColor;
	Boolean				hasActions;
	UInt32				myFrequency;
	OSErr				myErr = noErr;
		
	// add a background color to the sprite track
        //myBackgroundColor = [self RGBColor];
	//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);
	}
}


//////////
//
// QTWired_AddCursorChangeToSprite
// Add cursor-change-on-mouse-over and -down actions to the sprite having the specified ID
// in the specified atom container.
//
// Here we use the new "sprite behaviors atom" introduced in QuickTime 4.0, which
// simplifies adding button-like capabilities to sprites.
//
//////////

OSErr QTWired_AddCursorChangeToSprite (QTAtomContainer theContainer, QTAtomID theID)
{
	QTAtom					mySpriteAtom = 0;
	QTAtom					myBehaviorAtom = 0;
	QTSpriteButtonBehaviorStruct		myBehaviorRec;
	OSErr					myErr = paramErr;
	
	// find the sprite atom with the specified ID in the specified container
	mySpriteAtom = QTFindChildByID(theContainer, kParentAtomIsContainer, kSpriteAtomType, theID, NULL);
	if (mySpriteAtom == 0)
		goto bail;
	
	// insert a new sprite behaviors atom into the sprite atom
	myErr = QTInsertChild(theContainer, mySpriteAtom, kSpriteBehaviorsAtomType, 1, 1, 0, NULL, &myBehaviorAtom);
	if (myErr != noErr)
		goto bail;
	
	// set the sprite cursor behavior; -1 means: no change associated with this state transition
	myBehaviorRec.notOverNotPressedStateID = EndianS32_NtoB(-1);
	myBehaviorRec.overNotPressedStateID = EndianS32_NtoB(kQTCursorPointingHand);
	myBehaviorRec.overPressedStateID = EndianS32_NtoB(kQTCursorRightArrow);
	myBehaviorRec.notOverPressedStateID = EndianS32_NtoB(-1);

	myErr = QTInsertChild(theContainer, myBehaviorAtom, kSpriteCursorBehaviorAtomType, 1, 1, sizeof(QTSpriteButtonBehaviorStruct), &myBehaviorRec, NULL);

bail:
	return(myErr);
}

//////////
//
// 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 QTTextCopyCStringToPascal (const char *theSrc, 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;
}


//////////
//
// 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);
}

*/


@end
