// Copyright 1998-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 "OWScriptBlockTarget.h"
#import <Foundation/Foundation.h>
#import <OmniBase/OmniBase.h>
#import <OmniFoundation/OmniFoundation.h>
#import <OWF/OWF.h>

RCS_ID("$Header: /Network/Source/CVS/OmniGroup/Frameworks/OmniHTML/Scripting.subproj/OWScriptBlockTarget.m,v 1.3 2000/01/20 00:27:56 kc Exp $")

@interface OWScriptBlockTarget (Private)
- (void)_acceptScript:(NSData *)script
             language:(NSString *)lang
              headers:(OWHeaderDictionary *)heads;
- (void)_readDataAndFakeContent:(OWDataStreamCursor *)curs;
@end

@implementation OWScriptBlockTarget

#define NO_RESULT 0
#define HAVE_RESULT 1

- initWithParentContentInfo:(OWContentInfo *)pci
{
    self = [super init];
    if (!self) return nil;

    parentContentInfo = [pci retain];

    resultLock = [[NSConditionLock alloc] initWithCondition:NO_RESULT];

    theScript = nil;
    scriptLanguage = nil;
    scriptHeaders = nil;

    return self;
}

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

    [theScript release];
    [scriptLanguage release];
    [scriptHeaders release];
    [resultLock unlock];
    [resultLock release];
    [parentContentInfo release];
    
    [super dealloc];
}

- (NSData *)result
{
    NSData *res;
    [resultLock lockWhenCondition:HAVE_RESULT];
    res = [theScript retain];
    [resultLock unlock];
    return [res autorelease];
}

- (NSString *)resultLanguage
{
    NSString *res;
    [resultLock lockWhenCondition:HAVE_RESULT];
    res = [scriptLanguage retain];
    [resultLock unlock];
    return [res autorelease];
}

// OWTarget protocol

- (OWContentType *)targetContentType
{
    return [OWContentType contentTypeForString:@"Omni/ScriptBlock"];
}


- (OWTargetContentDisposition)pipeline:(OWPipeline *)aPipeline
                            hasContent:(id <OWContent>)someContent
{
    if (![[someContent contentType] isEqual:[self targetContentType]]) {
        /* Handle misconfigured servers which return scripts as text/plain or whatever */
        if([someContent isKindOfClass:[OWDataStream class]]) {
            NSLog(@"Faking plausible script block content type");
            /* We have to read the data in a different thread, since we're often called in the same thread as OWHTTPProcessor is reading the data, so of course blocking until our caller completes won't work */
            [[OWProcessor processorQueue] queueSelector:@selector(_readDataAndFakeContent:) forObject:self withObject:[(OWDataStream *)someContent newCursor]];
        } else {
            [resultLock lock];
            /* the nil result is our error indication */
            [resultLock unlockWithCondition:HAVE_RESULT];
            [aPipeline processor:nil
                    hasErrorName:@"NotAScript"
                          reason:@"Script source did not return a script"];
            return OWTargetContentDisposition_ContentRejectedCancelPipeline;
        }
    } else {
        NSDictionary *contentDictionary;
        /* all is groovy */
        OBASSERT([someContent isKindOfClass:[OWContentContainer class]]);
        contentDictionary = [(OWContentContainer *)someContent content];
        [self _acceptScript:[contentDictionary objectForKey:@"script"]
                   language:[contentDictionary objectForKey:@"language"]
                    headers:[contentDictionary objectForKey:@"headers"]];
    }

    return OWTargetContentDisposition_ContentAccepted;
}

- (OWTargetContentDisposition)pipeline:(OWPipeline *)aPipeline
                   hasAlternateContent:(id <OWContent>)someContent
{
    return [self pipeline:aPipeline hasContent:someContent];
}

- (OWTargetContentDisposition)pipeline:(OWPipeline *)aPipeline
                       hasErrorContent:(id <OWContent>)someContent
{
    [self _acceptScript:nil
               language:nil
                headers:nil];
    return OWTargetContentDisposition_ContentRejectedCancelPipeline;
}

- (void)pipelineDidEnd:(OWPipeline *)aPipeline;
{
    /* make sure we don't block forever. I don't think this method is actually necessary */
    [resultLock lock];
    /* don't modify our vars, since we might well have actual data */
    /* but allow whoever invoked us to unblock if we did't have data yet */
    [resultLock unlockWithCondition:HAVE_RESULT];
}

- (void)_acceptScript:(NSData *)script
             language:(NSString *)lang
              headers:(OWHeaderDictionary *)heads
{
    [resultLock lock];
    [theScript release];
    theScript = [script retain];
    [scriptLanguage release];
    scriptLanguage = [lang retain];
    [scriptHeaders release];
    scriptHeaders = [heads retain];
    [resultLock unlockWithCondition:HAVE_RESULT];
}

- (void)_readDataAndFakeContent:(OWDataStreamCursor *)curs
{
    NSData *theData;
    /* See comment in -pipeline:hasContent: for the reason for this kludge */

    NS_DURING {
        theData = [curs readAllData];
    } NS_HANDLER {
        // Indicate an error by returning nil data.
        // TODO: something better.
        theData = nil;
    } NS_ENDHANDLER;

    [self _acceptScript:theData language:nil headers:nil];
}

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

- (OWContentInfo *)parentContentInfo;
{
    return parentContentInfo;
}

@end



