/*************************************************************************
 * File Name: NSDictionary+MiscDefaultsSupport.m
 * Version  : 0.0 alpha
 * Date     : Thu 21-Aug-1997
 *************************************************************************
 *  COPYWHAT (C) 1997 by Tomi Engel
 *
 * This notice may not be removed from this source code.
 * The use and distribution of this software is governed by the
 * terms of the MiscKit license agreement.  Refer to the license
 * document included with the MiscKit distribution for the terms.
 *                    ALL RIGHTS RESERVED
 *
 *************************************************************************    
 * Notes      : 
 * Bugs       : 
 * Author(s)  : tsengel
 * Last update: $Date: 1997/08/27 11:02:58 $
 * History    : $Log: NSDictionary+MiscDefaultsSupport.m,v $
 * History    : Revision 1.1  1997/08/27 11:02:58  tsengel
 * History    : Added to the FBAuthor repository
 * History    :
 * History    : Revision 1.1  1997/08/22 00:34:30  tsengel
 * History    : Added category to simplify NSUSerDefaults handling
 * History    :
 * History    : Revision 1.1.1.1  1997/07/09 15:22:52  tsengel
 * History    : New import [GT]
 * History    :
 *************************************************************************/ 

#import "NSDictionary+MiscDefaultsSupport.h"


@implementation NSDictionary (MiscDefaultsSupport)

/*"
    NSDictionaries are often used in combination with the NSUserDefaults class. Even if both share some methods...they don't share all of them. This category is intended to add a set of convenience methods which make both APIs look more similar.
    This should make your life  litte easier since most apps have a place where they register their defualts like this:

       NSMutableDictionary* registrationDict = [NSMutableDictionary dictionary];

       [registrationDict setObject:@"YES" forKey:@"UseTheMiscKit"];
       [registrationDict setObject:[NSNumber numberWithInt:42] forKey:@"Don'tPanic"];

       [[NSUserDefaults standardUserDefaults] registerDefaults:registrationDict];

    ...which looks a littel odd and is somehow confusing since NSUserDefaults usually is handling this sort of thing in a more elegant way. With this category you can now rewrite your code so that it look more natural:


       NSMutableDictionary* registrationDict = [NSMutableDictionary dictionary];

       [registrationDict setBool:YES forKey:@"UseTheMiscKit"];
       [registrationDict setInteger:42 forKey:@"Don'tPanic"];

       [[NSUserDefaults standardUserDefaults] registerDefaults:registrationDict];


    While we could have implemented smarter methods we have sticked to the API definitions of the NSUserDefaults classs since otherwise it would become less obviouse while certain code works for NSDictionaries but not for NSUserDefaults. Time will tell if we should stick with this decission or not. 

    #NOTE: We propably should add the keyPath methods to the EOF part for these too. Could be useful.

"*/

- (NSString *)stringForKey:(id)aKey
/*"
     Invokes #objectForKey: with key aKey. Returns the corresponding value if it's some kind of a NSString object and nil otherwise.
"*/
{
    id		theValue = [self objectForKey:aKey];

    if( !theValue ) return nil;
    else if( [theValue isKindOfClass:[NSString class]] )
        return theValue;

    return nil;
}

- (NSArray *)arrayForKey:(id)aKey
/*"
     Invokes #objectForKey: with key aKey. Returns the corresponding value if it's some kind of a NSArray object and nil otherwise.
"*/
{
    id		theValue = [self objectForKey:aKey];

    if( !theValue ) return nil;
    else if( [theValue isKindOfClass:[NSArray class]] )
        return theValue;

    return nil;
}

- (NSDictionary *)dictionaryForKey:(id)aKey
/*"
    Invokes #objectForKey: with key aKey. Returns the corresponding value if it's some kind of a NSDictionary object and nil otherwise.
"*/
{
    id		theValue = [self objectForKey:aKey];

    if( !theValue ) return nil;
    else if( [theValue isKindOfClass:[NSDictionary class]] )
        return theValue;

    return nil;
}

- (NSData *)dataForKey:(id)aKey
/*"
    Invokes #objectForKey: with key aKey. Returns the corresponding value if it's some kind of a NSDictionary object and nil otherwise.
"*/
{
    id		theValue = [self objectForKey:aKey];

    if( !theValue ) return nil;
    else if( [theValue isKindOfClass:[NSData class]] )
        return theValue;

    return nil;
}

