#import "OIDocument.h"

#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#import <OmniBase/OmniBase.h>
#import <OmniFoundation/OmniFoundation.h>
#import <OmniAppKit/OmniAppKit.h>
#import <OWF/OWF.h>
#import <OIF/OIF.h>

RCS_ID("$Header: /Network/Developer/Source/CVS/OmniGroup/OmniImage/OIDocument.m,v 1.4 1998/04/04 03:21:07 bungi Exp $")

@interface OIDocument (Private)
// OIObserver protocol helpers
- (void)mainThreadImageDidSize;
- (void)mainThreadImageDidUpdate;
- (void)mainThreadImageDidAbort;
// Image sizing
- (void)setImageSize:(NSSize)newSize;
- (void)resizeWindowToSuggestedContentSize:(NSSize)suggestedContentSize;
@end

@implementation OIDocument

NSString *OIViewTaskHeaderName = @"Images";

#define ARROW_MOVE_AMOUNT 10

// Init and dealloc

- (void)dealloc;
{
    [OWPipeline cancelTarget:self];
    [omniImage removeObserver:self];
    [omniImage release];

    [super dealloc];
}


// Actions

- (IBAction)reload:(id)sender;
{
    OWPipeline *pipeline;

    pipeline = [OWPipeline currentPipelineForTarget:self];
    [pipeline deepFlushContentCache];
    [pipeline refetchContentFromLastAddress];
}

- (IBAction)printDocument:(id)sender;
{
    [imageView print:sender];
}

- (IBAction)zoomToOriginalSize:(id)sender;
{
    [self resizeWindowToSuggestedContentSize:imageSize];
}

- (IBAction)zoomToMaximumSize:(id)sender;
{
    [self resizeWindowToSuggestedContentSize:NSMakeSize(1e5, 1e5)];
}


// OWTarget protocol

- (OWContentType *)targetContentType;
{
    return [OIImage contentType];
}

- (OWTargetContentDisposition)pipeline:(OWPipeline *)aPipeline hasContent:(id <OWContent>)someContent;
{
    omniImage = [(OIImage *)someContent retain];
    [omniImage addObserver:self];
    if ([omniImage hasSize])
        [self mainThreadPerformSelectorOnce:@selector(mainThreadImageDidSize)];
    if ([omniImage image])
        [self mainThreadPerformSelectorOnce:@selector(mainThreadImageDidUpdate)];
    return OWTargetContentDisposition_ContentAccepted;
}

- (NSString *)targetTypeFormatString;
{
    return @"%@ Document"; // "Image Document"
}

- (OWContentInfo *)parentContentInfo;
{
    return [OWContentInfo headerContentInfoWithName:OIViewTaskHeaderName];
}


// OWOptionalTarget protocol

- (OWTargetContentDisposition)pipeline:(OWPipeline *)aPipeline hasAlternateContent:(id <OWContent>)someContent;
{
    NSLog(@"Cannot display content of type %@", [[someContent contentType] shortDescription]);
    return OWTargetContentDisposition_ContentRejectedCancelPipeline;
}

- (OWTargetContentDisposition)pipeline:(OWPipeline *)aPipeline hasErrorContent:(id <OWContent>)someContent;
{
    NSLog(@"Error displaying %@ (errorContent=%@)", [(OWAddress *)[aPipeline lastAddress] shortDescription], someContent);
    return OWTargetContentDisposition_ContentRejectedCancelPipeline;
}


// OIObserver protocol

- (void)imageDidSize:(OIImage *)anOmniImage;
{
    [self mainThreadPerformSelectorOnce:@selector(mainThreadImageDidSize)];
}

- (void)imageDidUpdate:(OIImage *)anOmniImage;
{
    [self mainThreadPerformSelectorOnce:@selector(mainThreadImageDidUpdate)];
}

- (void)imageDidAbort:(OIImage *)anOmniImage;
{
    [self mainThreadPerformSelectorOnce:@selector(mainThreadImageDidAbort)];
}


// Window delegate

