// 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 "OHHTMLDisplayProcessor.h"

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

#import "OHAppletCell.h"
#import "OHHTMLDocument.h"
#import "OHObjectCell.h"
#import "OHTextBuilder.h"

RCS_ID("$Header: /Network/Source/CVS/OmniGroup/Frameworks/OmniHTML/Building.subproj/OHHTMLDisplayProcessor-Applet.m,v 1.12 2000/01/29 00:57:07 toon Exp $")

@interface OHHTMLDisplayProcessor (Applet)
- (void)processAppletTag:(OWSGMLTag *)tag;
- (void)processParamTag:(OWSGMLTag *)tag;
@end

@implementation OHHTMLDisplayProcessor (Applet)

static OWSGMLTagType *embedTagType;
static OWSGMLTagType *objectTagType;
static OWSGMLTagType *appletTagType;
static OWSGMLTagType *paramTagType;

static unsigned int embedSrcAttributeIndex;
static unsigned int embedWidthAttributeIndex;
static unsigned int embedHeightAttributeIndex;
static unsigned int embedHSpaceAttributeIndex;
static unsigned int embedVSpaceAttributeIndex;
static unsigned int embedAlignAttributeIndex;
static unsigned int embedHiddenAttributeIndex;
static unsigned int embedTypeAttributeIndex;
static unsigned int objectClassIDAttributeIndex;
static unsigned int objectWidthAttributeIndex;
static unsigned int objectHeightAttributeIndex;
static unsigned int objectHSpaceAttributeIndex;
static unsigned int objectVSpaceAttributeIndex;
static unsigned int objectAlignAttributeIndex;
static unsigned int appletCodebaseAttributeIndex;
static unsigned int appletCodeAttributeIndex;
static unsigned int appletWidthAttributeIndex;
static unsigned int appletHeightAttributeIndex;
static unsigned int appletHSpaceAttributeIndex;
static unsigned int appletVSpaceAttributeIndex;
static unsigned int appletAlignAttributeIndex;
static unsigned int appletNameAttributeIndex;
static unsigned int paramNameAttributeIndex;
static unsigned int paramValueAttributeIndex;

+ (void)didLoad;
{
    OWSGMLDTD *dtd;
    OWSGMLMethods *methods;

    dtd = [self dtd];

    embedTagType = [dtd tagTypeNamed:@"embed"];
    objectTagType = [dtd tagTypeNamed:@"object"];
    appletTagType = [dtd tagTypeNamed:@"applet"];
    paramTagType = [dtd tagTypeNamed:@"param"];


    embedSrcAttributeIndex = [embedTagType addAttributeNamed:@"src"];
    embedWidthAttributeIndex = [embedTagType addAttributeNamed:@"width"];
    embedHeightAttributeIndex = [embedTagType addAttributeNamed:@"height"];
    embedHSpaceAttributeIndex = [embedTagType addAttributeNamed:@"hspace"];
    embedVSpaceAttributeIndex = [embedTagType addAttributeNamed:@"vspace"];
    embedAlignAttributeIndex = [embedTagType addAttributeNamed:@"align"];
    embedHiddenAttributeIndex = [embedTagType addAttributeNamed:@"hidden"];
    embedTypeAttributeIndex = [embedTagType addAttributeNamed:@"type"];

    objectClassIDAttributeIndex = [objectTagType addAttributeNamed:@"classid"];
    objectWidthAttributeIndex = [objectTagType addAttributeNamed:@"width"];
    objectHeightAttributeIndex = [objectTagType addAttributeNamed:@"height"];
    objectHSpaceAttributeIndex = [objectTagType addAttributeNamed:@"hspace"];
    objectVSpaceAttributeIndex = [objectTagType addAttributeNamed:@"vspace"];
    objectAlignAttributeIndex = [objectTagType addAttributeNamed:@"align"];
    appletCodebaseAttributeIndex = [appletTagType addAttributeNamed:@"codebase"];
    appletCodeAttributeIndex = [appletTagType addAttributeNamed:@"code"];
    appletWidthAttributeIndex = [appletTagType addAttributeNamed:@"width"];
    appletHeightAttributeIndex = [appletTagType addAttributeNamed:@"height"];
    appletHSpaceAttributeIndex = [appletTagType addAttributeNamed:@"hspace"];
    appletVSpaceAttributeIndex = [appletTagType addAttributeNamed:@"vspace"];
    appletAlignAttributeIndex = [appletTagType addAttributeNamed:@"align"];
    appletNameAttributeIndex = [appletTagType addAttributeNamed:@"name"];
    paramNameAttributeIndex = [paramTagType addAttributeNamed:@"name"];
    paramValueAttributeIndex = [paramTagType addAttributeNamed:@"value"];

    methods = [self sgmlMethods];

    [methods registerMethod:@"Embed" forTagName:@"embed"];
    [methods registerMethod:@"Object" forTagName:@"object"];
    [methods registerMethod:@"Applet" forTagName:@"applet"];
    [methods registerMethod:@"Param" forTagName:@"param"];
}

