// 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 "OAStatusDisplayer.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/Widgets.subproj/OAStatusDisplayer.m,v 1.8 1999/03/30 21:26:13 kc Exp $")

#import "OAStatusView.h"

static BOOL shouldShowStatusView = YES;

@interface OAStatusDisplayer (Private)
- (void)updateWindows;
@end

@implementation OAStatusDisplayer

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

    [super initialize];
    if (hasBeenInitialized)
        return;

    hasBeenInitialized = YES;
    shouldShowStatusView = [[OFUserDefaults sharedUserDefaults] boolForKey:@"OAShouldShowStatusView"];
}

// Init and dealloc

- initForView:(NSView <OAStatusViewPosition> *)aView;
{
    if (!(self = [super init]))
        return nil;
    
    viewToDisplayOver = [aView retain];

    statusView = [[OAStatusView alloc] init];

    statusWindow = [[NSWindow alloc] initWithContentRect:NSMakeRect(0.0, 0.0, 16.0, 16.0) styleMask:0 backing:NSBackingStoreBuffered defer:NO];
    [statusWindow setContentView:statusView];
    [statusView setFrameOrigin:NSZeroPoint];

    bufferWindow = [[NSWindow alloc] initWithContentRect:NSMakeRect(0.0, 0.0, 16.0, 16.0) styleMask:0 backing:NSBackingStoreBuffered defer:NO];

    return self;
}

- (void)dealloc;
{
    [statusView release];
    
    [statusWindow close];
    [bufferWindow close];
    
    [viewToDisplayOver release];
    [super dealloc];
}


// API

- (void)setStatus:(NSString *)aStatus;
{
    flags.shouldDraw = (aStatus != nil);

    [statusView setStatus:aStatus];

    [self updateWindows];
}

- (void)setStatus:(NSString *)aStatus withProgress:(unsigned int)amount ofTotal:(unsigned int)total;
{
    flags.shouldDraw = YES;

    [statusView setStatus:aStatus withProgress:amount ofTotal:total];

    [self updateWindows];
}


// OAExtraWindowDrawing protocol

- (void)windowWillFlush:(NSWindow *)window;
{
    NSRect frame;
    NSView *drawInView, *focusView;
    NSPoint upperRightPoint;
    BOOL lockedFocus;
    NSRect limitFrame;

    if (!flags.shouldDraw)
        return;
    
    upperRightPoint = [viewToDisplayOver upperRightCornerForStatusDisplayer:self shouldDrawInView:&drawInView];

    upperRightPoint = [drawInView convertPoint:upperRightPoint toView:nil];

    frame = [statusView frame];
    statusRect = NSMakeRect(upperRightPoint.x - NSWidth(frame), upperRightPoint.y - NSHeight(frame), NSWidth(frame), NSHeight(frame));

    // Don't draw outside of the view we're supposedly drawing in
    limitFrame = [drawInView convertRect:[drawInView bounds] toView:nil];
    if (NSMinX(statusRect) < NSMinX(limitFrame)) {
        float amountToShrink;

        amountToShrink = NSMinX(limitFrame) - NSMinX(statusRect);
        statusRect.origin.x += amountToShrink;
        statusRect.size.width -= amountToShrink;
    }
    statusRect = NSIntersectionRect(statusRect, limitFrame);
    if (NSIsEmptyRect(statusRect))
        return;

    // Save from main window onto bufferWindow
    [[bufferWindow contentView] lockFocus];
    PScomposite(NSMinX(statusRect), NSMinY(statusRect), NSWidth(statusRect), NSHeight(statusRect), [window gState], 0, 0, NSCompositeSourceOver);
    [[bufferWindow contentView] unlockFocus];

    focusView = [NSView focusView];
    if (!focusView) {
        focusView = [window contentView];
        [focusView lockFocus];
        lockedFocus = YES;
    } else
        lockedFocus = NO;

    statusRect = [focusView convertRect:statusRect fromView:nil];

    // Composite from statusWindow into main window
    PScomposite(0, 0, NSWidth(statusRect), NSHeight(statusRect), [statusWindow gState], NSMinX(statusRect), [focusView isFlipped] ? NSMaxY(statusRect) : NSMinY(statusRect), NSCompositeSourceOver);

    if (lockedFocus)
        [focusView unlockFocus];
}

- (void)windowDidFlush:(NSWindow *)window;
{
    NSView *focusView;
    BOOL lockedFocus;

    if (!flags.shouldDraw)
        return;

    focusView = [NSView focusView];
    if (!focusView) {
        focusView = [window contentView];
        [focusView lockFocus];
        lockedFocus = YES;
    } else
        lockedFocus = NO;

    PScomposite(0, 0, NSWidth(statusRect), NSHeight(statusRect), [bufferWindow gState], NSMinX(statusRect), [focusView isFlipped] ? NSMaxY(statusRect) : NSMinY(statusRect), NSCompositeSourceOver);

    if (lockedFocus)
        [focusView unlockFocus];
}

@end


@implementation OAStatusDisplayer (Private)

- (void)updateWindows;
{
    NSRect bounds;

    if (!shouldShowStatusView)
        return;

    bounds = [statusView bounds];
    [statusWindow setContentSize:bounds.size];
    [bufferWindow setContentSize:bounds.size];
    // When the content size changes, the view's frame shifts--e.g., the first resize from a height of 16.0 to a height 22.0 results in frame.origin.y becoming 6.0 (22.0 - 16.0).  We don't want that, so here we reset the frame origin back to zero.
    [statusView setFrameOrigin:NSZeroPoint];
    [statusView display];

    [[viewToDisplayOver window] queueSelectorOnce:@selector(flushWindow)];
}

@end
