//  DMLocalizedNibBundle.m
//
//  Created by William Jon Shipley on 2/13/05.
//  Copyright © 2005-2009 Golden % Braeburn, LLC. All rights reserved except as below:
//  This code is provided as-is, with no warranties or anything. You may use it in your projects as you wish, but you must leave this comment block (credits and copyright) intact. That's the only restriction -- Golden % Braeburn otherwise grants you a fully-paid, worldwide, transferrable license to use this code as you see fit, including but not limited to making derivative works.


#import <Cocoa/Cocoa.h>
#import <objc/runtime.h>


@interface NSBundle (DMLocalizedNibBundle)
+ (BOOL)deliciousLocalizingLoadNibFile:(NSString *)fileName externalNameTable:(NSDictionary *)context withZone:(NSZone *)zone;
@end

@interface NSBundle ()
+ (void)_localizeStringsInObject:(id)object table:(NSString *)table;
+ (NSString *)_localizedStringForString:(NSString *)string table:(NSString *)table;
// localize particular attributes in objects
+ (void)_localizeTitleOfObject:(id)object table:(NSString *)table;
+ (void)_localizeAlternateTitleOfObject:(id)object table:(NSString *)table;
+ (void)_localizeStringValueOfObject:(id)object table:(NSString *)table;
+ (void)_localizePlaceholderStringOfObject:(id)object table:(NSString *)table;
+ (void)_localizeToolTipOfObject:(id)object table:(NSString *)table;
+ (void)_localizeLabelOfObject:(id)object table:(NSString *)table;
@end

static NSMutableArray *deliciousBindingKeys = nil;

@implementation NSBundle (DMLocalizedNibBundle)

#pragma mark NSObject

+ (void)load;
{
    NSAutoreleasePool *autoreleasePool = [[NSAutoreleasePool alloc] init];
    if (self == [NSBundle class]) {
        method_exchangeImplementations(class_getClassMethod(self, @selector(loadNibFile:externalNameTable:withZone:)), class_getClassMethod(self, @selector(deliciousLocalizingLoadNibFile:externalNameTable:withZone:)));
        deliciousBindingKeys = [[NSMutableArray alloc] initWithObjects:
                                    NSMultipleValuesPlaceholderBindingOption,
                                    NSNoSelectionPlaceholderBindingOption,
                                    NSNotApplicablePlaceholderBindingOption,
                                    NSNullPlaceholderBindingOption,
                                    nil];
    }
    [autoreleasePool release];
}


#pragma mark API

+ (BOOL)deliciousLocalizingLoadNibFile:(NSString *)fileName externalNameTable:(NSDictionary *)context withZone:(NSZone *)zone;
{
    NSString *localizedStringsTableName = [[fileName lastPathComponent] stringByDeletingPathExtension];
    NSString *localizedStringsTablePath = [[NSBundle mainBundle] pathForResource:localizedStringsTableName ofType:@"strings"];
    if (localizedStringsTablePath && ![[[localizedStringsTablePath stringByDeletingLastPathComponent] lastPathComponent] isEqualToString:@"English.lproj"]) {
        
        NSNib *nib = [[NSNib alloc] initWithContentsOfURL:[NSURL fileURLWithPath:fileName]];
        NSMutableArray *topLevelObjectsArray = [context objectForKey:NSNibTopLevelObjects];
        if (!topLevelObjectsArray) {
            topLevelObjectsArray = [NSMutableArray array];
            context = [NSMutableDictionary dictionaryWithDictionary:context];
            [(NSMutableDictionary *)context setObject:topLevelObjectsArray forKey:NSNibTopLevelObjects];
        }
        BOOL success = [nib instantiateNibWithExternalNameTable:context];
        [self _localizeStringsInObject:topLevelObjectsArray table:localizedStringsTableName];
        
        [nib release];
        return success;
        
    } else {
        return [self deliciousLocalizingLoadNibFile:fileName externalNameTable:context withZone:zone];
    }
}



#pragma mark Private API