- (void)processAppletTag:(OWSGMLTag *)tag;
{
    OWAddress *codeBase;
    NSString *code;
    id <OWSGMLToken> sgmlToken;
    BOOL endTagSeen;

    if ([[OFUserDefaults sharedUserDefaults] boolForKey:@"OHAppletsDisabled"])
        return;

    if (sgmlTagAttributePresentAtIndex(tag, appletCodebaseAttributeIndex)) {
	NSString *string;
	
	string = sgmlTagValueForAttributeAtIndex(tag, appletCodebaseAttributeIndex);
	if ([string characterAtIndex:[string length] - 1] != '/')
	    string = [string stringByAppendingString:@"/"];
	codeBase = [baseAddress addressForRelativeString:string];
    } else
        codeBase = [baseAddress addressForRelativeString:@"./"];
    code = [sgmlTagValueForAttributeAtIndex(tag, appletCodeAttributeIndex) stringByDeletingPathExtension];
    
    OBASSERT(!currentAppletCell);
    currentAppletCell = [[OHAppletCell allocWithZone:[htmlDocument zone]] initWithCode:code codeBaseAddress:codeBase referringAddress:baseAddress htmlDocument:htmlDocument];

    // Size
    [currentAppletCell setRequestedSizeWidthString:sgmlTagValueForAttributeAtIndex(tag, appletWidthAttributeIndex) heightString:sgmlTagValueForAttributeAtIndex(tag, appletHeightAttributeIndex)];
    
    // Inset size
    [currentAppletCell setInsetSizeWidthString:sgmlTagValueForAttributeAtIndex(tag, appletHSpaceAttributeIndex) heightString:sgmlTagValueForAttributeAtIndex(tag, appletVSpaceAttributeIndex) defaultWidth:0.0];

    // Alignment
    [currentAppletCell setAlignmentString:sgmlTagValueForAttributeAtIndex(tag, appletAlignAttributeIndex)];

    // Applet name (used only by JavaScript, as far as I know)
    [currentAppletCell setName:sgmlTagValueForAttributeAtIndex(tag, appletNameAttributeIndex)];
    
    // Ignore contents of <APPLET> tag (except <PARAM> tags)
    endTagSeen = NO;
    while (!endTagSeen && (sgmlToken = [objectCursor readObject])) {
        switch ([sgmlToken tokenType]) {
            case OWSGMLTokenTypeStartTag:
                if ([(OWSGMLTag *)sgmlToken tagType] == paramTagType) {
                    // Process <PARAM> tags
                    [self processParamTag:(OWSGMLTag *)sgmlToken];
                }
                break;
            case OWSGMLTokenTypeEndTag:
                // Exit loop on </APPLET>
                if ([(OWSGMLTag *)sgmlToken tagType] == appletTagType) {
                    endTagSeen = YES;
                    break;
                }
            default:
            case OWSGMLTokenTypeCData:
                break;
        }
    }
    [textBuilder writeNonWhitespaceCellObject:currentAppletCell];
    if ([[OFUserDefaults sharedUserDefaults] boolForKey:@"OHAppletsRunAutomatically"])
        [currentAppletCell start:nil];
    [htmlDocument addApplet:currentAppletCell];
    [currentAppletCell release];
    currentAppletCell = nil;
}