- (NSArray *)stringArrayForKey:(id)aKey
/*"
     Invokes arrayForKey: with key aKey. Returns the corresponding value if it's an NSArray object containing NSStrings, and nil otherwise
"*/
{
    // <<NOTE>> Personally I have my doubts if this method really is very useful....but since NSUserDefaults contains it we
    // will provide a compatible method as well.
    // Sicne the original method description is not very precise we assume that the array is allow to contain _only_ NSStrings.

    id		theValue = [self arrayForKey:aKey];
    id		anEnum = [theValue objectEnumerator];
    id		nextEntry;

    // If theValue is nil the following code will work as well...so we jsut skip the value check.

    while( nextEntry = [anEnum nextObject] )
        if( ![nextEntry isKindOfClass:[NSString class]] ) return nil;

    return theValue;
}

- (int)integerForKey:(id)aKey
/*"
    Invokes #stringForKey: with key aKey and invokes the method #intValue on the returned object.
"*/
{
    id		theValue = [self stringForKey:aKey];
    return [theValue intValue];
}

- (float)floatForKey:(id)aKey
/*"
    Invokes #stringForKey: with key aKey and invokes the method #floatValue on the returned object.
"*/
{
    id		theValue = [self stringForKey:aKey];
    return [theValue floatValue];
}

- (BOOL)boolForKey:(id)aKey
/*"
    Invokes #stringForKey: with key aKey and invokes the method #boolValue on the returned object.
"*/
{
    // Since we ensured that NSStrings really know the boolValue method we do not have to check for he method.

    id		theValue = [self stringForKey:aKey];
    return [theValue boolValue];
}

@end


@implementation NSMutableDictionary (MiscDefaultsSupport)

/*"
In combination with the NSDictionary (MiscDefaultsSupport) category we provide the missing set methods to support the same methods like the NSDefaults class.
    <<NOTE>> If it is considered useful we might also add all the methods which are offered by the regular NSNumber class. However..they might not be of much use.
"*/

- (void)setInteger:(int)value forKey:(id)aKey
/*"
    Inserts an NSString representing value as an integer into the dictionary.
"*/
{
    id	anIntString = [[NSString alloc] initWithFormat:@"%i", value];

    [self setObject:anIntString forKey:aKey];
    [anIntString release];
}

- (void)setFloat:(float)value forKey:(id)aKey
/*"
    Inserts an NSString representing value as a float into the dictionary.
"*/
{
    id	aFloatString = [[NSString alloc] initWithFormat:@"%f", value];

    [self setObject:aFloatString forKey:aKey];
    [aFloatString release];
}

- (void)setBool:(BOOL)value forKey:(id)aKey
/*"
    Inserts an NSString according to value into the dictionary with the key aKey. NSStrings #initWithBool method is used to create the string.
"*/
{
    id	aBoolString = [[NSString alloc] initWithBool:value];

    [self setObject:aBoolString forKey:aKey];
    [aBoolString release];
}

@end


@implementation NSString (MiscDefaultsSupport)

/*"
    In combination with the NSDictionary methods this allows for NSUserDefaults like value handling. The used string constants are always "YES" and "NO" using all uppercase characters.
    Since the NSUserDefaults do not use these methods we can not provide "smarter" behavior at the risk of getting a little inconsistent. Time will 	tell if this limitation is needed.
"*/

+ (id)stringWithBool:(BOOL)value
/*"
    Returns a string by using #stringWithString and the strings "YES" or "NO" depending on the specified value.
"*/
{
    if( value == NO )
        return [self stringWithString:@"NO"];
    else
        return [self stringWithString:@"YES"];
}

- (id)initWithBool:(BOOL)value
/*"
    Invoces #initWithString and the strings "YES" or "NO" depending on the specified value.
"*/
{
    if( value == NO )
        return [self initWithString:@"NO"];
    else
        return [self initWithString:@"YES"];
}

- (BOOL)boolValue
/*"
    Returns YES if the value associated with defaultName is an NSString containing uppercase or lowercase "YES". Or if our #intValue method returns a non-zero value.
"*/
{
    if( [self caseInsensitiveCompare:@"YES"] == NSOrderedSame ||
        [self intValue] != 0 )
        return YES;

    return NO;
}

@end

@implementation NSMutableString (MiscDefaultsSupport)

/*" In combination with the NSDictionary methods this category allows for NSUserDefaults like bool value handling. Mutable string support a wya of setting the bool value directly."*/

- (void)setBoolValue:(BOOL)value
/*"
    Sets our string to a valid representation of YES or NO. This means that #boolValue will return to correct result afterwards. By default the string constants are "YES" and "NO".
"*/
{
    if( value == NO )
        [self setString:@"NO"];
    else
        [self setString:@"YES"];
}

@end
