// Copyright 1997-1999 Omni Development, Inc.  All rights reserved.
//
// This software may only be used and reproduced according to the
// terms in the file OmniSourceLicense.html, which should be
// distributed with this project and can also be found at
// http://www.omnigroup.com/DeveloperResources/OmniSourceLicense.html.

#import "OAInspector.h"

#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#import <OmniBase/OmniBase.h>
#import <OmniFoundation/OmniFoundation.h>

RCS_ID("$Header: /Network/Developer/Source/CVS/OmniGroup/OmniAppKit/Inspector.subproj/OAInspector.m,v 1.13 1999/03/30 21:25:57 kc Exp $")

@interface OAInspector (OAPrivateAPI)
- (void)_showInspector;
- (void)_inspectMainWindow;
- (void)_inspectWindow:(NSWindow *)window;
- (void)_selectionMightHaveChangedNotification:(NSNotification *)notification;
- (void)_inspectWindowNotification:(NSNotification *)notification;
- (void)loadInterface;
@end


NSString *OAInspectorSelectionDidChangeNotification = @"OAInspectorSelectionDidChangeNotification";
NSString *OAInspectorShowInspectorDefaultKey = @"OAShowInspector";

static NSString *windowFrameSaveName = @"Inspector";

static OAInspector         *sharedInspector = nil;
static id                   multipleSelectionObject;
static NSMutableDictionary *registeredInspectors = nil;

@implementation OAInspector

+ (void)initialize;
{
    static BOOL initialized = NO;

    [super initialize];
    if (initialized)
        return;
    initialized = YES;

    // Allocate shared instance on first messsage to class.
    registeredInspectors = [[NSMutableDictionary alloc] init];
    multipleSelectionObject = [[NSObject alloc] init];
}

+ (void)didLoad;
{
    // Allows us to bring up the Inspector panel if it was up when the app closed previously.
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(controllerStartRunning:) name:NSApplicationDidFinishLaunchingNotification object:nil];
}

+ (void)controllerStartRunning:(NSNotification *)notification
{
    if ([[OFUserDefaults sharedUserDefaults] boolForKey:OAInspectorShowInspectorDefaultKey])
        [self showInspector];
}

+ (void)registerInspector:(id <OAInspector>)inspector forClass:(Class)aClass;
{
    [registeredInspectors setObject:inspector forKey:aClass];
}

+  (OAInspector *) sharedInspector;
{
    if (!sharedInspector)
        sharedInspector = [[self alloc] init];
    return sharedInspector;
}

+ (void)showInspector
{
    [[self sharedInspector] _showInspector];
}

+ (id)multipleSelectionObject;
{
    return multipleSelectionObject;
}

// Init

- init
{
    [super init];

    isOnScreen = NO;
    return self;
}

- (BOOL)isInspectorVisible
{
    return isOnScreen;
}


// NSWindow delegate methods.

- (void)windowWillClose:(NSNotification *)notification;
{
    NSNotificationCenter *center;

    // Unsubscribe for the notifications we signed up for in -_showInspector
    center = [NSNotificationCenter defaultCenter];
    [center removeObserver:self name:NSWindowDidBecomeMainNotification object:nil];
    [center removeObserver:self name:NSWindowDidResignMainNotification object:nil];
    [center removeObserver:self name:OAInspectorSelectionDidChangeNotification object:nil];

    [[OFUserDefaults sharedUserDefaults] setBool:NO forKey:OAInspectorShowInspectorDefaultKey];
    
    [currentInspector inspectObject:nil];
    isOnScreen = NO;
}

@end


//
// Private API.
//

@implementation OAInspector (OAPrivateAPI)

