// Copyright 1997-2002 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.
//
// $Header: /Network/Source/CVS/OmniGroup/Frameworks/OWF/Pipelines.subproj/OWPipeline.h,v 1.35 2002/03/09 01:53:51 kc Exp $

#import <OWF/OWTask.h>

@class NSArray, NSCountedSet, NSConditionLock, NSLock, NSMutableArray, NSMutableDictionary, NSMutableSet, NSNotificationCenter;
@class OWContentCache, OWContentInfo, OWHeaderDictionary, OWProcessor, OWPipelineCoordinator, OWURL;

#import <Foundation/NSObject.h>	// For NSCopying

#import <OmniFoundation/OFWeakRetainConcreteImplementation.h>
#import <OWF/OWAddressProtocol.h>
#import <OWF/OWContentProtocol.h>
#import <OWF/OWTargetProtocol.h>

@interface OWPipeline : OWTask <OFWeakRetain, NSCopying>
{
    OFWeakRetainConcreteImplementation_IVARS;

    id <OWTarget, OFWeakRetain, NSObject> target;
    NSLock *targetLock;
    
    id <OWContent> _lastContent;
    NSLock *_lastContentLock;
    id <OWAddress> lastAddress;

    NSMutableDictionary *context;
    NSLock *contextLock;
    OWHeaderDictionary *headerDictionary;
    OWURL *headerURL;

    OWProcessor *firstProcessor;
    NSMutableArray *processorArray;
    NSMutableArray *unstartedProcessors;
    NSConditionLock *processorArrayConditionLock;

    OWContentType *targetContentType;
    OWContentType *lastContentType;
    NSMutableSet *processedContentTypes;
    struct {
        unsigned int contentError:1;
        unsigned int everHadContentError:1;
        unsigned int disableContentCache:1;
        unsigned int useCachedErrorContent:1;
        unsigned int processingError:1;
        unsigned int delayedForError:1;
    } flags;
    OWContentCache *contentCacheForLastAddress;
    unsigned int addedContentCount;

    OWPipelineCoordinator *pipelineCoordinator;
    NSString *targetTypeFormatString;
    int maximumWorkToBeDone;

    NSString *errorNameString;
    NSString *errorReasonString;
}

// For notification of pipeline errors
+ (NSNotificationCenter *)pipelineErrorNotificationCenter;

// For notification of pipeline fetches
+ (void)addObserver:(id)anObserver selector:(SEL)aSelector address:(id <OWAddress>)anAddress;
- (void)addObserver:(id)anObserver selector:(SEL)aSelector;
+ (void)removeObserver:(id)anObserver address:(id <OWAddress>)anAddress;
+ (void)removeObserver:(id)anObserver;

// Pipeline target management
+ (void)invalidatePipelinesForTarget:(id <OWTarget>)aTarget;
    // Targets call this when they are freed so no pipeline tries to give them content.
+ (void)abortTreeActivityForTarget:(id <OWTarget>)aTarget;
    // Usually called because of user input
+ (void)abortPipelinesForTarget:(id <OWTarget>)aTarget;
    // Only affects the current pipelines for the target, not the their children
    // You probably want to use +abortTreeActivityForTarget: instead.
+ (OWPipeline *)currentPipelineForTarget:(id <OWTarget>)aTarget;
    // Last pipeline that the target accepted content from, in -pipelineBuilt.
+ (NSArray *)pipelinesForTarget:(id <OWTarget>)aTarget;
+ (OWPipeline *)firstActivePipelineForTarget:(id <OWTarget>)aTarget;
+ (OWPipeline *)lastActivePipelineForTarget:(id <OWTarget>)aTarget;

// Status Monitoring
+ (void)activeTreeHasChanged;
+ (void)startActiveStatusUpdateTimer;
+ (void)stopActiveStatusUpdateTimer;

// Init and dealloc
+ (void)startPipelineWithContent:(id <OWContent>)aContent target:(id <OWTarget, OWTarget, OFWeakRetain, NSObject>)aTarget;

