/* 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 "MHOverlayView.h"

@implementation MHOverlayView


- (id)initWithFrame:(NSRect)frameRect
{
	[super initWithFrame:frameRect];
        mainRect.origin.x = mainRect.origin.y = 0;
        mainRect.size.width = mainRect.size.height = 32;
        draggedSprite = nil;
        alternating = NO;
        resizing = 0;
        [[NSColor blueColor] set];
        [self registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
	return self;
}

- (BOOL)performKeyEquivalent:(NSEvent *)theEvent
{
    alternating = !alternating;
    if (alternating)
        return [super performKeyEquivalent:theEvent];
    BOOL option = NO;
    if ([theEvent modifierFlags] & NSAlternateKeyMask)
	option = YES;
    NSString *chars = [theEvent characters];
    unichar uch = [chars characterAtIndex:0];
    NSMutableDictionary *item = [MHSprite selectedItem];
    if (![[item objectForKey:@"isLeaf"] boolValue]) return [super performKeyEquivalent:theEvent];
    NSString *key = nil;
    BOOL increasing = NO;
    if (uch == NSUpArrowFunctionKey) {
	if (option) {
	    key = @"Height";
	    increasing = YES;
	} else key = @"Y";
    } else if (uch == NSDownArrowFunctionKey) {
	if (option) key = @"Height";
	else {
	    key = @"Y";
	    increasing = YES;
	}
    } else if (uch == NSLeftArrowFunctionKey || uch == NSRightArrowFunctionKey) {
	if (option) key = @"Width";
	else key = @"X";
	if (uch == NSRightArrowFunctionKey) increasing = YES;
    } else return [super performKeyEquivalent:theEvent];
    int value = [[item objectForKey:key] intValue];
    if (increasing) value++;
    else value--;
    [item setObject:[NSString stringWithFormat:@"%d", value] forKey:key];
    if (option && (uch == NSUpArrowFunctionKey || uch == NSDownArrowFunctionKey)) {
	value = [[item objectForKey:@"Y"] intValue];
	if (uch == NSUpArrowFunctionKey) value--;
	else value++;
	[item setObject:[NSString stringWithFormat:@"%d", value] forKey:@"Y"];
    }
    [self setNeedsDisplay:YES];
    [MHSprite reloadOutline];
    return YES;
}

- (void)drawRect:(NSRect)rect
{
    id item = [MHSprite selectedItem];
    id child, parent = nil;
    NSMutableDictionary *track = nil;
    NSRect srcRect, frame = [self frame];
    srcRect = [self scaledFrame:frame]; // this method sets the global hscalar and vscalar vars
    NSImage *image;
    if ([[item objectForKey:@"isLeaf"] boolValue])
        track = [item objectForKey:@"parent"];
    else
        track = item;
    image = [track objectForKey:@"bgImage"];
    if (image) {
        srcRect.origin.x = srcRect.origin.y = 0;
        srcRect.size = [image size];
        frame = [self scaledFrame:srcRect];
	frame.origin.y += [self frame].size.height - frame.size.height;
        [image drawInRect:frame fromRect:srcRect operation:NSCompositeCopy fraction:1];
    } else {
        NSData *data = [track objectForKey:@"color"];
        if (data)
            [[NSUnarchiver unarchiveObjectWithData:data] set];
        frame = [self frame];
        frame.origin.x = frame.origin.y = 0;
        [NSBezierPath fillRect:frame];
    }
    int i, n;
    if (!item) return;
    if (![[item objectForKey:@"isLeaf"] boolValue]) {
        n = [(NSArray *)[item objectForKey:@"sprites"] count];
        for (i=0;i<n;i++)
            [self drawSprite:[[item objectForKey:@"sprites"] objectAtIndex:i] selected:NO];
        goto bail;
    }
    parent = [item objectForKey:@"parent"];
    n = [(NSArray *)[parent objectForKey:@"sprites"] count];
    for (i=0;i<n;i++) {
        child = [[parent objectForKey:@"sprites"] objectAtIndex:i];
        [self drawSprite:child selected:child == item];
    }
bail:
    if ([MHSprite qsMode]) {
	[[NSColor greenColor] set];
	[NSBezierPath strokeRect:qsRect];
    }
}


- (IBAction)refreshView:(id)sender
{
    [self setNeedsDisplay:YES];
}

- (void) resetCursorRects
{
    if ([MHSprite qsMode]) {
	NSRect frame = [self frame];
	frame.origin = NSMakePoint(0,0);
	[self addCursorRect:frame cursor:[NSCursor crosshairCursor]];
    } else
	[self discardCursorRects];
}

BOOL cancelled = NO;

- (void)rightMouseDown:(NSEvent *)theEvent
{
    NSPoint point = [theEvent locationInWindow];
    NSRect frame = [self frame];
    point.x -= frame.origin.x;
    point.y -= frame.origin.y;
    id item = [MHSprite selectedItem];
    if ([[item objectForKey:@"isLeaf"] boolValue])
	item = [item objectForKey:@"parent"];
    int i, n = [(NSArray *)[item objectForKey:@"sprites"] count];
    id theHit = nil;
    for (i=n-1;i>=0;i--) {
	id aChild = [[item objectForKey:@"sprites"] objectAtIndex:i];
	NSRect aRect = [self frameOfSprite:aChild];
	if (point.x > aRect.origin.x && point.x < aRect.origin.x + aRect.size.width && point.y > aRect.origin.y && point.y < aRect.origin.y + aRect.size.height) {
	    theHit = aChild;
	    break;
	}
    }
    if (!theHit) return;
    [MHSprite selectItem:theHit];
    NSMenu *menu = [MHSprite rightClickMenu];
	if (menu)
		[NSMenu popUpContextMenu:menu withEvent:theEvent forView:self];
}

- (void)mouseDown:(NSEvent *)theEvent
{
    if ([theEvent modifierFlags] & NSControlKeyMask) {
	[self rightMouseDown:theEvent];
        return;
    }
    if ([MHSprite qsMode]) {
	qsPoint = [theEvent locationInWindow];
	qsPoint.x -= [self frame].origin.x;
	qsPoint.y -= [self frame].origin.y;
	return;
    }
    int i, n;
    id aChild;
    NSRect aRect;
    NSPoint point = [theEvent locationInWindow];
    NSRect frame = [self frame];
    point.x -= frame.origin.x;
    point.y -= frame.origin.y;
    id item = [MHSprite selectedItem];
    if ([[item objectForKey:@"isLeaf"] boolValue])
        item = [item objectForKey:@"parent"];
    n = [(NSArray *)[item objectForKey:@"sprites"] count];
    for (i= n - 1; i>=0; i--) {
        aChild = [[item objectForKey:@"sprites"] objectAtIndex:i];
        if (![[aChild objectForKey:@"added"] boolValue]) {
            aRect = [self frameOfSprite:aChild];
            int left = aRect.origin.x,
                right = left + aRect.size.width,
                bottom = aRect.origin.y,
                top = bottom + aRect.size.height;
            if (point.x > left-1 && point.x < left+1) {
                draggedSprite = aChild;
                resizing = 7;
            } else if (point.x > right - 1 && point.x < right + 1) {
                draggedSprite = aChild;
                resizing = 3;
            }
            if (point.y > bottom-1 && point.y < bottom+1) {
                draggedSprite = aChild;
                if (resizing == 3) resizing = 4;
                else if (resizing == 7) resizing = 6;
                else resizing = 5;
            } else if (point.y > top-1 && point.y < top+1) {
                draggedSprite = aChild;
                if (resizing == 3) resizing = 2;
                else if (resizing == 7) resizing = 8;
                else resizing = 1;
            } else if (point.x > left && point.x < right && point.y > bottom && point.y < top) {
                draggedSprite = aChild;
            }
            if (draggedSprite == aChild) {
                [MHSprite selectItem:aChild];
                return;
            }
        }
    }
    draggedSprite = nil;
    //NSLog(@"(%g, %g)", point.x, point.y);
}

- (void)mouseUp:(NSEvent *)theEvent
{
    resizing = 0;
	draggedSprite = nil;
    if ([MHSprite qsMode]) {
	qsRect.origin.y = [self frame].size.height - qsRect.origin.y - qsRect.size.height;
	qsRect.origin.x /= hScalar;
	qsRect.size.width /= hScalar;
	qsRect.origin.y /= vScalar;
	qsRect.size.height /= vScalar;
	[MHSprite newSpriteWithRect:qsRect];
	qsRect.size = NSMakeSize(0,0);
    }
}

- (void)mouseDragged:(NSEvent *)theEvent
{
    NSPoint point = [theEvent locationInWindow];
    NSRect frame = [self frame];
    point.x -= frame.origin.x;
    point.y -= frame.origin.y;
    if ([MHSprite qsMode]) {
	qsRect = [self makeRectFromPoints:point];
	[self setNeedsDisplay:YES];
	return;
    }
    if (!draggedSprite)
        return;
    //if (resizing && [[draggedSprite objectForKey:@"Image"] hasPrefix:@"/"])
    //    return;
    NSRect rect = [self frameOfSprite:draggedSprite];
    int x, y, diff;
    if (!resizing) { // dragging the whole box
            point.x = (double)(point.x - rect.size.width / 2) / hScalar;
            point.y = (double)(frame.size.height - point.y - rect.size.height / 2) / vScalar;
            [draggedSprite setObject:[NSNumber numberWithInt:point.x] forKey:@"X"];
            [draggedSprite setObject:[NSNumber numberWithInt:point.y] forKey:@"Y"];
    } else {
        if (resizing == 8 || resizing == 1 || resizing == 2) {// dragging the top
            y = frame.size.height - ((double)point.y / vScalar);
            diff = [[draggedSprite objectForKey:@"Y"] intValue] - y;
            [draggedSprite setObject:[NSNumber numberWithInt:y] forKey:@"Y"];
            y = [[draggedSprite objectForKey:@"Height"] intValue] + diff;
            if (y > 0)
                [draggedSprite setObject:[NSNumber numberWithInt:y] forKey:@"Height"];
        }
        if (resizing > 1 && resizing < 5) { // dragging the right
            x = ((double)point.x / hScalar) - rect.origin.x;
            if (x > 0)
                [draggedSprite setObject:[NSNumber numberWithInt:x] forKey:@"Width"];
        }
        if (resizing > 3 && resizing < 7) { // dragging the bottom
            y = (double)(rect.origin.y + rect.size.height - point.y) / vScalar;
            if (y > 0)
                [draggedSprite setObject:[NSNumber numberWithInt:y] forKey:@"Height"];
        }
        if (resizing > 5 && resizing < 9) { // dragging the left
            x = ((double)point.x / hScalar);
            diff = [[draggedSprite objectForKey:@"X"] intValue] - x;
            [draggedSprite setObject:[NSNumber numberWithInt:x] forKey:@"X"];
            x = [[draggedSprite objectForKey:@"Width"] intValue] + diff;
            if (x > 0)
                [draggedSprite setObject:[NSNumber numberWithInt:x] forKey:@"Width"];
        }
    }
    [self setNeedsDisplay:YES];
    [MHSprite reloadOutline];
}

- (void)drawSprite:(NSMutableDictionary *)sprite selected:(BOOL)flag
{
    if ([[sprite objectForKey:@"added"] boolValue]) return;
    [[NSColor blueColor] set];
    if (flag)
		[[NSColor redColor] set];
    NSRect frame = [self frameOfSprite:sprite];
    NSArray *iarray = [NSArray arrayWithObjects:@"image", @"rimage", @"cimage", nil];
    int i = [MHSprite selectedImage];
    NSImage *image = [sprite objectForKey:[iarray objectAtIndex:i]];
    if (image) {
        NSRect srcRect;
        srcRect.size = [image size];
        srcRect.origin.x = srcRect.origin.y = 0;
        [image drawInRect:frame fromRect:srcRect operation:NSCompositeSourceOver fraction:1];
    }
    [NSBezierPath strokeRect:frame];
}

- (NSRect)frameOfSprite:(NSMutableDictionary *)sprite
{
    int width = [[sprite objectForKey:@"Width"] intValue];
    int height = [[sprite objectForKey:@"Height"] intValue];
    if (!width) width = 40;
    if (!height) height = 30;
    [sprite setObject:[NSNumber numberWithInt:width] forKey:@"Width"];
    [sprite setObject:[NSNumber numberWithInt:height] forKey:@"Height"];
    //NSSize size = [sprite size];
    NSRect frame;
    NSRect frameRect = [self frame];
    //NSSize origSize = [MHSprite naturalSize];
    //hScalar = (double)frameRect.size.width / (double)origSize.width;
    //vScalar = (double)frameRect.size.height / (double)origSize.height;
    //frame.size.width = (double)size.width * hScalar;
    //frame.size.height = (double)size.height * vScalar;
    id object = [sprite objectForKey:@"X"];
    if (!object) object = [NSNumber numberWithInt:0];
    frame.origin.x = [object intValue];
    object = [sprite objectForKey:@"Y"];
    if (!object) object = [NSNumber numberWithInt:0];
    frame.origin.y = [object intValue];
    frame.size.width = width;
    frame.size.height = height;
    frame = [self scaledFrame:frame];
    frame.origin.y = frameRect.size.height - frame.origin.y - frame.size.height;
    return frame;
}

- (NSRect)scaledFrame:(NSRect)oldFrame
{
    NSRect frame, frameRect = [self frame];
    NSSize origSize = [MHSprite naturalSize];
    hScalar = (double)frameRect.size.width / (double)origSize.width;
    vScalar = (double)frameRect.size.height / (double)origSize.height;
    frame.size.width = (double)oldFrame.size.width * hScalar;
    frame.size.height = (double)oldFrame.size.height * vScalar;
    frame.origin.x = (double)oldFrame.origin.x * hScalar;
    frame.origin.y = (double)oldFrame.origin.y * vScalar;
    return frame;
}

- (NSRect)makeRectFromPoints:(NSPoint)point
{
    NSRect rect;
    if (point.x < qsPoint.x) rect.origin.x = point.x;
    else rect.origin.x = qsPoint.x;
    rect.size.width = point.x - qsPoint.x;
    if (rect.size.width < 0) rect.size.width = 0 - rect.size.width;
    
    if (point.y < qsPoint.y) rect.origin.y = point.y;
    else rect.origin.y = qsPoint.y;
    rect.size.height = point.y - qsPoint.y;
    if (rect.size.height < 0) rect.size.height = 0 - rect.size.height;
    
    return rect;
}

- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
{
    return NSDragOperationCopy;
}

- (BOOL)performDragOperation:(id <NSDraggingInfo>)info
{
    NSPasteboard *pboard = [info draggingPasteboard];
    if (![[pboard types] containsObject:NSFilenamesPboardType] ) return NO;
    NSArray *files = [pboard propertyListForType:NSFilenamesPboardType];
    BOOL success = NO;
    NSImage *image = nil;
    NSString *path = nil;
    int i, n = [files count];
    if (!n) return NO;
    if (n > 3) n = 3;
    for (i=0;i<n;i++) {
        BOOL isDir;
        path = [files objectAtIndex:i];
        if ([[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir] && !isDir) {
            image = [[[NSImage alloc] initWithContentsOfFile:path] autorelease];
            if (image) success = YES;
        }
    }
    if (success) {
        NSPoint point = [info draggingLocation];
        NSRect frame = [self frame];
        point.x -= frame.origin.x;
        point.y -= frame.origin.y;
        NSMutableDictionary *item = [MHSprite selectedItem];
        if ([[item objectForKey:@"isLeaf"] boolValue])
            item = [item objectForKey:@"parent"];
        n = [(NSArray *)[item objectForKey:@"sprites"] count];
        NSMutableDictionary *theHit = nil;
        for (i=n-1;i>=0;i--) {
            id aChild = [[item objectForKey:@"sprites"] objectAtIndex:i];
            NSRect aRect = [self frameOfSprite:aChild];
            if (point.x > aRect.origin.x && point.x < aRect.origin.x + aRect.size.width && point.y > aRect.origin.y && point.y < aRect.origin.y + aRect.size.height) {
                theHit = aChild;
                break;
            }
        }
        if (theHit) {
            NSArray *keys = [NSArray arrayWithObjects:@"Image", @"Rollover", @"Click", nil];
            NSArray *keys2 = [NSArray arrayWithObjects:@"image", @"rimage", @"cimage", nil];
            n = [files count];
            if (n > 3) n = 3;
            for (i=0;i<n;i++) {
                path = [files objectAtIndex:i];
                image = [[[NSImage alloc] initWithContentsOfFile:path] autorelease];
                if (image) {
                    [theHit setObject:path forKey:[keys objectAtIndex:i]];
                    [theHit setObject:image forKey:[keys2 objectAtIndex:i]];
                }
            }
        } else {
            path = [files objectAtIndex:0];
            image = [[[NSImage alloc] initWithContentsOfFile:path] autorelease];
            if (image) {
                [item setObject:path forKey:@"bgImageSource"];
                [item setObject:image forKey:@"bgImage"];
                [item setObject:image forKey:@"Image"];
            }
        }
    }
    return YES;
}

- (void)concludeDragOperation:(id <NSDraggingInfo>)info
{
    [self setNeedsDisplay:YES];
    [MHSprite reloadOutline];
}

@end
