// Copyright 1997-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 <OmniFoundation/CFDictionary-OFExtensions.h>

#import <OmniFoundation/CFString-OFExtensions.h>
#import <Foundation/NSObject.h>
#import <Foundation/NSString.h>
#import <OmniBase/rcsid.h>

RCS_ID("$Header: /Network/Source/CVS/OmniGroup/Frameworks/OmniFoundation/CoreFoundationExtensions/CFDictionary-OFExtensions.m,v 1.5 2000/11/11 07:10:53 bungi Exp $")



static const void *_OFCaseInsensitiveStringKeyRetainCallBack(CFAllocatorRef allocator, const void *value)
{
    return CFRetain((CFStringRef)value);
}

static void _OFCaseInsensitiveStringKeyReleaseCallBack(CFAllocatorRef allocator, const void *value)
{
    CFRelease((CFStringRef)value);
}

static CFStringRef _OFCaseInsensitiveStringKeyCopyDescriptionCallBack(const void *value)
{
    return CFRetain((CFStringRef)value);
}

static Boolean _OFCaseInsensitiveStringKeyIsEqualCallBack(const void *value1, const void *value2)
{
    return CFStringCompare((CFStringRef)value1, (CFStringRef)value2, kCFCompareCaseInsensitive) == kCFCompareEqualTo;
}

static CFHashCode _OFCaseInsensitiveStringKeyHashCallBack(const void *value)
{
    // This is the only interesting function in the bunch.  We need to ensure that all
    // case variants of the same string (when 'same' is determine case insensitively)
    // have the same hash code.  We will do this by using CFStringGetCharacters over
    // the first 16 characters of each key.
    // This is obviously not a good hashing algorithm for all strings.
    UniChar characters[16];
    unsigned int length;
    CFStringRef string;
    
    string = (CFStringRef)value;
    
    length = CFStringGetLength(string);
    if (length > 16)
        length = 16;
        
    CFStringGetCharacters(string, CFRangeMake(0, length), characters);
    
    return OFCaseInsensitiveHash(characters, length);
}


const CFDictionaryKeyCallBacks
_OFCaseInsensitiveStringKeyDictionaryCallbacks = {
    0,
    _OFCaseInsensitiveStringKeyRetainCallBack,
    _OFCaseInsensitiveStringKeyReleaseCallBack,
    _OFCaseInsensitiveStringKeyCopyDescriptionCallBack,
    _OFCaseInsensitiveStringKeyIsEqualCallBack,
    _OFCaseInsensitiveStringKeyHashCallBack
};

const CFDictionaryKeyCallBacks *
OFCaseInsensitiveStringKeyDictionaryCallbacks = &_OFCaseInsensitiveStringKeyDictionaryCallbacks;


static const void * _OFNSObjectDictionaryValueRetainCallBack(CFAllocatorRef allocator, const void *value)
{
    return [(id)value retain];
}

static void _OFNSObjectDictionaryValueReleaseCallBack(CFAllocatorRef allocator, const void *value)
{
    [(id)value release];
}

static CFStringRef _OFNSObjectDictionaryValueCopyDescriptionCallBack(const void *value)
{
    return (CFStringRef)[[(id)value description] retain];
}

static Boolean _OFNSObjectDictionaryValueIsEqualCallBack(const void *value1, const void *value2)
{
    return [(id)value1 isEqual: (id)value2];
}

static const CFDictionaryValueCallBacks
_OFNSObjectDictionaryValueCallbacks = {
    0,
    _OFNSObjectDictionaryValueRetainCallBack,
    _OFNSObjectDictionaryValueReleaseCallBack,
    _OFNSObjectDictionaryValueCopyDescriptionCallBack,
    _OFNSObjectDictionaryValueIsEqualCallBack,
};

const CFDictionaryValueCallBacks *
OFNSObjectDictionaryValueCallbacks = &_OFNSObjectDictionaryValueCallbacks;


// Convenience functions

NSMutableDictionary *OFCreateCaseInsensitiveKeyMutableDictionary()
{
    return (NSMutableDictionary *) CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
                                          OFCaseInsensitiveStringKeyDictionaryCallbacks,
                                          OFNSObjectDictionaryValueCallbacks);
}

