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

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

#import "OWNetLocation.h"
#import "OWURL.h"

RCS_ID("$Header: /Network/Source/CVS/OmniGroup/Frameworks/OWF/Content.subproj/Address.subproj/OWProxyServer.m,v 1.9 1999/03/30 21:26:24 kc Exp $")

@interface OWProxyServer (Private)
+ (void)controllerDidInit:(NSNotification *)notification;
+ (NSArray *)activeProxyServers;
+ (void)activateProxyServer:(OWProxyServer *)aProxyServer;
+ (void)deactivateProxyServer:(OWProxyServer *)aProxyServer;
+ (OWProxyServer *)proxyServerFromDefaultsDictionary:(NSDictionary *)aDictionary;
@end

@implementation OWProxyServer

static NSLock *activeProxyServersLock;
static NSMutableArray *activeProxyServers;
static NSMutableDictionary *nonProxiableSchemes;
static NSObject *dummyValue;

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

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

    activeProxyServersLock = [[NSRecursiveLock alloc] init];
    activeProxyServers = nil;
    nonProxiableSchemes = [[NSMutableDictionary alloc] initWithCapacity:6];
    dummyValue = [[NSObject alloc] init];
}

+ (void)didLoad;
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(controllerDidInit:) name:OFControllerDidInitNotification object:nil];
}

+ (OWURL *)proxyURLForURL:(OWURL *)aURL;
{
    NSArray *proxyServers;
    int proxyIndex, proxyCount;
    OWURL *aProxyURL;

    if (!activeProxyServers)
        return aURL;
    if ([nonProxiableSchemes objectForKey:[aURL scheme]])
        return aURL;
    proxyServers = [self activeProxyServers];
    proxyCount = [proxyServers count];
    aProxyURL = aURL;
    for (proxyIndex = 0; proxyIndex < proxyCount; proxyIndex++) {
	OWProxyServer *proxyServer;

	proxyServer = [proxyServers objectAtIndex:proxyIndex];
	if ([proxyServer isProxyForURL:aURL]) {
	    aProxyURL = [proxyServer proxyURL];
            if (!aProxyURL)
                aProxyURL = aURL;
	    break;
	}
    }
    OBASSERT(aProxyURL != nil);
    return aProxyURL;
}

+ (NSArray *)proxyServersFromDefaults;
{
    NSMutableArray *proxyServers;
    NSEnumerator *serverDictionaryEnumerator;
    NSDictionary *serverDictionary;

    proxyServers = [NSMutableArray arrayWithCapacity:0];

    [activeProxyServersLock lock];
    [activeProxyServers removeAllObjects];

    serverDictionaryEnumerator = [[[OFUserDefaults sharedUserDefaults] arrayForKey:@"OWProxyServers"] objectEnumerator];
    while ((serverDictionary = [serverDictionaryEnumerator nextObject]))
	[proxyServers addObject:[self proxyServerFromDefaultsDictionary:serverDictionary]];
    [activeProxyServersLock unlock];

    return proxyServers;
}

+ (OWProxyServer *)proxyServerWithURL:(OWURL *)aURL;
{
    return [[[self alloc] initWithProxyURL:aURL] autorelease];
}

// Init and dealloc

- initWithProxyURL:(OWURL *)aProxyURL;
{
    if (![super init])
	return nil;

    proxyURL = [aProxyURL retain];
    description = nil;
    schemes = nil;
    destinations = nil;
    active = NO;

    return self;
}

- (void)dealloc;
{
    [proxyURL release];
    [description release];
    [schemes release];
    [destinations release];
    [super dealloc];
}

//

- (OWURL *)proxyURL;
{
    return [[proxyURL retain] autorelease];
}

- (NSString *)description;
{
    return description ? description : [proxyURL compositeString];
}

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

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

- (BOOL)isActive;
{
    return active;
}

//

- (void)setProxyURL:(OWURL *)aProxyURL;
{
    if (proxyURL == aProxyURL)
	return;
    [proxyURL autorelease];
    proxyURL = [aProxyURL retain];
    [self setDescription:nil];
}

- (void)setDescription:(NSString *)aDescription;
{
    OWURL *aProxyURL;

    if (description == aDescription)
        return;
    [description release];
    description = nil;
    aProxyURL = [OWURL urlFromString:aDescription];
    [self setProxyURL:aProxyURL];
    if (!aProxyURL)
        description = [aDescription retain];
}

- (void)setSchemes:(NSArray *)someSchemes;
{
    if (schemes == someSchemes)
	return;
    [schemes autorelease];
    if ([someSchemes count] > 0)
	schemes = [[NSArray alloc] initWithArray:someSchemes];
    else
	schemes = nil;
}

- (void)setDestinations:(NSArray *)someDestinations;
{
    if (destinations == someDestinations)
	return;
    [destinations autorelease];
    if ([someDestinations count] > 0)
	destinations = [[NSArray alloc] initWithArray:someDestinations];
    else
	destinations = nil;
}

//

- (void)activate;
{
    if (active)
	return;
    active = YES;
    [isa activateProxyServer:self];
}

