//
//  OAMigrationUtilities.m
//  Flash
//
//  Created by Nicholas Matsakis on 8/30/07.
//  Copyright 2007 __MyCompanyName__. All rights reserved.
//

#import "OAMigrationUtilities.h"

/** Utility methods borrowed from Apple's examples */
@implementation OAMigrationUtilities

+ (NSString *)pathForModelNamed:(NSString *)modelName {
    
    NSString *path = nil;
    
    NSBundle *bundle = [NSBundle bundleForClass:[self class]];
    path = [bundle pathForResource:modelName ofType:@"mom"];
    
    /*
     this code doesn't work:
     
    NSArray *allBundles = [NSBundle allFrameworks];
    NSBundle *currentBundle = nil;
    int i= 0 , bundleCount = [allBundles count];
    
    for( ; i < bundleCount ; i++ ){
        currentBundle = [allBundles objectAtIndex: i];
        path =  [currentBundle pathForResource: modelName ofType: @"mom"];
        
        if (nil != path) {
            break;
        }
    }
     */
    
    if (nil == path) {
        @throw [NSException exceptionWithName: @"MissingResourceException" reason: [NSString stringWithFormat: @"Can't find model %@!", modelName] userInfo: nil];
    }
    
    return path;
}

+ (NSManagedObjectModel *) namedObjectModel:(NSString*)modelName
{
    return [[NSManagedObjectModel alloc] initWithContentsOfURL:[NSURL fileURLWithPath:[self pathForModelNamed:modelName]]];
}


+ (NSManagedObjectContext *)createRetainedCoreDataStackWithStorePath:(NSString *)storePath 
                                                           storeType:(NSString *)storeType
                                                               model:(NSManagedObjectModel *)storeModel {
    NSError *error;
    NSPersistentStoreCoordinator *coordinator;
    NSManagedObjectContext *managedObjectContext = nil;
    
    coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: storeModel];
    id store = nil;
    if (store = [coordinator addPersistentStoreWithType:storeType 
                                          configuration:nil 
                                                    URL:[NSURL fileURLWithPath: storePath] 
                                                options:nil 
                                                  error:&error]){
        managedObjectContext = [[NSManagedObjectContext alloc] init];
        [managedObjectContext setPersistentStoreCoordinator: coordinator];
    } 
    
    [coordinator release];
    
    return managedObjectContext;
    
}

+ (void)setMetadata:(NSString *)value forKey:(NSString *)key inStoreWithPath:(NSString *)path inContext:(NSManagedObjectContext *)context {
    NSPersistentStoreCoordinator *coordinator = [context persistentStoreCoordinator];
    id store = [coordinator persistentStoreForURL: [NSURL fileURLWithPath: path]];
    NSMutableDictionary *metadata = [[coordinator metadataForPersistentStore: store] mutableCopy];
    [metadata setValue: value forKey: key];
    [coordinator setMetadata: metadata forPersistentStore: store];    
}

+ (NSString *)getMetadataForKey:(NSString *)key inStoreWithPath:(NSString *)path inContext:(NSManagedObjectContext *)context {
    NSString *version = nil;
    
    if (nil == context) {
        NSError *error = nil;
        NSDictionary *metadata = [NSPersistentStoreCoordinator metadataForPersistentStoreWithURL: [NSURL fileURLWithPath: path] error:&error];
        if (nil == error) {
            version = [metadata valueForKey: key];
        }
    } else {
        NSPersistentStoreCoordinator *coordinator = [context persistentStoreCoordinator];
        id store = [coordinator persistentStoreForURL: [NSURL fileURLWithPath: path]];
        NSMutableDictionary *metadata = [[coordinator metadataForPersistentStore: store] mutableCopy];
        version = [metadata valueForKey: key];
    } 
    return version;
}

+ (void)presentErrorWithDescription:(NSString *)errorString {
    static NSString *domainString;
    
    if (nil == domainString) {
        NSArray *identifierComponents = [[[NSBundle mainBundle] bundleIdentifier] componentsSeparatedByString: @"."];
        domainString = [identifierComponents objectAtIndex: [identifierComponents count] - 1];
    }
    NSError *error = [NSError errorWithDomain: domainString code: 0 userInfo: [NSDictionary dictionaryWithObject: errorString forKey: NSLocalizedDescriptionKey]];
    [[NSApplication sharedApplication] presentError:error];
}

