// Copyright 1997-2000 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 "OHAppletCell.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 "OHHTMLDocument.h"
#import "OHHTMLView.h"

RCS_ID("$Header: /Network/Source/CVS/OmniGroup/Frameworks/OmniHTML/Cells.subproj/OHAppletCell.m,v 1.17 2000/01/29 00:57:08 toon Exp $")

@interface OHAppletCell (Private)
- (NSImage *)statusImage;
- (NSSize)sizeOfStatusImage:(NSImage *)statusImage;
- (void)drawStatusImage:(NSImage *)statusImage withFrame:(NSRect)contentFrame inView:(NSView *)controlView;
@end

@implementation OHAppletCell

static OWContentType *appletContentType;
static NSImage *appletImage;
static NSImage *appletErrorImage;
static OFUserDefaults *defaults;

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

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

    bundle = [NSBundle bundleForClass:self];

    appletContentType = [OWContentType contentTypeForString:@"Omni/Applet"];
    appletImage = [[NSImage alloc] initWithContentsOfFile:[bundle pathForResource:@"OHApplet" ofType:@"tiff"]];
    [appletImage setDataRetained:YES];
    [appletImage setScalesWhenResized:YES];
    appletErrorImage = [[NSImage alloc] initWithContentsOfFile:[bundle pathForResource:@"OHAppletError" ofType:@"tiff"]];
    [appletErrorImage setDataRetained:YES];
    [appletErrorImage setScalesWhenResized:YES];
    defaults = [OFUserDefaults sharedUserDefaults];
}

// Init and dealloc

- initWithCode:(NSString *)aClassName codeBaseAddress:(OWAddress *)anAddress referringAddress:(OWAddress *)aReferringAddress htmlDocument:(OHHTMLDocument *)aDocument;
{
    OWWebPipeline *appletPipeline;

    if (![super init])
        return nil;

    nonretainedHTMLDocument = aDocument;
    codeBaseAddress = [anAddress retain];
    if (![aClassName hasSuffix:@".class"])
        aClassName = [aClassName stringByAppendingString:@".class"];
    appletClassName = [aClassName retain];
    status = OHAppletStatusUnloaded;
    cellName = nil;

    appletPipeline = [[OWWebPipeline alloc] initWithContent:[codeBaseAddress addressForRelativeString:appletClassName] target:self useCachedErrorContent:YES];
    [appletPipeline setReferringAddress:aReferringAddress];
    [appletPipeline release];

    return self;
}

- (void)dealloc;
{    
    [OWPipeline cancelTarget:self];
    [appletController nullifyAppletCell];
    [appletClassName release];
    [codeBaseAddress release];
    [parameters release];
    [appletController release];
    [cellName release];
    [super dealloc];
}

//

- (void)addParameter:(NSString *)name value:(NSString *)value;
{
    if (!parameters)
	parameters = [[NSMutableDictionary alloc] init];
    if (value)
        [parameters setObject:value forKey:name];
}

- (void)addParameterDictionary:(NSDictionary *)dictionary;
{
    [parameters addEntriesFromDictionary:dictionary];
}

//

- (OWAddress *)codeBaseAddress;
{
    return codeBaseAddress;
}

- (OHHTMLDocument *)document;
{
    return nonretainedHTMLDocument;
}

- (NSDictionary *)parameters;
{
    return parameters;
}

- (NSString *)name
{
    return cellName;
}

- (void)setName:(NSString *)appletName
{
    [appletName retain];
    [cellName release];
    cellName = appletName;
}

//

- (id <OHAppletController>)appletController;
{
    return appletController;
}

// Actions

- (IBAction)start:(id)sender;
{
    OWWebPipeline *appletPipeline;

    switch (status) {
        case OHAppletStatusUnloaded:
            appletPipeline = (OWWebPipeline *)[OWPipeline currentPipelineForTarget:self];
            [appletPipeline setContextObject:parameters forKey:@"AppletParameters"];
            [appletPipeline fetch];
            status = OHAppletStatusLoading;
            break;
        case OHAppletStatusReady:
        case OHAppletStatusStopped:
            status = OHAppletStatusRunning;
            [appletController start];
            break;
        default:
            return;
    }
    [self queueSelector:@selector(relayoutCell)];
}

- (IBAction)stop:(id)sender;
{
    if (status != OHAppletStatusRunning)
        return;
    [appletController stop];
    status = OHAppletStatusStopped;
}

// OHBasicCell subclass

- (NSSize)naturalSize;
{
    NSImage *statusImage;

    statusImage = [self statusImage];
    if (statusImage)
        return [self sizeOfStatusImage:statusImage];
    else
        return [super naturalSize];
}