- (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize;
{
    NSRect frameRect;
    NSRect newImageRect;
    double scale;
    NSSize lastImageSize;

    lastImageSize = [imageView bounds].size;

    newImageRect = [NSWindow contentRectForFrameRect:NSMakeRect(0.0, 0.0, frameSize.width, frameSize.height) styleMask:NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask];

    if (ABS(NSWidth(newImageRect) - lastImageSize.width) > ABS(NSHeight(newImageRect) - lastImageSize.height)) {
	scale = NSWidth(newImageRect) / imageSize.width;
    } else {
	scale = NSHeight(newImageRect) / imageSize.height;
    }
 
    newImageRect = NSMakeRect(0, 0, rint(imageSize.width * scale), rint(imageSize.height * scale));

    frameRect = [NSWindow frameRectForContentRect:newImageRect styleMask:NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask];

    return frameRect.size;
}

- (void)windowWillClose:(NSNotification *)notification;
{
    [omniImage removeObserver:self];
    [omniImage release];
    omniImage = nil;
    window = nil;
}

@end


@implementation OIDocument (SubclassesOnly)

+ (NSString *)fileExtension;
{
    return @"tiff";
}

- (BOOL)writeToPath:(NSString *)aPath;
{
    return NO;
}

- (BOOL)readFromPath:(NSString *)aPath;
{
    OWPipeline *pipeline;

    pipeline = [[OWPipeline alloc] initWithContent:[OWAddress addressWithFilename:aPath] target:self];
    [pipeline startProcessingContent];
    [pipeline release];

    return YES;
}

@end


@implementation OIDocument (Private)

// OIObserver protocol helpers

- (void)mainThreadImageDidSize;
{
    [self setImageSize: [omniImage size]];
}

- (void)mainThreadImageDidUpdate;
{
    NSImage *newImage;

    newImage = [omniImage image];
    [newImage setDataRetained:YES];
    [imageView setImage:newImage];
    [imageView setNeedsDisplay:YES];

    [self setImageSize: [omniImage size]];
}

- (void)mainThreadImageDidAbort;
{
    [imageView setNeedsDisplay:YES];
}


// Image sizing

- (void)setImageSize:(NSSize)newSize;
{
    if (imageSize.height == newSize.height && imageSize.width == newSize.width)
        return;

    imageSize = newSize;
    [self resizeWindowToSuggestedContentSize:imageSize];
   
    [imageView setNeedsDisplay:YES];
}

- (void)resizeWindowToSuggestedContentSize:(NSSize)suggestedContentSize;
{
    NSScreen *screen;
    NSRect screenFrame, originalWindowFrame, suggestedWindowFrame;
    unsigned int styleMask;

    styleMask = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask;

    screen = [window screen];
    screenFrame = [screen frame];

    // Step 1: determine how big the window can be and still fit on screen
    suggestedWindowFrame = [NSWindow frameRectForContentRect:NSMakeRect(0.0, 0.0, suggestedContentSize.width, suggestedContentSize.height) styleMask:styleMask];
    
    if (suggestedWindowFrame.size.width > screenFrame.size.width || suggestedWindowFrame.size.height > screenFrame.size.height) {
        NSSize limitedFrameSize;
        NSRect limitedImageRect;
        double widthBasedScale, heightBasedScale, scale;

        limitedFrameSize = NSMakeSize(MIN(suggestedWindowFrame.size.width, screenFrame.size.width), MIN(suggestedWindowFrame.size.height, screenFrame.size.height));
        limitedImageRect = [NSWindow contentRectForFrameRect:NSMakeRect(0.0, 0.0, limitedFrameSize.width, limitedFrameSize.height) styleMask:styleMask];

        widthBasedScale = NSWidth(limitedImageRect) / imageSize.width;
        heightBasedScale = NSHeight(limitedImageRect) / imageSize.height;
        scale = MIN(widthBasedScale, heightBasedScale);

        suggestedWindowFrame = [NSWindow frameRectForContentRect:NSMakeRect(0.0, 0.0, rint(imageSize.width * scale), rint(imageSize.height * scale)) styleMask:styleMask];
    }

    // Step 2: place the window with the same upper-left corner if it's not too big
    originalWindowFrame = [window frame];
    
    suggestedWindowFrame.origin = NSMakePoint(NSMinX(originalWindowFrame), MAX(NSMaxY(originalWindowFrame) - NSHeight(suggestedWindowFrame), NSMinY(screenFrame)));
    [window setFrame:suggestedWindowFrame display:YES];
}

@end
