/* -LICENSE-START-
 ** Copyright (c) 2018 Blackmagic Design
 **
 ** Permission is hereby granted, free of charge, to any person or organization
 ** obtaining a copy of the software and accompanying documentation covered by
 ** this license (the "Software") to use, reproduce, display, distribute,
 ** execute, and transmit the Software, and to prepare derivative works of the
 ** Software, and to permit third-parties to whom the Software is furnished to
 ** do so, all subject to the following:
 ** 
 ** The copyright notices in the Software and this entire statement, including
 ** the above license grant, this restriction and the following disclaimer,
 ** must be included in all copies of the Software, in whole or in part, and
 ** all derivative works of the Software, unless such copies or derivative
 ** works are solely in the form of machine-executable object code generated by
 ** a source language processor.
 ** 
 ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 ** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
 ** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
 ** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
 ** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 ** DEALINGS IN THE SOFTWARE.
 ** -LICENSE-END-
 */

/* DeckLinkKeyerMovieView.m */

#import "DeckLinkKeyerMovieView.h"
#import "DeckLinkKeyerController.h"

@implementation DeckLinkKeyerMovieView

- (id)initWithCoder:(NSCoder*)coder
{
	if (self = [super initWithCoder:coder])
	{
		highlight = NO;
		acceptDrags = YES;
		[self registerForDraggedTypes:[NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
	}
	return self;
}

- (void)setAcceptDrags:(BOOL)flag
{
	acceptDrags = flag;
}

- (BOOL)setMovieFile:(NSURL*)fileURL forMode:(IDeckLinkDisplayMode*)displayMode
{
	AVURLAsset*				asset;
	AVAssetImageGenerator*	imageGen;
	CGImageRef				cgImage;
	//
	NSBitmapImageRep*		ourRep = nil;
	NSData*					bitmapPtr = nil;
	NSImage*				ourImage = nil;
	NSImage*				sourceImage;
	NSSize					frameSize;
	NSSize					imageSize;
	NSUInteger				frameRowBytes;
	//
	BOOL					success = NO;
	
	asset = [[[AVURLAsset alloc] initWithURL:fileURL options:nil] autorelease];
	
	// First try to access URL as movie content
	if ([[asset tracksWithMediaType:AVMediaTypeVideo] count] > 0)
	{
		imageGen = [AVAssetImageGenerator assetImageGeneratorWithAsset:asset];
	
		imageGen.maximumSize = CGSizeMake(displayMode->GetWidth(), displayMode->GetHeight());
		imageGen.apertureMode = AVAssetImageGeneratorApertureModeProductionAperture;
		imageGen.appliesPreferredTrackTransform = YES;
	
		cgImage = [imageGen copyCGImageAtTime:CMTimeMake(0, 1) actualTime:nil error:nil];
	}
	else
	{
		// Otherwise try to read file as CGImage
		CGImageSourceRef myImageSource = CGImageSourceCreateWithURL((CFURLRef)fileURL, NULL);
		
		if (myImageSource == NULL)
			// Image source does not exist
			goto bail;
			
		// Create an image from the first item in the image source.
		cgImage = CGImageSourceCreateImageAtIndex(myImageSource, 0, NULL);
		CFRelease(myImageSource);
	}

	imageSize.width = CGImageGetWidth(cgImage);
	imageSize.height = CGImageGetHeight(cgImage);

	// If the movie dimensions are larger than the display mode dimensions,
	// scale the frame (preserving its aspect ratio) to fit within the
	// display mode dimensions.
	if ((imageSize.width > displayMode->GetWidth()) || (imageSize.height > displayMode->GetHeight()))
	{
		// -- First attempt to resize to the display mode width
		frameSize.width = displayMode->GetWidth();
		frameSize.height = ((imageSize.height * displayMode->GetWidth()) / imageSize.width);
		// -- If the height exceeds the display mode height, resize to the display mode height
		if (frameSize.height > displayMode->GetHeight())
		{
			frameSize.width = ((displayMode->GetHeight() * imageSize.width) / imageSize.height);
			frameSize.height = displayMode->GetHeight();
		}
	}
	else
	{
		// Centre smaller image in output window
		frameSize.width = imageSize.width;
		frameSize.height = imageSize.height;
	}
	frameRowBytes = (NSUInteger)frameSize.width * 4;

	// Create bitmap representation to write image content into
	ourRep = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
										pixelsWide:frameSize.width
										pixelsHigh:frameSize.height
										bitsPerSample:8
										samplesPerPixel:4
										hasAlpha:YES
										isPlanar:NO
										colorSpaceName:NSCalibratedRGBColorSpace
										bitmapFormat:NSAlphaFirstBitmapFormat
										bytesPerRow:frameRowBytes
										bitsPerPixel:32] autorelease];

	[NSGraphicsContext saveGraphicsState];
	[NSGraphicsContext setCurrentContext:[NSGraphicsContext
										graphicsContextWithBitmapImageRep:ourRep]];
	
	sourceImage = [[[NSImage alloc] initWithCGImage:cgImage size:imageSize] autorelease];
	[sourceImage drawInRect:NSMakeRect(0.0, 0.0, frameSize.width, frameSize.height) fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0];
	[NSGraphicsContext restoreGraphicsState];
	
	// Write bitmap to DeckLink video frame buffer
	bitmapPtr = [NSData dataWithBytes:[ourRep bitmapData] length:frameRowBytes * frameSize.height];
	[bitmapPtr getBytes:[controller getFrameBuffer:frameSize.width height:frameSize.height] length:frameRowBytes * frameSize.height];
	
	// Update Image View with new frame
	ourImage = [[[NSImage alloc] initWithSize:frameSize] autorelease];
	[ourImage addRepresentation:ourRep];
	[self setImage:ourImage];
	[self setNeedsDisplay:YES];

	success = YES;
	
bail:
	CGImageRelease(cgImage);
	
	return success;
}

- (void)drawRect:(NSRect)rect
{
	[super drawRect:rect];
	
	if (highlight)
	{
		// Highlight by overlaying a gray border
		[[NSColor grayColor] set];
		[NSBezierPath setDefaultLineWidth:5];
		[NSBezierPath strokeRect:rect];
	}
}

/* Dragging destination methods */
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
{
	NSPasteboard*		pboard;
	
	// Examine the contents
	pboard = [sender draggingPasteboard];
	if ((acceptDrags == YES) && ([[pboard types] containsObject:NSFilenamesPboardType]))
	{
		highlight = YES;
		[self setNeedsDisplay:YES];
		
		return NSDragOperationGeneric;		// Accept data as a generic operation
	}
	
	return NSDragOperationNone;
}

- (void)draggingExited:(id <NSDraggingInfo>)sender
{
	highlight = NO;
	[self setNeedsDisplay:YES];
}

- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
{
	highlight = NO;
	[self setNeedsDisplay:YES];
	return YES;
}

- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
	NSPasteboard*		pboard;
	
	// Do the work here
	// -- Examine the contents
	pboard = [sender draggingPasteboard];
	if ([[pboard types] containsObject:NSURLPboardType])
	{
		[controller setMovieFile:[NSURL URLFromPasteboard:pboard]];
		return YES;
	}
	
	return NO;
}

- (void)concludeDragOperation:(id <NSDraggingInfo>)sender
{
	
}

@end

