//
//  FSAViewAssociationController.m
//  F-Script Anywhere
//
//  Created by Nicholas Riley on Wed Jul 17 2002.
//  Copyright (c) 2002 Nicholas Riley. All rights reserved.
//

/*

 F-Script Anywhere is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 F-Script Anywhere is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with F-Script Anywhere; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*/

#import "FSAViewAssociationController.h"
#import "FSAController.h"
#import "FSAWindowManager.h"
#import "FSAnywhere.h"
#import <FScript/FSInterpreter.h>
#import <FScript/System.h>

@implementation FSAViewAssociationController

- (id)initWithFSAController:(FSAController *)fsa;
{
    self = [super init];

    if (self != nil) {
        NSImage *bullseyeImage = [[NSImage alloc] initByReferencingFile: [[NSBundle bundleForClass: [self class]] pathForResource: @"Bullseye menu cursor" ofType: @"tiff"]];
        NSString *label = [fsa interpreterLabel];
        
        interpreter = [[[fsa interpreterView] interpreter] retain];
        system = [fsa system];
        [[self window] setResizeIncrements: NSMakeSize(1, 12)];
        if (label != nil) [[self window] setTitle: [NSString stringWithFormat: @"%@: %@", [[self window] title], label]];
        bullseyeCursor = [[NSCursor alloc] initWithImage: bullseyeImage hotSpot: NSMakePoint(6, 7)];
    }
    return self;
}

- (void)dealloc;
{
    [viewHierarchyMenu release];
    [selectedElement release];
    [interpreter release];
    [bullseyeCursor release];
    [[NSNotificationCenter defaultCenter] removeObserver: self];
    [super dealloc];
}

- (void)stopCapturingVoluntarily:(BOOL)voluntary;
{
    FSALog(@"stopping capture");
    [[NSNotificationCenter defaultCenter] removeObserver: self name: NSMenuWillSendActionNotification object: nil];
    if (voluntary) {
        FSALog(@"voluntary!");
        [[self window] makeKeyAndOrderFront: self];
        [bullseyeCursor pop];
    }
}

- (void)_addElement:(id)element withLabel:(NSString *)label toSubmenuForItem:(NSMenuItem *)item;
{
    NSMenu *submenu = [item submenu];
    NSMenuItem *subItem;
    if (submenu == nil) {
        id superElement = [item representedObject];
        submenu = [[NSMenu alloc] initWithTitle: @""];
        subItem = [submenu addItemWithTitle: NSStringFromClass([superElement class])
                                     action: @selector(elementSelected:)
                              keyEquivalent: @""];
        [subItem setTarget: self];
        [subItem setRepresentedObject: superElement];
        [item setSubmenu: submenu];
        [submenu release];
    }
    [submenu addItem: [NSMenuItem separatorItem]];
    [submenu addItemWithTitle: label action: nil keyEquivalent: @""];
    subItem = [submenu addItemWithTitle: [@"  "
                stringByAppendingString: NSStringFromClass([element class])]
                                           action: @selector(elementSelected:)
                                    keyEquivalent: @""];
    [subItem setTarget: self];
    [subItem setRepresentedObject: element];
}

- (void)_addValueForSelector:(SEL)sel withLabel:(NSString *)label toSubmenuForItem:(NSMenuItem *)item;
{
    id obj = [item representedObject];
    if ([obj respondsToSelector: sel]) {
        id value = [obj performSelector: sel];
        if (value == nil) return;
        [self _addElement: value withLabel: label toSubmenuForItem: item];
    }
}

- (void)_addElementToMenu:(id)element;
{
    NSMenuItem *item;
    if (element == nil) return;
    item = [viewHierarchyMenu addItemWithTitle: [@"  "
                stringByAppendingString: NSStringFromClass([element class])]
                                        action: @selector(elementSelected:)
                                 keyEquivalent: @""];
    [item setTarget: self];
    [item setRepresentedObject: element];
    [self _addValueForSelector: @selector(windowController) withLabel: @"Window Controller" toSubmenuForItem: item];
    [self _addValueForSelector: @selector(delegate) withLabel: @"Delegate" toSubmenuForItem: item];
    [self _addValueForSelector: @selector(dataSource) withLabel: @"Data Source" toSubmenuForItem: item];
    [self _addValueForSelector: @selector(target) withLabel: @"Target" toSubmenuForItem: item];
    [self _addValueForSelector: @selector(cell) withLabel: @"Cell" toSubmenuForItem: item];
}

