//
//  QTImage.m
//  Hootenanny
//
//  Created by Noah Sorscher on 1/21/05.
//  Copyright 2005 __MyCompanyName__. All rights reserved.
//

#import "QTImage.h"
#import <QuickTime/QuickTime.h>


@implementation QTImage

- (NSImage *)initWithFile:(NSString *)path transparency:(NSColor *)keyColor time:(TimeValue)time
{
    if (!path) return nil;
    NSMovie *movie = [[NSMovie alloc] initWithURL:[NSURL fileURLWithPath:path] byReference:NO];
    if (!movie) return nil;
    
    GWorldPtr gworld;
    Rect srcRect, portRect;
    GetMovieBox([movie QTMovie], &srcRect);
    NSRect r = NSMakeRect(0, 0, srcRect.right-srcRect.left, srcRect.bottom-srcRect.top);
    
    NSWindow *win = [[NSWindow alloc] initWithContentRect:r styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
    r = [[win contentView] frame];
    NSMovieView *myView = [[NSMovieView alloc] initWithFrame:r];
    [myView showController:NO adjustingSize:NO];
    [win setContentView:myView];
    r = [myView frame];
    [myView setMovie:movie];
    
    TimeRecord tr;
    GetMovieTime([movie QTMovie], &tr);
    tr.value.lo = time;
    SetMovieTime([movie QTMovie], &tr);
    
    // http://developer.apple.com/qa/qtmtb/qtmtb57.html
    OSErr err = NewGWorld(&gworld,
                k32ARGBPixelFormat,
                &srcRect,
                NULL,
                NULL,
                0);
        /* make sure to lock the PixMap */
    LockPixels(GetGWorldPixMap(gworld));
        /* erase */
    SetGWorld(gworld,NULL);
    GetPortBounds(gworld, &portRect);
    EraseRect(&portRect);
        /* tell the movie to draw into the GWorld */
    SetMovieGWorld([movie QTMovie], gworld,  GetGWorldDevice(gworld));
    
    MoviesTask([movie QTMovie], 0);
    NSImage *image = [self gworldToNSImage:gworld transparency:keyColor];
    [win release];
    [myView release];
    [movie release];
    return image;
}


-(NSImage *)gworldToNSImage:(GWorldPtr) gWorldPtr transparency:(NSColor *)keyColor
{
    //NSLog(@"gworldToNSImage");
    PixMapHandle 		pixMapHandle = NULL;
    Ptr 				pixBaseAddr = nil;
    NSBitmapImageRep 	*imageRep = nil;
    NSImage 			*image = nil;
    
    float keyR = 0, keyB = 0, keyG = 0, keyA = 0;
    unsigned char KeyR = 0, KeyG = 0, KeyB = 0, KeyA = 0;
    if (keyColor) {
        keyColor = [keyColor colorUsingColorSpaceName:@"NSCalibratedRGBColorSpace"];
        [keyColor getRed:&keyR green:&keyG blue:&keyB alpha:&keyA];
        KeyR = 255.0 * keyR;
        KeyG = 255.0 * keyG;
        KeyB = 255.0 * keyB;
        KeyA = 255.0 * keyA;
    }
    
    //NSAssert(gWorldPtr != nil, @"nil gWorldPtr");
    if (nil == gWorldPtr) return nil;

    // Lock the pixels
    pixMapHandle = GetGWorldPixMap(gWorldPtr);
    if (pixMapHandle)
    {
        Rect 		portRect;
        unsigned 	portWidth, portHeight;
        int 		bitsPerSample, samplesPerPixel;
        BOOL 		hasAlpha, isPlanar;
        int 		destRowBytes;

        NSAssert(LockPixels(pixMapHandle) != false, @"LockPixels returns false");
    
        GetPortBounds(gWorldPtr, &portRect);
        portWidth = (portRect.right - portRect.left);
        portHeight = (portRect.bottom - portRect.top);
    
        bitsPerSample 	= 8;
        samplesPerPixel = 4;
        hasAlpha		= YES;
        isPlanar 		= NO;
        destRowBytes 	= portWidth * samplesPerPixel;
        imageRep 		= [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL pixelsWide:portWidth pixelsHigh:portHeight bitsPerSample:bitsPerSample samplesPerPixel:samplesPerPixel hasAlpha:hasAlpha isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace bytesPerRow:destRowBytes bitsPerPixel:0];
        if (imageRep)
        {
            char 	*theData;
            int 	pixmapRowBytes;
            int 	rowByte,rowIndex;

            theData = [imageRep bitmapData];
        
            pixBaseAddr = GetPixBaseAddr(pixMapHandle);
            if (pixBaseAddr)
            {
                pixmapRowBytes = GetPixRowBytes(pixMapHandle);
            
                for (rowIndex=0; rowIndex< portHeight; rowIndex++)
                {
                    unsigned char *dst = theData + rowIndex * destRowBytes;
                    unsigned char *src = pixBaseAddr + rowIndex * pixmapRowBytes;
                    unsigned char a,r,g,b;
                    
                    for (rowByte = 0; rowByte < portWidth; rowByte++)
                    {
                        a = *src++;		// get source Alpha component
                        r = *src++;		// get source Red component
                        g = *src++;		// get source Green component
                        b = *src++;		// get source Blue component  
                        
                        if (keyColor) {
                            if (r == KeyR && g == KeyG && b == KeyB)
                                a = 0;
                        }
            
                        *dst++ = r;		// set dest. Alpha component
                        *dst++ = g;		// set dest. Red component
                        *dst++ = b;		// set dest. Green component
                        *dst++ = a;		// set dest. Blue component  
                    }
                }
            
                image = [[[NSImage alloc]initWithSize:NSMakeSize(portWidth, portHeight)] autorelease];
                if (image)
                {
                    [image addRepresentation:imageRep];
                    [imageRep release];
                }
            }
        }
    }

    NSAssert(pixMapHandle != NULL, @"null pixMapHandle");
    NSAssert(imageRep != nil, @"nil imageRep");
    NSAssert(pixBaseAddr != nil, @"nil pixBaseAddr");
    NSAssert(image != nil, @"nil image");

    if (pixMapHandle)
    {
        UnlockPixels(pixMapHandle);
    }

    return image;
}


@end