+ (BOOL)createPathIfNecessary:(NSString *)storeDirectory {
    NSFileManager *defaultManager = [NSFileManager defaultManager];
    BOOL success = NO;
    
    
    int i, c;
    NSArray* components = [storeDirectory pathComponents];
    NSString* current = @"";
    c = [components count];  
    for (i = 0; i < c; i++) {
        NSString* index = [components objectAtIndex:i];
        NSString* next = [current stringByAppendingPathComponent:index];
        current = next;
        if (![[NSFileManager defaultManager] fileExistsAtPath: next]) {
            success = [defaultManager createDirectoryAtPath: next attributes: nil];
            if (!success) {
                [self presentErrorWithDescription: [NSString stringWithFormat: @"Can't create directory at path (%@)", next]];
                return NO;
            }
        } 
    }
    
    return YES;
}

// Very simplistic attribute to descriptive string conversion
+ (NSString *)descriptionForAttributeWithKey:(NSString *)key ofObject:(NSManagedObject *)object
{
    id value = [object valueForKey:key];
    if ([value isKindOfClass:[NSString class]])
        if ([(NSString *)value length] > 20)
            return [NSString stringWithFormat:@"\"%@...\"", [(NSString *)value substringToIndex:17]];
    return [NSString stringWithFormat:@"\"%@\"", value];
    
    return [NSString stringWithFormat:@"%@", value];
}

// Returns a string description of the managed object, displaying the entity name and  
// objectID detail, and if object is not in the visited objects set the attributes and 
// descriptions for related objects (by recursively invoking
// contentDescriptionForManagedObject:linePrefix:visitedObjects:.)
+ (NSString *)contentDescriptionForManagedObject:(NSManagedObject *)object linePrefix:(NSString *)prefix visitedObjects:(NSMutableSet *)visitedObjects {
    NSMutableString *buffer = [NSMutableString string];
    NSEntityDescription *entity = [object entity];
    NSString *newPrefix = [prefix stringByAppendingString:@"\t"];
    
    // Describe the entity and object ID, include the 'name' if that's an attribute
    [buffer appendFormat:@"%@(...%@)", [entity name], [[[object objectID] URIRepresentation] path]];
    if ([visitedObjects containsObject:object]) 
        [buffer appendString:@"*"]; // indicate that this managed object has already been visited
    if ([[entity attributesByName] objectForKey:@"name"] != nil) 
        [buffer appendFormat:@" -- \"%@\"", [object valueForKey:@"name"]];
    [buffer appendString:@"\n"];
    
    // If this object has already been visited, return immediately
    if ([visitedObjects containsObject:object]) {
        return buffer;
    } else {
        [visitedObjects addObject:object];
    }
    
    // Describe the attributes
    NSString *key = nil;
    NSEnumerator *attributeKeyEnumerator = [[[[entity attributesByName] allKeys] sortedArrayUsingSelector:@selector(compare:)] objectEnumerator];
    while (key = [attributeKeyEnumerator nextObject]) {
        [buffer appendFormat:@"%@%@ = %@\n", newPrefix, key, [self descriptionForAttributeWithKey:key ofObject:object]];
    }
    
    // Describe the relatiohships and their contents 
    NSEnumerator *relationshipKeyEnumerator = [[[[entity relationshipsByName] allKeys] sortedArrayUsingSelector:@selector(compare:)] objectEnumerator];
    while (key = [relationshipKeyEnumerator nextObject]) {
        NSRelationshipDescription *relationship = [[entity relationshipsByName] objectForKey:key];
        
        if ([relationship isToMany]) {
            [buffer appendFormat:@"%@%@ =>> [\n", newPrefix, key, newPrefix];
            NSString *toManyPrefix = [newPrefix stringByAppendingString:@"\t"];
            NSEnumerator *relatedObjectEnumerator = nil;
            // try to enumerate the to many relationship in order by the name of the destination objects
            if ([[[relationship destinationEntity] attributesByName] objectForKey:@"name"]) {
                relatedObjectEnumerator = [[[[object valueForKey:key] allObjects] sortedArrayUsingDescriptors:[NSArray arrayWithObject:[[[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES] autorelease]]] objectEnumerator];
            } else {
                relatedObjectEnumerator = [[object valueForKey:key] objectEnumerator];
            }
            NSManagedObject *relatedObject = nil;
            while (relatedObject = [relatedObjectEnumerator nextObject]) {
                [buffer appendFormat:@"%@%@", toManyPrefix, [self contentDescriptionForManagedObject:relatedObject linePrefix:toManyPrefix visitedObjects:visitedObjects]];
            }
            [buffer appendFormat:@"%@]\n", newPrefix];
        } else {
            [buffer appendFormat:@"%@\t%@ => %@", prefix, key, [self contentDescriptionForManagedObject:[object valueForKey:key] linePrefix:newPrefix visitedObjects:visitedObjects]];
        }
    }
    return buffer;
}


@end