- (void)_showInspector;
{
    NSNotificationCenter *defaultNotificationCenter;

    if (isOnScreen) {
        [inspectorWindow makeKeyAndOrderFront:self];
        return;
    }

    [[OFUserDefaults sharedUserDefaults] setBool:YES forKey:OAInspectorShowInspectorDefaultKey];

    if (!inspectorWindow)
        [self loadInterface];

    // While the Inspector is visible, watch for any window to become main.  When that happens, determine if that window's delegate responds to the OAInspectableControllerProtocol, and act accordingly.
    defaultNotificationCenter = [NSNotificationCenter defaultCenter];
    [defaultNotificationCenter addObserver:self selector:@selector(_inspectWindowNotification:) name:NSWindowDidBecomeMainNotification object:nil];
    [defaultNotificationCenter addObserver:self selector:@selector(_selectionMightHaveChangedNotification:) name:NSWindowDidResignMainNotification object:nil];
    [defaultNotificationCenter addObserver:self selector:@selector(_selectionMightHaveChangedNotification:) name:OAInspectorSelectionDidChangeNotification object:nil];


    // Since we were just asked to be shown, jumpstart ourselves by inspecting the main window.
    isOnScreen = YES; // Otherwise, _inspectMainWindow will short-circuit
    [self _inspectMainWindow];
    [inspectorWindow makeKeyAndOrderFront:self];
}


- (void)_inspectMainWindow;
{
    [self _inspectWindow:[NSApp mainWindow]];
}

- (void)_inspectWindow:(NSWindow *)window;
{
    NSView *newView;
    id <OAInspectableController> windowDelegate;
    id inspectedObject;
    id <OAInspector, NSObject> newInspector;

    if (!isOnScreen)
        return;

    windowDelegate = [window delegate];

    if ([windowDelegate conformsToProtocol:@protocol(OAInspectableController)])
        inspectedObject = [windowDelegate inspectedObject];
    else
        inspectedObject = nil;

    newInspector = nil;
    // When inspecting nil, bring up the "No Inspector" panel.
    if (inspectedObject == multipleSelectionObject)
        newView = multiInspectorBox;
    else if (!inspectedObject)
        newView = noInspectorBox;
    else {
        newInspector = [registeredInspectors objectForKey:[inspectedObject class]];
        newView = [newInspector inspectorView];
        OBASSERT(newView); // Don't vend me objects I can't inspect.
    }
    
    [inspectorWindow makeFirstResponder:inspectorWindow];

    if (newView != currentInspectorView) {
        [currentInspectorView removeFromSuperview];
        [inspectorBox addSubview:newView];
        [newView setFrameOrigin:NSMakePoint(0, 0)];

        [currentInspector inspectObject:nil];
        currentInspector = newInspector;

        [newView setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
        [newView setFrameSize:[inspectorBox frame].size];
        currentInspectorView = newView;
        if ([currentInspector inspectorName])
            [inspectorWindow setTitle:[[currentInspector inspectorName] stringByAppendingString:@" Inspector"]];
        else
            [inspectorWindow setTitle:@"Inspector"];
    }
    [currentInspector inspectObject:inspectedObject];
    [inspectorBox setNeedsDisplay:YES];
}

- (void)_selectionMightHaveChangedNotification:(NSNotification *)notification;
{
    [self _inspectMainWindow];
}

- (void)_inspectWindowNotification:(NSNotification *)notification;
{
    [self _inspectWindow:(NSWindow *)[notification object]];
}

- (void)loadInterface;
{
    if (![NSBundle loadNibNamed:@"OAInspector.nib" owner:self])
        [NSException raise:NSInternalInconsistencyException format:@"Unable to locate OAInspector.nib"];

    [inspectorWindow setDelegate:self];

    [noInspectorBox retain];
    [noInspectorBox removeFromSuperview];

    [multiInspectorBox retain];
    [multiInspectorBox removeFromSuperview];
    
    [inspectorBox setAutoresizesSubviews:YES];

    [inspectorWindow setFrameUsingName:windowFrameSaveName];
    [inspectorWindow setFrameAutosaveName:windowFrameSaveName];

}

@end