- (void)captureOneView;
{
    NSEvent *event;
    NSView *view, *superView = nil, *contentView;
    NSWindow *eventWindow;
    static unsigned captureCount = 0;
    unsigned capture = captureCount++;
    
    FSALog(@"%4u>capturing one", capture);
    [bullseyeCursor push];
captureElement:
    [bullseyeCursor set];
    FSALog(@"%4u waiting for event...", capture);
    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(menuWillSendAction:) name: NSMenuWillSendActionNotification object: nil];
    event = [NSApp nextEventMatchingMask: NSLeftMouseDownMask | NSRightMouseDownMask | NSOtherMouseDownMask | NSKeyUpMask | NSAppKitDefinedMask
                               untilDate: [NSDate distantFuture]
                                  inMode: NSEventTrackingRunLoopMode
                                 dequeue: YES];
    FSALog(@"%4u got %@", capture, event);
    [[NSNotificationCenter defaultCenter] removeObserver: self name: NSMenuWillSendActionNotification object: nil];
    if ([event type] == NSAppKitDefined) {
        if ([event subtype] == NSApplicationDeactivatedEventType) {
            [NSApp discardEventsMatchingMask: NSAnyEventMask beforeEvent: event];
            [self stopCapturingVoluntarily: NO];
            [NSApp sendEvent: event];
            return;
        }
        goto captureElement;
    }
    if ([event type] == NSKeyUp) {
        [NSApp discardEventsMatchingMask: NSAnyEventMask & ~NSKeyUpMask beforeEvent: event];
        FSALog(@"%4u<stop capture [key up]", capture);
        [self stopCapturingVoluntarily: YES];
        return;
    }
    [viewHierarchyMenu release]; viewHierarchyMenu = nil;
    viewHierarchyMenu = [[NSMenu alloc] initWithTitle: @""];
    NS_DURING
        eventWindow = [event window];
        contentView = [eventWindow contentView];
        view = [[contentView superview] hitTest: [event locationInWindow]];
        if (view == nil) {
            [self captureOneView];
            NS_VOIDRETURN;
        }
        [viewHierarchyMenu addItemWithTitle: @"View" action: nil keyEquivalent: @""];
        [self _addElementToMenu: view];
        superView = view;
        do {
            superView = [superView superview];
            if (superView == nil) break;
            [self _addElementToMenu: superView];
        } while (superView != contentView);
        [viewHierarchyMenu addItem: [NSMenuItem separatorItem]];
        [viewHierarchyMenu addItemWithTitle: @"Window" action: nil keyEquivalent: @""];
        [self _addElementToMenu: eventWindow];
    NS_HANDLER
	[self alertWithString:[NSString stringWithFormat: @"Çan exception occurred: %@È", localException]];
    NS_ENDHANDLER
    [NSMenu popUpContextMenu: viewHierarchyMenu withEvent: event forView: view];
    [self stopCapturingVoluntarily: YES];
//    if ([captureButton state] == NSOnState) goto captureElement;
    FSALog(@"%4u<stop capture [fell through to end]", capture);
}

- (IBAction)captureView:(id)sender
{
    [selectedElement release]; selectedElement = nil;
    [self captureOneView];
}

- (void)setSelectedElement:(id)element;
{
    FSALog(@"element selected: %@", element);
    NS_DURING
        [selectedElement release];
        selectedElement = [element retain];
        [[self window] orderFront: self];
    NS_HANDLER
	[self alertWithString:[NSString stringWithFormat: @"Çan exception occurred: %@È", localException]];
    NS_ENDHANDLER
    [viewHierarchyMenu release]; viewHierarchyMenu = nil;
}

- (void)elementSelected:(NSMenuItem *)sender;
{
    [self setSelectedElement: [sender representedObject]];
    [system browse: selectedElement];
//    [self captureOneView];
}

- (void)menuWillSendAction:(NSNotification *)notification;
{
    NSMenuItem *item = [[notification userInfo] objectForKey: @"MenuItem"];
    [self setSelectedElement: item];
    [NSApp discardEventsMatchingMask: NSAnyEventMask beforeEvent: [NSApp currentEvent]];
    // we're already capturing, don't do it again
}

- (IBAction)viewInObjectBrowser:(id)sender;
{
    FSALog(@"system: %@", system);
    [system browse: selectedElement];
}

- (void)alertWithString:(NSString *)alertString
{
    [NSAlert alertWithMessageText:alertString
		    defaultButton:nil
		  alternateButton:nil
		      otherButton:nil
	informativeTextWithFormat:nil];
}

@end