- (void)drawRect:(NSRect)drawRect inHTMLView:(OHHTMLView *)htmlView;
{
    NSImage *statusImage;
    NSRect contentFrame;

    statusImage = [self statusImage];
    contentFrame = [self contentFrame];
    if (statusImage) {
        [self drawStatusImage:statusImage withFrame:contentFrame inView:htmlView];
    } else {
        [super drawRect:contentFrame inHTMLView:htmlView];
    }
}

- (void)resetContentViewSize;
{
    if (![self statusImage])
        [super resetContentViewSize];
}

- (BOOL)wantsToTrackMouse;
{
    return YES;
}

- (BOOL)trackMouse:(NSEvent *)event inHTMLView:(OHHTMLView *)htmlView;
{
    if (!appletController)
        [self start:nil];
    return YES;
}

- (BOOL)wantsLinkCursor;
{
    return YES;
}

// OHViewCell subclass

- (void)setupContentView;
{
    [self setContentView:[appletController view]];
}

// OWTarget protocol

- (OWContentType *)targetContentType;
{
    return appletContentType;
}

- (OWTargetContentDisposition)pipeline:(OWPipeline *)aPipeline hasContent:(id <OWContent>)content;
{
    appletController = [content retain];
    status = OHAppletStatusReady;
    return OWTargetContentDisposition_ContentAccepted;
}

- (NSString *)targetTypeFormatString;
{
    return @"%@ Applet";
}

- (OWContentInfo *)parentContentInfo;
{
    return [nonretainedHTMLDocument contentInfo];
}

// OWOptionalTarget protocol

- (OWTargetContentDisposition)pipeline:(OWPipeline *)aPipeline hasAlternateContent:(id <OWContent>)someContent;
{
    if ([someContent isKindOfClass:[OWDataStream class]] && [(OWDataStream *)someContent resetContentTypeAndEncoding]) {
        // OK, we've reset the content type and encoding, let's try again
        [aPipeline addContent:someContent];
        [aPipeline startProcessingContent];
        return OWTargetContentDisposition_ContentUpdatedOrTargetChanged;
    } else {
        return OWTargetContentDisposition_ContentRejectedSavePipeline;
    }
}

- (void)pipelineDidEnd:(OWPipeline *)aPipeline;
{
    switch (status) {
        case OHAppletStatusReady:
            // OK, start that app
            [self queueSelector:@selector(start:)];
            break;
        case OHAppletStatusLoading:
            // The load failed
            status = OHAppletStatusError;
            [self queueSelector:@selector(redisplayCell)];
            break;
        default:
            // This isn't really expected, but if it does happen:  do nothing.
            break;
    }
}

// Debugging

- (NSMutableDictionary *)debugDictionary;
{
    NSMutableDictionary *debugDictionary;

    debugDictionary = [super debugDictionary];

    if (appletClassName)
        [debugDictionary setObject:appletClassName forKey:@"appletClassName"];
    if (codeBaseAddress)
        [debugDictionary setObject:codeBaseAddress forKey:@"codeBaseAddress"];
    if (parameters)
        [debugDictionary setObject:parameters forKey:@"parameters"];

    if (appletController)
        [debugDictionary setObject:appletController forKey:@"appletController"];

    return debugDictionary;
}

@end

@implementation OHAppletCell (Private)

- (NSImage *)statusImage;
{
    switch (status) {
        default:
        case OHAppletStatusUnloaded:
        case OHAppletStatusLoading:
            // TODO: Should probably have more status images
        case OHAppletStatusReady:
        case OHAppletStatusStopped:
            return appletImage;

        case OHAppletStatusRunning:
            if ([self hasContentView])
                return nil;
            [self setupContentView];
            if ([self hasContentView])
                return nil;

            status = OHAppletStatusError;
            // NO BREAK
        case OHAppletStatusError:
            return appletErrorImage;
    }
}

- (NSSize)sizeOfStatusImage:(NSImage *)statusImage;
{
    return [statusImage size];
}

- (void)drawStatusImage:(NSImage *)statusImage withFrame:(NSRect)contentFrame inView:(NSView *)controlView;
{
    NSSize imageSize;
    float scale;
    NSRect frameRect, drawRect;

    [[NSColor blackColor] set];
    frameRect = contentFrame;
    frameRect.size.height -= 1.0;
    frameRect.size.width -= 1.0;
    NSFrameRectWithWidth(frameRect, 0.0);
    
    drawRect = NSInsetRect(contentFrame, 1.0, 1.0);
    
    imageSize = [statusImage size];
    scale = MIN(MIN(NSWidth(drawRect) / imageSize.width, NSHeight(drawRect) / imageSize.height), 1.0);
    
    [statusImage setSize:NSMakeSize(floor(imageSize.width * scale), floor(imageSize.height * scale))];

    [statusImage compositeToPoint:NSMakePoint(NSMinX(drawRect), NSMaxY(drawRect)) operation:NSCompositeSourceOver];

    [statusImage setSize:imageSize];
}

@end