+ (void)_localizeStringsInObject:(id)object table:(NSString *)table;
{
    if ([object isKindOfClass:[NSArray class]]) {
        NSArray *array = object;
        
        for (id nibItem in array)
            [self _localizeStringsInObject:nibItem table:table];

    } else if ([object isKindOfClass:[NSCell class]]) {
        NSCell *cell = object;
        
        if ([cell isKindOfClass:[NSActionCell class]]) {
            NSActionCell *actionCell = (NSActionCell *)cell;
            
            if ([actionCell isKindOfClass:[NSButtonCell class]]) {
                NSButtonCell *buttonCell = (NSButtonCell *)actionCell;
                if ([buttonCell imagePosition] != NSImageOnly) {
                    [self _localizeTitleOfObject:buttonCell table:table];
                    [self _localizeStringValueOfObject:buttonCell table:table];
                    [self _localizeAlternateTitleOfObject:buttonCell table:table];
                }
                
            } else if ([actionCell isKindOfClass:[NSTextFieldCell class]]) {
                NSTextFieldCell *textFieldCell = (NSTextFieldCell *)actionCell;
                // Following line is redundant with other code, localizes twice.
                // [self _localizeTitleOfObject:textFieldCell table:table];
                [self _localizeStringValueOfObject:textFieldCell table:table];
                [self _localizePlaceholderStringOfObject:textFieldCell table:table];

            } else if ([actionCell type] == NSTextCellType) {
                [self _localizeTitleOfObject:actionCell table:table];
                [self _localizeStringValueOfObject:actionCell table:table];
            }
        }
        
    } else if ([object isKindOfClass:[NSMenu class]]) {
        NSMenu *menu = object;
        [self _localizeTitleOfObject:menu table:table];
        
        [self _localizeStringsInObject:[menu itemArray] table:table];
        
    } else if ([object isKindOfClass:[NSMenuItem class]]) {
        NSMenuItem *menuItem = object;
        [self _localizeTitleOfObject:menuItem table:table];
        [self _localizeToolTipOfObject:menuItem table:table];
        
        [self _localizeStringsInObject:[menuItem submenu] table:table];
        
    } else if ([object isKindOfClass:[NSView class]]) {
        NSView *view = object;
        [self _localizeToolTipOfObject:view table:table];

        if ([view isKindOfClass:[NSBox class]]) {
            NSBox *box = (NSBox *)view;
            [self _localizeTitleOfObject:box table:table];
            
        } else if ([view isKindOfClass:[NSControl class]]) {
            NSControl *control = (NSControl *)view;

            if ([view isKindOfClass:[NSButton class]]) {
                NSButton *button = (NSButton *)control;
                
                if ([button isKindOfClass:[NSPopUpButton class]]) {
                    NSPopUpButton *popUpButton = (NSPopUpButton *)button;
                    NSMenu *menu = [popUpButton menu];
                    
                    [self _localizeStringsInObject:[menu itemArray] table:table];
                } else
                    [self _localizeStringsInObject:[button cell] table:table];

                
            } else if ([view isKindOfClass:[NSMatrix class]]) {
                NSMatrix *matrix = (NSMatrix *)control;
                
                NSArray *cells = [matrix cells];
                [self _localizeStringsInObject:cells table:table];
                
                for (NSCell *cell in cells) {
                    
                    NSString *localizedCellToolTip = [self _localizedStringForString:[matrix toolTipForCell:cell] table:table];
                    if (localizedCellToolTip)
                        [matrix setToolTip:localizedCellToolTip forCell:cell];
                }
                
            } else if ([view isKindOfClass:[NSSegmentedControl class]]) {
                NSSegmentedControl *segmentedControl = (NSSegmentedControl *)control;
                
                NSUInteger segmentIndex, segmentCount = [segmentedControl segmentCount];
                for (segmentIndex = 0; segmentIndex < segmentCount; segmentIndex++) {
                    NSString *localizedSegmentLabel = [self _localizedStringForString:[segmentedControl labelForSegment:segmentIndex] table:table];
                    if (localizedSegmentLabel)
                        [segmentedControl setLabel:localizedSegmentLabel forSegment:segmentIndex];
                    NSString *localizedSegmentTooltip = [self _localizedStringForString:[[segmentedControl cell] toolTipForSegment:segmentIndex] table:table];
                    if (localizedSegmentTooltip)
                        [[segmentedControl cell] setToolTip:localizedSegmentTooltip forSegment:segmentIndex];
                    
                    [self _localizeStringsInObject:[segmentedControl menuForSegment:segmentIndex] table:table];
                }
                
            } else if ([view isKindOfClass:[NSTableView class]]) {
                for (NSTableColumn *column in [view tableColumns]) {
                    [self _localizeStringValueOfObject:[column headerCell] table:table];
                }
            
            } else if ([view isKindOfClass:[NSTextField class]]) {
                NSDictionary *vb;
                if (vb = [view infoForBinding:@"value"]) {
                    NSMutableDictionary *lvb = [NSMutableDictionary dictionaryWithDictionary:[vb objectForKey:NSOptionsKey]];
                    for (NSString *bindingKey in deliciousBindingKeys) {
                        if ([lvb objectForKey:bindingKey] == [NSNull null]) continue;
                        NSString *localizedBindingString = [self _localizedStringForString:[lvb objectForKey:bindingKey] table:table];
                        if (localizedBindingString)
                            [lvb setObject:localizedBindingString forKey:bindingKey];
                    }
                    [view bind:@"value" toObject:[vb objectForKey:NSObservedObjectKey] withKeyPath:[vb objectForKey:NSObservedKeyPathKey] options:lvb];
                }
                [self _localizeStringsInObject:[control cell] table:table];
                
            } else
                [self _localizeStringsInObject:[control cell] table:table];

        } else if ([view isKindOfClass:[NSTabView class]]) {
            NSTabView *tabView = (NSTabView *)view;
            for (NSTabViewItem *tabViewItem in [tabView tabViewItems]) {
                [self _localizeLabelOfObject:tabViewItem table:table];
                if ([tabViewItem respondsToSelector:@selector(toolTip)]) // 10.6+
                    [self _localizeToolTipOfObject:tabViewItem table:table];
                [self _localizeStringsInObject:[tabViewItem view] table:table];
            }

        }
        
        [self _localizeStringsInObject:[view subviews] table:table];
        
    } else if ([object isKindOfClass:[NSWindow class]]) {
        NSWindow *window = object;
        [self _localizeTitleOfObject:window table:table];
        
        [self _localizeStringsInObject:[window contentView] table:table];
        
    }
}