- (void)deactivate;
{
    if (!active)
	return;
    active = NO;
    [isa deactivateProxyServer:self];
}

//

- (BOOL)isProxyForURL:(OWURL *)aURL;
{
    if (!active)
	return NO;
    if (schemes && [schemes count] && ![schemes containsObject:[aURL scheme]])
	return NO;
    if (destinations && [destinations count]) {
        unsigned int netIndex, netCount;
	NSString *aNetLocation;
	OWNetLocation *urlNetLocation;
	NSString *urlHostname;

	urlNetLocation = [aURL parsedNetLocation];
	urlHostname = [urlNetLocation hostname];
	netCount = [destinations count];
	for (netIndex = 0; netIndex < netCount; netIndex++) {
	    aNetLocation = [destinations objectAtIndex:netIndex];
	    if (![urlHostname hasSuffix:aNetLocation])
		continue;
	    return YES;
	}
	return NO;
    }
    return YES;
}

//

- (NSDictionary *)defaultsDictionary;
{
    NSMutableDictionary *defaultsDictionary;

    defaultsDictionary = [[NSMutableDictionary alloc] init];

    if (proxyURL)
        [defaultsDictionary setObject:[proxyURL compositeString] forKey:@"proxyURL"];
    else if (description)
	[defaultsDictionary setObject:description forKey:@"proxyURL"];
    if (schemes)
	[defaultsDictionary setObject:schemes forKey:@"schemes"];
    if (destinations)
	[defaultsDictionary setObject:destinations forKey:@"destinations"];
    if (!active)
	[defaultsDictionary setObject:@"NO" forKey:@"active"];

    return defaultsDictionary;
}

// Debugging

- (NSMutableDictionary *)debugDictionary;
{
    NSMutableDictionary *debugDictionary;

    debugDictionary = [super debugDictionary];

    [debugDictionary setObject:active ? @"YES" : @"NO" forKey:@"active"];
    if (proxyURL)
	[debugDictionary setObject:proxyURL forKey:@"proxyURL"];
    if (description)
	[debugDictionary setObject:description forKey:@"description"];
    if (schemes)
	[debugDictionary setObject:schemes forKey:@"schemes"];
    if (destinations)
	[debugDictionary setObject:destinations forKey:@"destinations"];

    return debugDictionary;
}

@end

@implementation OWProxyServer (Private)

+ (void)controllerDidInit:(NSNotification *)notification;
{
    NSArray *nonProxiableSchemesArray;
    unsigned int schemeIndex, schemeCount;

    [self proxyServersFromDefaults];

    [nonProxiableSchemes removeAllObjects];
    nonProxiableSchemesArray = [[OFUserDefaults sharedUserDefaults] arrayForKey:@"OWNonProxiableSchemes"];
    schemeCount = [nonProxiableSchemesArray count];
    for (schemeIndex = 0; schemeIndex < schemeCount; schemeIndex++) {
        NSString *nonProxiableScheme;

        nonProxiableScheme = [nonProxiableSchemesArray objectAtIndex:schemeIndex];
	[nonProxiableSchemes setObject:dummyValue forKey:nonProxiableScheme];
    }
}

+ (NSArray *)activeProxyServers;
{
    NSArray *activeProxyServersCopy;

    if (!activeProxyServers)
	return nil;
    [activeProxyServersLock lock];
    activeProxyServersCopy = [[activeProxyServers mutableCopy] autorelease];
    [activeProxyServersLock unlock];
    return activeProxyServersCopy;
}

+ (void)activateProxyServer:(OWProxyServer *)aProxyServer;
{
    [activeProxyServersLock lock];
    if (!activeProxyServers)
	activeProxyServers = [[NSMutableArray alloc] init];
    [activeProxyServers addObject:aProxyServer];
    [activeProxyServersLock unlock];
}

+ (void)deactivateProxyServer:(OWProxyServer *)aProxyServer;
{
    [activeProxyServersLock lock];
    [activeProxyServers removeObject:aProxyServer];
    if ([activeProxyServers count] == 0) {
	[activeProxyServers release];
	activeProxyServers = nil;
    }
    [activeProxyServersLock unlock];
}

+ (OWProxyServer *)proxyServerFromDefaultsDictionary:(NSDictionary *)aDictionary;
{
    OWProxyServer *newProxyServer;
    NSString *aDescription;
    NSArray *someSchemes;
    NSArray *someDestinations;

    aDescription = [aDictionary objectForKey:@"proxyURL"];
    someSchemes = [aDictionary objectForKey:@"schemes"];
    someDestinations = [aDictionary objectForKey:@"destinations"];

    newProxyServer = [[[self alloc] initWithProxyURL:nil] autorelease];
    [newProxyServer setDescription:aDescription];
    [newProxyServer setSchemes:someSchemes];
    [newProxyServer setDestinations:someDestinations];
    if (![[aDictionary objectForKey:@"active"] isEqualToString:@"NO"])
	[newProxyServer activate];

    return newProxyServer;
}

@end