- initWithContent:(id <OWContent>)aContent target:(id <OWTarget, OFWeakRetain, NSObject>)aTarget useCachedErrorContent:(BOOL)useError;
- initWithContent:(id <OWContent>)aContent target:(id <OWTarget, OFWeakRetain, NSObject>)aTarget;

// Pipeline management
- (void)startProcessingContent;
- (void)abortTask;

- (void)fetch;
- (BOOL)canRefetchContentFromLastAddress;
    // Returns YES if the pipeline's state allows -refetchContentFromLastAddress.
- (void)refetchContentFromLastAddress;
- (void)refetchContentFromLastAddressOrSource:(BOOL)useSource;

// Target
- (id <OWTarget, OFWeakRetain, NSObject>)target;
- (void)setTarget:(id <OWTarget, OFWeakRetain, NSObject>)newTarget;
    // Don't use this to setTarget to nil or you get an exception.  Sets parentContentInfo.
- (void)invalidate;
    // Called in +invalidatePipelinesForTarget:, if the pipeline was pointing at the target that wants to be invalidated.
    // Also called in -pipelineBuilt if our target rejects the content we offer and didn't suggest a new target, and in +_target:acceptedContentFromPipeline: on all pipelines created before the parameter that point at the same target (eg, some other pipeline beat you to the punch, sorry, guys).
- (void)parentContentInfoLostContent;
    // When our parent content info's content calls [OWContentInfo nullfiyContent], this method will be called on all of the contentInfo's childTasks.  We call the same method on our target if it implements it.  This is currently unused.
- (void)updateStatusOnTarget;

// Content
- (id <OWContent>)lastContent;
- (OWContentType *)lastContentType;
- (OWContentCache *)contentCacheForLastAddress;

- (void)addContent:(id <OWContent>)newContent;
- (void)contentError;
- (void)disableContentCache;
- (void)cacheContent;
- (void)permanentRedirection:(id <OWAddress>)redirectTo;
- (void)flushContentCache;

- (id)contextObjectForKey:(NSString *)key;
- (void)setContextObject:(id)anObject forKey:(NSString *)key;
    // returns the object that's in the context dictionary, whichever one it turns out to be
- (id)setContextObjectNoReplace:(id)anObject forKey:(NSString *)key;
- (NSDictionary *)contextDictionary;

- (OWHeaderDictionary *)headerDictionary;
- (void)setHeaderDictionary:(OWHeaderDictionary *)newHeaderDictionary fromURL:(OWURL *)newHeaderURL;
- (void)addHeader:(NSString *)headerName value:(NSString *)headerValue;

// Processors call these methods

- (OWProcessor *)firstProcessor;
- (void)addProcessor:(OWProcessor *)aProcessor;
- (void)removeProcessor:(OWProcessor *)aProcessor; // subclasses only
- (void)processorDidRetire:(OWProcessor *)aProcessor;
- (void)processorStatusChanged:(OWProcessor *)aProcessor;
- (void)processor:(OWProcessor *)aProcessor hasErrorName:(NSString *)name;
- (void)processor:(OWProcessor *)aProcessor hasErrorName:(NSString *)name reason:(NSString *)reason;

OFWeakRetainConcreteImplementation_INTERFACE

@end

@interface OWPipeline (SubclassesOnly)

- (void)deactivate;
- (void)setLastAddress:(id <OWAddress>)newLastAddress;

// This is called by the OWPipelineCoordinator
- (void)_buildPipe;

@end

#import <OWF/FrameworkDefines.h>

OWF_EXTERN NSString *OWPipelineHasErrorNotificationName;
OWF_EXTERN NSString *OWPipelineWillDeallocateNotificationName;
OWF_EXTERN NSString *OWPipelineHasErrorNotificationPipelineKey;
OWF_EXTERN NSString *OWPipelineHasErrorNotificationProcessorKey;
OWF_EXTERN NSString *OWPipelineHasErrorNotificationErrorNameKey;
OWF_EXTERN NSString *OWPipelineHasErrorNotificationErrorReasonKey;

OWF_EXTERN NSString *OWPipelineTreeActivationNotificationName;
OWF_EXTERN NSString *OWPipelineTreeDeactivationNotificationName;
OWF_EXTERN NSString *OWPipelineTreePeriodicUpdateNotificationName;