- (void)processObjectTag:(OWSGMLTag *)tag;
{
    id <OWSGMLToken> sgmlToken;
    BOOL endTagSeen;

    OBASSERT(!currentAppletCell);
    currentAppletCell = [[OHObjectCell allocWithZone:[htmlDocument zone]] initWithClassID:sgmlTagValueForAttributeAtIndex(tag, objectClassIDAttributeIndex) baseAddress:baseAddress htmlDocument:htmlDocument];

    // Size
    [currentAppletCell setRequestedSizeWidthString:sgmlTagValueForAttributeAtIndex(tag, objectWidthAttributeIndex) heightString:sgmlTagValueForAttributeAtIndex(tag, objectHeightAttributeIndex)];

    // Inset size
    [currentAppletCell setInsetSizeWidthString:sgmlTagValueForAttributeAtIndex(tag, objectHSpaceAttributeIndex) heightString:sgmlTagValueForAttributeAtIndex(tag, objectVSpaceAttributeIndex) defaultWidth:0.0];

    // Alignment
    [currentAppletCell setAlignmentString:sgmlTagValueForAttributeAtIndex(tag, objectAlignAttributeIndex)];

    // Ignore contents of <OBJECT> tag (except <PARAM> tags)
    endTagSeen = NO;
    while (!endTagSeen && (sgmlToken = [objectCursor readObject])) {
        switch ([sgmlToken tokenType]) {
            case OWSGMLTokenTypeStartTag:
                if ([(OWSGMLTag *)sgmlToken tagType] == paramTagType) {
                    // Process <PARAM> tags
                    [self processParamTag:(OWSGMLTag *)sgmlToken];
                }
                break;
            case OWSGMLTokenTypeEndTag:
                // Exit loop on </OBJECT>
                if ([(OWSGMLTag *)sgmlToken tagType] == objectTagType) {
                    endTagSeen = YES;
                    break;
                }
            default:
            case OWSGMLTokenTypeCData:
                break;
        }
    }
    [textBuilder writeNonWhitespaceCellObject:currentAppletCell];
//    [htmlDocument addApplet:currentAppletCell];???
    [currentAppletCell start:self];
    [currentAppletCell release];
    currentAppletCell = nil;
}

- (void)processEmbedTag:(OWSGMLTag *)tag;
{

    OBASSERT(!currentAppletCell);
    currentAppletCell = [[OHObjectCell allocWithZone:[htmlDocument zone]] initWithClassID:nil baseAddress:baseAddress htmlDocument:htmlDocument];

    // Hidden
    if (sgmlTagAttributePresentAtIndex(tag, embedHiddenAttributeIndex)) {
        [currentAppletCell setRequestedSize:NSMakeSize(1.0,1.0) requestedWidthIsPercentage:NO requestedHeightIsPercentage:NO];
    } else {
        //Size
        [currentAppletCell setRequestedSizeWidthString:sgmlTagValueForAttributeAtIndex(tag, embedWidthAttributeIndex) heightString:sgmlTagValueForAttributeAtIndex(tag, embedHeightAttributeIndex)];

        // Inset size
        [currentAppletCell setInsetSizeWidthString:sgmlTagValueForAttributeAtIndex(tag, embedHSpaceAttributeIndex) heightString:sgmlTagValueForAttributeAtIndex(tag, embedVSpaceAttributeIndex) defaultWidth:0.0];
    }

    // Alignment
    [currentAppletCell setAlignmentString:sgmlTagValueForAttributeAtIndex(tag, embedAlignAttributeIndex)];

    [currentAppletCell addParameterDictionary:[tag attributes]];
    [currentAppletCell addParameter:@"src" value:sgmlTagValueForAttributeAtIndex(tag, embedSrcAttributeIndex)];
    [currentAppletCell addParameter:@"type" value:sgmlTagValueForAttributeAtIndex(tag, embedTypeAttributeIndex)];
    [textBuilder writeNonWhitespaceCellObject:currentAppletCell];
//    [htmlDocument addApplet:currentAppletCell];???
    [currentAppletCell start:self];
    [currentAppletCell release];
    currentAppletCell = nil;
}

- (void)processParamTag:(OWSGMLTag *)tag;
{
    if (!currentAppletCell)
        return;

    [currentAppletCell addParameter:sgmlTagValueForAttributeAtIndex(tag, paramNameAttributeIndex) value:sgmlTagValueForAttributeAtIndex(tag, paramValueAttributeIndex)];
}

@end
