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

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

#import "NSDate-OWExtensions.h"
#import "OWAddress.h"
#import "OWContentCache.h"
#import "OWContentInfo.h"
#import "OWCookie.h"
#import "OWHeaderDictionary.h"
#import "OWURL.h"

RCS_ID("$Header: /Network/Source/CVS/OmniGroup/Frameworks/OWF/Pipelines.subproj/OWWebPipeline.m,v 1.14 1999/09/27 23:34:15 kc Exp $")

@interface OWWebPipeline (Private)
- (void)postProcessHeaders;
- (void)processRefreshHeader:(NSString *)refresh;
- (void)processExpiresHeader:(NSString *)expires;
@end

@implementation OWWebPipeline

static NSCharacterSet *TokenSet;
static OFScheduler *refreshScheduler;

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

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

    refreshScheduler = [[[OFScheduler mainScheduler] subscheduler] retain];
    TokenSet = [[[NSCharacterSet characterSetWithCharactersInString:@";"] invertedSet] retain];
}

- initWithContent:(id <OWContent>)aContent target:(id <OWTarget>)aTarget useCachedErrorContent:(BOOL)useError;
{
    if (![super initWithContent:aContent target:aTarget useCachedErrorContent:useError])
        return nil;

    webPipelineFlags.proxyCacheDisabled = NO;
    historyAction = OWWebPipelineForwardHistoryAction;
    if (parentContentInfo)
        [self setReferringContentInfo:parentContentInfo];
    
    return self;
}

- (void)dealloc;
{
    [referringContentInfo release];
    [referringAddress release];
    [super dealloc];
}

- (id <OWAddress>)referringAddress;
{
    return referringAddress;
}

- (void)setReferringAddress:(id <OWAddress>)anAddress;
{
    id <OWAddress> oldReferringAddress;

    if (referringAddress == anAddress)
        return;

    oldReferringAddress = referringAddress;
    referringAddress = [anAddress retain];
    [oldReferringAddress release];
}

- (OWContentInfo *)referringContentInfo
{
    return referringContentInfo;
}

- (void)setReferringContentInfo:(OWContentInfo *)anInfo
{
    if (anInfo != referringContentInfo) {
        [anInfo retain];
        [referringContentInfo release];
        referringContentInfo = anInfo;
    }

    [self setReferringAddress:[referringContentInfo address]];
}

- (OWWebPipelineHistoryAction)historyAction;
{
    return historyAction;
}

- (void)setHistoryAction:(OWWebPipelineHistoryAction)newHistoryAction;
{
    historyAction = newHistoryAction;
}

- (BOOL)proxyCacheDisabled;
{
    return webPipelineFlags.proxyCacheDisabled || (lastAddress && [lastAddress isAlwaysUnique]);
}

- (void)setProxyCacheDisabled:(BOOL)newDisabled;
{
    webPipelineFlags.proxyCacheDisabled = newDisabled;
}

// OWPipeline subclass

- (void)deactivate;
{
    [self postProcessHeaders];
    [super deactivate];
}

- (void)refetchContentFromLastAddress;
{
    historyAction = OWWebPipelineReloadHistoryAction;
    [self setProxyCacheDisabled:YES];
    [super refetchContentFromLastAddress];
}


// NSCopying protocol

- copyWithZone:(NSZone *)zone;
{
    OWWebPipeline *newPipeline;

    newPipeline = [super copyWithZone:zone];
    [newPipeline setReferringContentInfo:referringContentInfo];
    [newPipeline setReferringAddress:referringAddress];
    [newPipeline setHistoryAction:OWWebPipelineReloadHistoryAction];
    return newPipeline;
}

@end

@implementation OWWebPipeline (Private)

- (void)postProcessHeaders;
{
    NSString *headerValue;

    if ((headerValue = [headerDictionary lastStringForKey:@"refresh"]))
	[self processRefreshHeader:headerValue];
    if ((headerValue = [headerDictionary lastStringForKey:@"expires"]))
	[self processExpiresHeader:headerValue];
    [OWCookie registerCookiesFromURL:headerURL headerDictionary:headerDictionary];
#warning Should process other headers, e.g. Cache-Control
}

- (void)processRefreshHeader:(NSString *)refresh;
{
    NSString *refreshTimeString, *urlString;
    NSCalendarDate *refreshDate;
    OWURL *refreshURL, *referringURL;
    OWAddress *refreshAddress;
    OWWebPipeline *refreshPipeline;

    if ([refresh containsString:@";"]) {
        NSScanner *scanner;

        refreshTimeString = nil;
        urlString = nil;
        scanner = [[NSScanner alloc] initWithString:refresh];
        [scanner scanCharactersFromSet:TokenSet intoString:&refreshTimeString];
        while ([scanner scanString:@";" intoString:NULL])
            if ([scanner scanString:@"url=" intoString:NULL])
                [scanner scanCharactersFromSet:TokenSet intoString:&urlString];
    } else {
        refreshTimeString = refresh;
        urlString = nil;
    }
    if (!refreshTimeString)
        return;
    refreshDate = [[NSCalendarDate alloc] initWithTimeIntervalSinceNow:[refreshTimeString floatValue]];
    [refreshDate setCalendarFormat:@"%b %d %H:%M:%S"];
    referringURL = [(OWAddress *)lastAddress url];
    refreshURL = referringURL;
    if (urlString) {
        if (refreshURL)
            refreshURL = [refreshURL urlFromRelativeString:urlString];
        else
            refreshURL = [OWURL urlFromString:urlString];
    }
    refreshAddress = [OWAddress addressWithURL:refreshURL];
    refreshPipeline = [[[self class] alloc] initWithContent:refreshAddress target:[self target]];
    [[refreshPipeline contentCacheForLastAddress] flushCachedContent];
    [refreshPipeline setProxyCacheDisabled:YES];
    [refreshPipeline setContextObject:[NSString stringWithFormat:@"Timed Refresh at %@", refreshDate] forKey:@"Status"];
    if (referringURL)
        [refreshPipeline setReferringAddress:[OWAddress addressWithURL:referringURL]];
    [refreshScheduler scheduleSelector:@selector(startProcessingContent) onObject:refreshPipeline withObject:nil atDate:refreshDate];
    [refreshDate autorelease];
    [refreshPipeline release];
}

- (void)processExpiresHeader:(NSString *)expires;
{
    NSDate *expireDate;

    expireDate = [NSDate dateWithHTTPDateString:expires];
    if (!expireDate)
	expireDate = [NSDate dateWithTimeIntervalSinceNow:0];
    [contentCacheForLastAddress expireAtDate:expireDate];
}

@end
