//
//  ICeCoffEEWebKit.m
//  ICeCoffEE APE
//
//  Created by Nicholas Riley on Sun Jan 19 2003.
//  Copyright (c) 2003 Nicholas Riley. All rights reserved.
//

#import "ICeCoffEEWebKit.h"
#import "ICeCoffEEWebPolicyDelegate.h"
#import "ICeCoffEEParser.h"
#import "ICeCoffEETrigger.h"
#import <WebKit/WebKit.h>
#import <unistd.h>

// XXX WebCoreFrameBridge is going away
// (see <http://trac.webkit.org/projects/webkit/changeset/30712>)
// WebCoreBridge, from WebCoreBridge.h (Safari 2)
// Web(Core)FrameBridge, from WebCoreFrameBridge.h (Safari 3)
@interface WebCoreBridge : NSObject

// XXX move to DOM-based accessors
- (DOMRange *)convertNSRangeToDOMRange:(NSRange)range;
- (NSString *)stringForRange:(DOMRange *)range;

@end

// XXX WebHTMLView is going away
@interface WebHTMLView : NSObject

- (NSRect)selectionRect;
- (DOMRange *)_documentRange;

- (WebView *)_webView;
- (WebCoreBridge *)_bridge; // WebFrameBridge in Safari 3 (see above)

@end

@implementation ICeCoffEEWebKit

- (NSMenu *)menuForEvent:(NSEvent *)e;
{
    NSMenu *myMenu = [super menuForEvent: e];
    return ICCF_MenuForEvent(self, myMenu, e);
}

static NSEvent *downEvent = nil;
static id /* (WebPolicyDelegate) */ policyDelegate;
static id /* DOMRange */ selectedRange;

- (void)mouseDown:(NSEvent *)e;
{
    [downEvent release]; downEvent = nil;
    if (ICCF_enabled && ICCF_prefs.commandClickEnabled && ICCF_EventIsCommandMouseDown(e)) {
	if ([self respondsToSelector: @selector(_webView)]) {
	    WebView *webView = [(WebHTMLView *)self _webView];
	    
	    // save selection: it may be deselected on super mouseDown
	    selectedRange = [[webView selectedDOMRange] retain];
	    
	    // stop any URL launching from happening
	    if ([webView isEditable]) {
		policyDelegate = [[webView policyDelegate] retain];
		[webView setPolicyDelegate: [ICeCoffEEWebPolicyDelegate sharedDelegate]];
	    }
	    
	    downEvent = [e retain];
	}
    }
    [super mouseDown: e];
}

- (void)mouseUp:(NSEvent *)e;
{
    [super mouseUp: e];

    if (downEvent == nil)
	return;
    
    WebView *webView = [(WebHTMLView *)self _webView];
    BOOL isEditable = [webView isEditable];

    if (isEditable) {
	[webView setPolicyDelegate: policyDelegate];
	[policyDelegate release]; policyDelegate = nil;
    }

    NSPoint downPt = [downEvent locationInWindow];
    NSPoint upPt = [e locationInWindow];
    if (abs(downPt.x - upPt.x) > kICHysteresisPixels && abs(downPt.y - upPt.y) > kICHysteresisPixels)
	return;

    @try {
	if (!isEditable)
	    [webView setEditable: YES];

	NSPoint viewClickPt = [webView convertPoint: downPt fromView: nil];
	NSDictionary *elementDict = [webView elementAtPoint: viewClickPt];
	NSLog(@"elementDict: %@", elementDict);
	NSAssert([elementDict count] != 0, ICCF_LocalizedString(@"Sorry, ICeCoffEE was unable to find anything to select"));

	WebCoreBridge *bridge = [(WebHTMLView *)self _bridge];

	id link = [elementDict objectForKey: @"WebElementLinkURL"];
	NSString *url = [link isKindOfClass: [NSURL class]] ? [link absoluteString] : nil;

	ICCF_StartIC();
	
	id /* DOMRange */ domRange = nil;
	
	if (url != nil) {
	    ICLog(@"got a link");
	    if (!isEditable) {
		ICCF_StopIC();
		return;
	    }
	    // XXX handle existing selection
	    domRange = [webView selectedDOMRange];
	    [domRange selectNode: [elementDict objectForKey:@"WebElementDOMNode"]];
	    [webView setSelectedDOMRange: domRange affinity: NSSelectionAffinityDownstream];
	} else {
	    // may have become deselected in mouseDown
	    [webView setSelectedDOMRange: selectedRange affinity: NSSelectionAffinityDownstream];
	    
	    // XXX at some point, characterIndexForPoint: wasn't implemented, so this will fail
	    NSRange range = [ICeCoffEETrigger rangeForEvent: downEvent onTarget: (NSView<NSTextInput> *)self];

	    // XXX limit to a reasonable size
	    // NSRange fetchRange = [bridge convertDOMRangeToNSRange: [(WebHTMLView *)self _documentRange]];
	    NSString *s = [bridge stringForRange: [(WebHTMLView *)self _documentRange]];
	
	    if (range.length == 0) {
		range.length = 1;
		range = ICCF_URLEnclosingRange(s, range);
		domRange = [bridge convertNSRangeToDOMRange: range];
		[webView setSelectedDOMRange: domRange affinity: NSSelectionAffinityDownstream];
	    } else {
		domRange = [bridge convertNSRangeToDOMRange: range];
	    }
	    
	    url = [s substringWithRange: range];
	}	
	
	if (ICCF_LaunchURL(url, ICCF_KeyboardAction(downEvent)) && ICCF_prefs.textBlinkEnabled && domRange != nil) {
	    NSRect selectionRect = [(WebHTMLView *)self selectionRect];
	    for (int i = 0 ; i < ICCF_prefs.textBlinkCount ; i++) {
		[webView setSelectedDOMRange: nil affinity: NSSelectionAffinityDownstream];
		[self setNeedsDisplayInRect: selectionRect];
		[self display];
		usleep(kICBlinkDelayUsecs);
		[webView setSelectedDOMRange: domRange affinity: NSSelectionAffinityDownstream];
		[self setNeedsDisplayInRect: selectionRect];
		[self display];
		usleep(kICBlinkDelayUsecs);
	    }
	}
    } @catch (NSException *e) {
	ICCF_HandleException(e, downEvent);
    } @finally {
	[selectedRange release]; selectedRange = nil;
	[downEvent release]; downEvent = nil;
	if (!isEditable)
	    [webView setEditable: NO];
    }

    ICCF_StopIC();
}

@end
