// 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.

#import <OWF/OWProcessorDescription.h>

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

#import <OWF/OWContentType.h>

RCS_ID("$Header: /Network/Source/CVS/OmniGroup/Frameworks/OWF/Processors.subproj/OWProcessorDescription.m,v 1.5 2002/03/09 01:53:52 kc Exp $")


static NSLock *registrationLock = nil;
static NSMutableDictionary *descriptionByName = nil;
static NSMutableArray      *allDescriptions;

@interface OWProcessorDescription (PrivateAPI)
- (id) _initWithProcessorClassName: (NSString *) name;
@end

@implementation OWProcessorDescription

+ (void) initialize;
{
    OBINITIALIZE;
    
    registrationLock = [[NSLock alloc] init];
    descriptionByName = [[NSMutableDictionary alloc] init];
    allDescriptions = [[NSMutableArray alloc] init];
}

+ (OWProcessorDescription *) processorDescriptionForProcessorClassName: (NSString *) className;
{
    OWProcessorDescription *aDescription;
    
    [registrationLock lock];
    aDescription = [descriptionByName objectForKey: className];
    if (!aDescription) {
        aDescription = [[self alloc] _initWithProcessorClassName: className];
        [descriptionByName setObject: aDescription forKey: className];
        [allDescriptions addObject: aDescription];
        [aDescription release];
    }
    [registrationLock unlock];

    return aDescription;
}

/*" Returns a new autoreleased processor description that is not registered in the cache queried by +processorDescriptionForProcessorClassName:.  This is necessary for implementing processors where one class has multiple pieces of functionality and wants to report them seperately and register them in code, rather than through the Info plist in the processor bundle.  A good example of this is the Netscape plugin support in OmniWeb.  One ObjC class represents all of the Netscape plugins, but we want a different plugin description for each Netscape plugin so that JavaScript can report each Netscape plugin on its own. "*/
+ (OWProcessorDescription *) createUnregisteredProcessorDescriptionForProcessorClassName: (NSString *) className;
{
    OWProcessorDescription *aDescription;

    aDescription = [[self alloc] _initWithProcessorClassName: className];
    [registrationLock lock];
    [allDescriptions addObject: aDescription];
    [registrationLock unlock];
    
    return [aDescription autorelease];
}

+ (NSArray *) processorDescriptions;
{
    NSArray *processorDescriptions;
    
    [registrationLock lock];
    processorDescriptions = [[NSArray alloc] initWithArray: allDescriptions];
    [registrationLock unlock];
    
    return [processorDescriptions autorelease];
}

- init;
{
    [self doesNotRecognizeSelector:_cmd];
    return nil;
}

- (void) dealloc;
{
    [processorClassName release];
    [bundlePath release];
    [sourceContentTypes release];
    [description release];
    [name release];
    [super dealloc];
}

- (NSString *) processorClassName;
{
    return processorClassName;
}

- (NSArray *) sourceContentTypes;
{
    return sourceContentTypes;
}

- (Class) processorClass;
{
    if (!processorClass)
        processorClass = [OFBundledClass classNamed: processorClassName];
    return processorClass;
}

- (NSString *) bundlePath;
{
    return bundlePath;
}

- (void) setBundlePath: (NSString *) aPath;
{
    [bundlePath autorelease];
    bundlePath = [aPath copy];
}

- (NSString *) name;
{
    return name;
}

- (void) setName: (NSString *) aName;
{
    [name autorelease];
    name = [aName copy];
}

- (NSString *) description;
{
    return description;
}

- (void) setDescription: (NSString *) aDescription;
{
    [description autorelease];
    description = [aDescription copy];
}


- (void) registerProcessesContentType: (OWContentType *) sourceContentType toContentType:(OWContentType *)resultContentType cost:(float)cost;
{
    [sourceContentTypes addObject: sourceContentType];
    [sourceContentType linkToContentType:resultContentType usingProcessorDescription:self cost:cost];
}

// OFBundleRegistryTarget informal protocol

+ (void)registerItemName:(NSString *)itemName bundle:(NSBundle *)bundle description:(NSDictionary *)descriptionDict;
{
    NSEnumerator *conversionEnumerator;
    NSDictionary *conversionDictionary;
    OWProcessorDescription *processorDescription;
    NSString *descriptionString, *nameString;
    
    [OFBundledClass createBundledClassWithName:itemName bundle:bundle description:descriptionDict];

    processorDescription = [self processorDescriptionForProcessorClassName: itemName];
    [processorDescription setBundlePath: [bundle bundlePath]];

    descriptionString = [descriptionDict objectForKey: @"description"];
    if (descriptionString)
        [processorDescription setDescription: descriptionString];
    
    nameString = [descriptionDict objectForKey: @"name"];
    if (nameString)
        [processorDescription setName: nameString];
    
    conversionEnumerator = [[descriptionDict objectForKey:@"converts"] objectEnumerator];
    while ((conversionDictionary = [conversionEnumerator nextObject])) {
	OWContentType *inputType, *outputType;
	NSString *aCostObject;
	float aCost;

	inputType = [OWContentType contentTypeForString:[conversionDictionary objectForKey:@"input"]];
	outputType = [OWContentType contentTypeForString:[conversionDictionary objectForKey:@"output"]];
	aCostObject = [conversionDictionary objectForKey:@"cost"];
	aCost = aCostObject ? [aCostObject floatValue] : 1.0;
        
        [processorDescription registerProcessesContentType: inputType toContentType: outputType cost: aCost];
    }
}

// Debugging

- (NSMutableDictionary *) debugDictionary;
{
    NSMutableDictionary *dict;
    
    dict = [super debugDictionary];
    [dict setObject: processorClassName forKey: @"processorClassName"];
    [dict setObject: sourceContentTypes forKey: @"sourceContentTypes"];
    if (bundlePath)
        [dict setObject: bundlePath forKey: @"bundlePath"];
    if (description)
        [dict setObject: description forKey: @"description"];
    if (name)
        [dict setObject: name forKey: @"name"];
    
    return dict;
}


@end


@implementation OWProcessorDescription (PrivateAPI)

- (id) _initWithProcessorClassName: (NSString *) className;
{
    processorClassName = [className copy];
    description = [processorClassName retain];
    name = [processorClassName retain];
    sourceContentTypes = [[NSMutableArray alloc] init];
    bundlePath = [[[NSBundle mainBundle] bundlePath] retain];
    
    return self;
}

@end


