//
//  TaskTableView.m
//  RubyFrictionless
//
//  Created by Pierce T. Wetter III on 4/17/07.
//  Copyright 2007 __MyCompanyName__. All rights reserved.
//

#import "TaskTableView.h"
//#import "NSTableView-OAExtensions.h"

typedef struct {
	float red1, green1, blue1, alpha1;
	float red2, green2, blue2, alpha2;
} _twoColorsType;

void _linearColorBlendFunction(void *info, const float *in, float *out)
{
	_twoColorsType *twoColors = info;
	
	out[0] = (1.0 - *in) * twoColors->red1 + *in * twoColors->red2;
	out[1] = (1.0 - *in) * twoColors->green1 + *in * twoColors->green2;
	out[2] = (1.0 - *in) * twoColors->blue1 + *in * twoColors->blue2;
	out[3] = (1.0 - *in) * twoColors->alpha1 + *in * twoColors->alpha2;
}

void _linearColorReleaseInfoFunction(void *info)
{
	free(info);
}
//#import <OmniAppKit/OATypeAheadSelectionHelper.h>
//static OATypeAheadSelectionHelper *TypeAheadHelper = nil;

static const CGFunctionCallbacks linearFunctionCallbacks = {0, &_linearColorBlendFunction, &_linearColorReleaseInfoFunction};

@implementation TaskTableView

- (void) showActionable: (id) sender
{
	[_delegate showActionable: sender];
}
- (void) showToDo: (id) sender
{
	[_delegate showToDo: sender];
}
- (void) showDone: (id) sender
{
	[_delegate showDone: sender];
}

- (void) delete: (id) sender
{
	[_delegate delete: sender];
}

- (void) addChild: (id) sender
{
	[_delegate addChildToTasks: sender];
}

- (void) addSibling: (id) sender
{
	[_delegate addChildToTasks: sender];
}

- (void) textDidEndEditing: (NSNotification *) notification
{
    NSDictionary *userInfo;
    userInfo = [notification userInfo];
	
    NSNumber *textMovement;
    textMovement = [userInfo objectForKey: @"NSTextMovement"];
	
    int movementCode;
    movementCode = [textMovement intValue];
	
    // see if this a 'pressed-return' instance
	
    if (movementCode == NSReturnTextMovement) {
        // hijack the notification and pass a different textMovement
        // value
		
        textMovement = [NSNumber numberWithInt: NSIllegalTextMovement];
		
        NSDictionary *newUserInfo;
        newUserInfo = [NSDictionary dictionaryWithObject: textMovement
												  forKey: @"NSTextMovement"];
		
        notification = [NSNotification notificationWithName:
			[notification name]
													 object: [notification object]
												   userInfo: newUserInfo];
    }
	
    [super textDidEndEditing: notification];
	
} // textDidEndEditing
- (void)dealloc;
{
	[[NSNotificationCenter defaultCenter] removeObserver:self];
	[super dealloc];
}


// NSView

- (void)viewWillMoveToWindow:(NSWindow *)newWindow;
{
	[[NSNotificationCenter defaultCenter] removeObserver:self
													name:NSWindowDidResignKeyNotification object:nil];
	[[NSNotificationCenter defaultCenter] addObserver:self
											 selector:@selector(_windowDidChangeKeyNotification:)
												 name:NSWindowDidResignKeyNotification object:newWindow];
	[[NSNotificationCenter defaultCenter] removeObserver:self
													name:NSWindowDidBecomeKeyNotification object:nil];
	[[NSNotificationCenter defaultCenter] addObserver:self
											 selector:@selector(_windowDidChangeKeyNotification:)
												 name:NSWindowDidBecomeKeyNotification object:newWindow];
}
// NSTableView

