//
//  ICeCoffEETTView.m
//  ICeCoffEE
//
//  Created by Nicholas Riley on 2/21/08.
//  Copyright 2008 Nicholas Riley. All rights reserved.
//

#import "ICeCoffEETTView.h"
#import "ICeCoffEE.h"
#import "ICeCoffEEParser.h"
#import "ICeCoffEETTViewTrigger.h"
#include <unistd.h>

static NSRange ICCF_zeroRange = { NSNotFound, 5 };

@implementation ICeCoffEETTViewSuper
// NSTextInput implementation
- (void)insertText:(id)aString {}
- (void)doCommandBySelector:(SEL)aSelector {}
- (void)setMarkedText:(id)aString selectedRange:(NSRange)selRange {}
- (void)unmarkText {}
- (BOOL)hasMarkedText { return NO; }
- (long)conversationIdentifier { return 0; }
- (NSAttributedString *)attributedSubstringFromRange:(NSRange)theRange { return nil; }
- (NSRange)markedRange { return ICCF_zeroRange; }
- (NSRange)selectedRange { return ICCF_zeroRange; }
- (NSRect)firstRectForCharacterRange:(NSRange)theRange { return NSZeroRect; }
- (unsigned int)characterIndexForPoint:(NSPoint)thePoint { return 0; }
- (NSArray*)validAttributesForMarkedText { return nil; }
// Selection
- (void)clearTextSelection {}
- (void)setSelectedRange:(NSRange)charRange {}
// misc. other stuff
- (NSString *)string { return nil; }
@end

static BOOL ICCF_discardNextMouseUp = NO;

void ICCF_LaunchURLFromTTView(ICeCoffEETTView *self, NSEvent *triggeringEvent, NSRange range) {
    
    @try {
	NSString *s = [self string];
	unsigned length = [s length];
	NSCAssert(s != nil && length != 0, ICCF_LocalizedString(@"No text was found"));
	
	ICCF_StartIC();
	
	// XXX handle discontiguous/rectangular selection with [self valueForKey: @"textSelectionRanges"] => NSIndexSet    
	NSCAssert(range.location < length, ICCF_LocalizedString(@"Sorry, ICeCoffEE was unable to find anything to select"));
	if (range.length == 0) {
	    range.length = 1;
	    range = ICCF_URLEnclosingRange(s, range);
	    [self setSelectedRange: range];
	}
	
	iccfURLAction keyboardAction = ICCF_KeyboardAction(triggeringEvent);
	if (ICCF_LaunchURL([s substringWithRange: range], keyboardAction)) {
	    if (ICCF_prefs.textBlinkEnabled) {
		for (unsigned i = 0 ; i < ICCF_prefs.textBlinkCount ; i++) {
		    [self clearTextSelection];
		    [self display];
		    usleep(kICBlinkDelayUsecs);
		    [self setSelectedRange: range];
		    [self display];
		    usleep(kICBlinkDelayUsecs);
		}
	    }
	} else if (keyboardAction.presentMenu) {
	    // mouse up used to cancel menu?
	    // XXX next click lost if Esc used; next drag behaves like Command-drag
	    ICCF_discardNextMouseUp = YES;
	}
    } @catch (NSException *e) {
	ICCF_HandleException(e, triggeringEvent);
    }
    
    ICCF_StopIC();
}


@implementation ICeCoffEETTView

static NSEvent *ICCF_downEvent;

- (void)mouseUp:(NSEvent *)upEvent;
{
    if (ICCF_downEvent != nil) {
        NSPoint downPt = [ICCF_downEvent locationInWindow];
        NSPoint upPt = [upEvent locationInWindow];
        if (abs(downPt.x - upPt.x) <= kICHysteresisPixels && abs(downPt.y - upPt.y) <= kICHysteresisPixels) {
	    [ICeCoffEETTViewTrigger setTriggerForEvent: ICCF_downEvent onTarget: self];
	    ICCF_discardNextMouseUp = YES; // otherwise Command-Option-click => cursor repositioning Option-click 
        }
        [ICCF_downEvent release];
        ICCF_downEvent = nil;
    }
    ICLog(@"ICeCoffEETTView up: %@", upEvent);
    if (ICCF_discardNextMouseUp) {
	ICCF_discardNextMouseUp = NO;
	return;
    }
    [super mouseUp: upEvent];
}

- (void)mouseDown:(NSEvent *)downEvent;
{
    [ICeCoffEETrigger cancel];

    if (ICCF_enabled && ICCF_prefs.commandClickEnabled && ICCF_EventIsCommandMouseDown(downEvent)) {
	[ICCF_downEvent release];
	ICCF_downEvent = [downEvent retain];
    }
    ICLog(@"ICeCoffEETTView down: %@", downEvent);
    [super mouseDown: downEvent];
}

- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender;
{
    if (!ICCF_prefs.terminalRequireOptionForSelfDrag || [sender draggingSource] != self || ([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask)) {
        [super draggingEntered: sender];
        // When doing non-self drags, this works around one bug in Terminal wherein the option key acts as a toggle, and it shouldn't (see Aqua HIG).  Unfortunately, this messes up drag feedback for self drags, but I don't know of any way to fix it.  Not that most Cocoa apps get it remotely right, anyway.
        return NSDragOperationCopy;
    }
    return NSDragOperationNone;
}

@end