+ (NSString *)_localizedStringForString:(NSString *)string table:(NSString *)table;
{
    if (![string length])
        return nil;
    
    static NSString *defaultValue = @"I AM THE DEFAULT VALUE";
    NSString *localizedString = [[NSBundle mainBundle] localizedStringForKey:string value:defaultValue table:table];
    if (localizedString != defaultValue) {
        return localizedString;
    } else { 
#ifdef BETA_BUILD
        NSLog(@"        not going to localize string %@", string);
        return string; // [string uppercaseString]
#else
        return string;
#endif
    }
}


#define DM_DEFINE_LOCALIZE_BLAH_OF_OBJECT(blahName, capitalizedBlahName) \
+ (void)_localize ##capitalizedBlahName ##OfObject:(id)object table:(NSString *)table; \
{ \
    NSString *localizedBlah = [self _localizedStringForString:[object blahName] table:table]; \
    if (localizedBlah) \
        [object set ##capitalizedBlahName:localizedBlah]; \
}

DM_DEFINE_LOCALIZE_BLAH_OF_OBJECT(title, Title)
DM_DEFINE_LOCALIZE_BLAH_OF_OBJECT(alternateTitle, AlternateTitle)
DM_DEFINE_LOCALIZE_BLAH_OF_OBJECT(stringValue, StringValue)
DM_DEFINE_LOCALIZE_BLAH_OF_OBJECT(placeholderString, PlaceholderString)
DM_DEFINE_LOCALIZE_BLAH_OF_OBJECT(toolTip, ToolTip)
DM_DEFINE_LOCALIZE_BLAH_OF_OBJECT(label, Label)

@end