- (void)highlightSelectionInClipRect:(NSRect)rect;
{
	// Take the color apart
	NSColor *alternateSelectedControlColor = [NSColor alternateSelectedControlColor];
	float hue, saturation, brightness, alpha;
	[[alternateSelectedControlColor colorUsingColorSpaceName:NSDeviceRGBColorSpace] getHue:&hue
																				saturation:&saturation brightness:&brightness alpha:&alpha];
	
	// Create synthetic darker and lighter versions
	NSColor *lighterColor = [NSColor colorWithDeviceHue:hue
											 saturation:MAX(0.0, saturation-.12) 
											 brightness:MIN(1.0,brightness+0.30) 
												  alpha:alpha];
	NSColor *darkerColor = [NSColor colorWithDeviceHue:hue
											saturation:MIN(1.0, (saturation > .04) ? saturation+0.12 : 0.0) 
											brightness:MAX(0.0, brightness-0.045) 
												 alpha:alpha];
	
	/* If this view isn't key, use the gray version of the dark color.
		Note that this varies from the standard gray version that NSCell
		returns as its highlightColorWithFrame: when the cell is not in a
		key view, in that this is a lot darker. Mike and I think this is
		justified for this kind of view -- if you're using the dark
		selection color to show the selected status, it makes sense to
		leave it dark. */
	NSResponder *firstResponder = [[self window] firstResponder];
	if (![firstResponder isKindOfClass:[NSView class]] ||
		![(NSView *)firstResponder isDescendantOf:self] || 
		![[self window] isKeyWindow]) 
	{
		alternateSelectedControlColor = [[alternateSelectedControlColor colorUsingColorSpaceName:NSDeviceWhiteColorSpace] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
		lighterColor = [[lighterColor colorUsingColorSpaceName:NSDeviceWhiteColorSpace] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
		darkerColor = [[darkerColor colorUsingColorSpaceName:NSDeviceWhiteColorSpace] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
	}
	
	// Set up the helper function for drawing washes
	CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
	_twoColorsType *twoColors = malloc(sizeof(_twoColorsType)); /* We
		malloc() the helper data because we may draw this wash during
		printing, in which case it won't necessarily be evaluated
	immediately. We need for all the data the shading function needs
		to draw to potentially outlive us.*/
	[lighterColor getRed:&twoColors->red1 green:&twoColors->green1
					blue:&twoColors->blue1 alpha:&twoColors->alpha1];
	[darkerColor getRed:&twoColors->red2 green:&twoColors->green2
				   blue:&twoColors->blue2 alpha:&twoColors->alpha2];
	static const float domainAndRange[8] = {0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0};
	CGFunctionRef linearBlendFunctionRef = CGFunctionCreate(twoColors, 1,
															domainAndRange, 4, domainAndRange, &linearFunctionCallbacks);
	
	NSIndexSet *selectedRowIndexes = [self selectedRowIndexes];
	unsigned int rowIndex = [selectedRowIndexes indexGreaterThanOrEqualToIndex:0];
	
	while (rowIndex != NSNotFound) {
		unsigned int endOfCurrentRunRowIndex, newRowIndex = rowIndex;
		do {
			endOfCurrentRunRowIndex = newRowIndex;
			newRowIndex = [selectedRowIndexes indexGreaterThanIndex:endOfCurrentRunRowIndex];
		} while (newRowIndex == endOfCurrentRunRowIndex + 1);
		
		NSRect rowRect = NSUnionRect([self rectOfRow:rowIndex],
									 [self rectOfRow:endOfCurrentRunRowIndex]);
		
		NSRect topBar, washRect;
		NSDivideRect(rowRect, &topBar, &washRect, 1.0, NSMinYEdge);
		
		// Draw the top line of pixels of the selected row in the alternateSelectedControlColor
		[alternateSelectedControlColor set];
		NSRectFill(topBar);
		
		// Draw a soft wash underneath it
		CGContextRef context = [[NSGraphicsContext currentContext]
			graphicsPort];
		CGContextSaveGState(context); {
			CGContextClipToRect(context, (CGRect){{NSMinX(washRect),
				NSMinY(washRect)}, {NSWidth(washRect),
					NSHeight(washRect)}});
			CGShadingRef cgShading = CGShadingCreateAxial(colorSpace,
														  CGPointMake(0, NSMinY(washRect)), CGPointMake(0,
																										NSMaxY(washRect)), linearBlendFunctionRef, NO, NO);
			CGContextDrawShading(context, cgShading);
			CGShadingRelease(cgShading);
		} CGContextRestoreGState(context);
		
		rowIndex = newRowIndex;
	}
				
				
	CGFunctionRelease(linearBlendFunctionRef);
	CGColorSpaceRelease(colorSpace);
}

- (void)selectRow:(int)row byExtendingSelection:(BOOL)extend;
{
	[super selectRow:row byExtendingSelection:extend];
	[self setNeedsDisplay:YES]; // we display extra because we draw multiple contiguous selected rows differently, so changing one row's selection can change how others draw.
}

- (void)deselectRow:(int)row;
{
	[super deselectRow:row];
	[self setNeedsDisplay:YES]; // we display extra because we draw multiple contiguous selected rows differently, so changing one row's selection can change how others draw.
}

- (void)keyDown:(NSEvent *)theEvent;
{
    NSString *characters;
    unichar firstCharacter;
    unsigned int modifierFlags;
	
    characters = [theEvent characters];
    modifierFlags = [theEvent modifierFlags];
    firstCharacter = [characters characterAtIndex:0];
	
    switch (firstCharacter) {
		case 13:
			if (modifierFlags & NSAlternateKeyMask) 
				[_delegate addChild:nil];
			else
				[_delegate addSibling:nil];
			return;
		case NSDeleteFunctionKey:
		case 127:
			[self delete: nil];
			return;
		case 'a':
			[self showActionable: nil];
			return;
		case 't':
			[self showToDo: nil];
			return;
		case 'd':
			[self showDone: nil];
			return;
        case 'e': { // not reached if type-ahead selection is turned on
            int columnIndex, rowIndex;
			
            columnIndex = [[self tableColumns] indexOfObject:[self columnWithIdentifier:@"name"]];
            rowIndex = [self selectedRow];
            [self editColumn:columnIndex row:rowIndex withEvent:nil select:YES];
            return;
        } 
			/*case 'g': // not reached if type-ahead selection is turned on
            [self group:nil];
            return;
        case 'u': // not reached if type-ahead selection is turned on
            [self ungroup:nil];
            return;*/
       /* case '<': {
            NSArray *selectedItems;
			
            selectedItems = [self selectedItems];
            [self contractAll:nil];
            [self setSelectedItems:selectedItems];
            return;
        }
        case '>': {
            NSArray *selectedItems;
			
            selectedItems = [self selectedItems];
            [self expandAll:nil];
            [self setSelectedItems:selectedItems];
            return;
        }
        case NSLeftArrowFunctionKey:
            if (modifierFlags & NSAlternateKeyMask) {
                [self contractSelection:nil];
                return;
            }
            break;
        case NSRightArrowFunctionKey:
            if (modifierFlags & NSAlternateKeyMask) {
                [self expandSelection:nil];
                return;
            }
            break;*/
        default:
            break;
    }
    [self interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
}

// NSTableView (Private)

- (id)_highlightColorForCell:(NSCell *)cell;
{
	return nil;
}

@end
@implementation TaskTableView (Private)

- (void)_windowDidChangeKeyNotification:(NSNotification
										 *)notification;
{
	[self setNeedsDisplay:YES];
}


@end
