//
//  Core_Data_PersistenceAppDelegate.m
//  Core Data Persistence
//
//  Created by Robert Górczyński on 11-07-18.
//

#import "Core_Data_PersistenceAppDelegate.h"
#import "PersistenceViewController.h"

@implementation Core_Data_PersistenceAppDelegate

@synthesize window;
@synthesize rootController;

#pragma mark -
#pragma mark Cykl życiowy aplikacji

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    
    // W tym miejscu można umieścić polecenia wykonywane po uruchomieniu aplikacji.
    [self.window addSubview:rootController.view];    
    [self.window makeKeyAndVisible];
    
    return YES;
}


- (void)applicationWillResignActive:(UIApplication *)application {
    /*
     Ta metoda jest wywoływana, gdy aplikacja przechodzi ze stanu aktywnego do nieaktywnego. Może być wywołana w określonych sytuacjach (na przykład w chwili odbywania rozmowy telefonicznej lub po otrzymaniu wiadomości SMS) bądź kiedy użytkownik kończy działanie aplikacji. Metoda rozpoczyna proces przejścia do stanu pozostania w tle. Tę metodę można wykorzystać do wstrzymania wykonywania bieżących zadań, wyłączenia liczników czasu, zmniejszenia liczby klatek generowanych przez OpenGL ES. W grach ta metoda powinna być użyta do wstrzymania gry (pauza).
     */
}


- (void)applicationDidEnterBackground:(UIApplication *)application {
    /*
     Tę metodę należy wykorzystać do zwolnienia zasobów współdzielonych, zapisania danych użytkownika, wyzerowania liczników czasu oraz do przechowania takiej ilości informacji o stanie, która pozwoli na przywrócenie aplikacji do stanu bieżącego. Jeżeli aplikacja obsługuje działanie w tle, w chwili kończenia działania należy wywołać tę metodę zamiast applicationWillTerminate:.
     */
    [self saveContext];
}


- (void)applicationWillEnterForeground:(UIApplication *)application {
    /*
     Ta metoda jest wywoływana podczas przechodzenia aplikacji ze stanu aktywnego do działania w tle. Można więc tutaj wycofać wiele zmian wprowadzonych w chwili przechodzenia do stanu działania w tle.
     */
}


- (void)applicationDidBecomeActive:(UIApplication *)application {
    /*
     W tej metodzie można wznowić działanie zadań zatrzymanych (lub nieuruchomionych), gdy aplikacja była nieaktywna. Jeżeli aplikacja znajdowała się w trybie działania w tle, w metodzie można przeprowadzić odświeżenie interfejsu użytkownika.
     */
}


/**
 Metoda applicationWillTerminate: zapisuje zmiany w kontekście obiektu zarządzanego aplikacji przed zakończeniem działania aplikacji.
 */
- (void)applicationWillTerminate:(UIApplication *)application {
    [self saveContext];
}


- (void)saveContext {
    
    NSError *error = nil;
	NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
    if (managedObjectContext != nil) {
        if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
            /*
             Zastąp tę implementację kodem, który prawidłowo obsługuje błędy.
             
             Funkcja abort() powoduje zakończenie działania aplikacji i wygenerowanie odpowiedniego pliku dziennika. Ta funkcja nie powinna być używana w ostatecznej wersji aplikacji choć może być użyteczna podczas prac nad aplikacją. Jeżeli nie będzie możliwości kontynuacji działania po wystąpieniu błędu, wyświetl użytkownikowi komunikat informujący o konieczności zakończenia działania aplikacji poprzez naciśnięcie przycisku Początek.
             */
            NSLog(@"Wystąpił błąd niemożliwy do usunięcia %@, %@", error, [error userInfo]);
            abort();
        } 
    }
}    


#pragma mark -
#pragma mark Stos Core Data

/**
 Metoda zwraca kontekst obiektu zarządzanego aplikacji.
 Jeżeli ten kontekst jeszcze nie istnieje, zostanie utworzony i dołączony do koordynatora trwałego magazynu danych aplikacji.
 */
- (NSManagedObjectContext *)managedObjectContext {
    
    if (managedObjectContext_ != nil) {
        return managedObjectContext_;
    }
    
    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        managedObjectContext_ = [[NSManagedObjectContext alloc] init];
        [managedObjectContext_ setPersistentStoreCoordinator:coordinator];
    }
    return managedObjectContext_;
}


/**
 Metoda zwraca model obiektu zarządzanego aplikacji.
 Jeżeli ten model jeszcze nie istnieje, zostanie utworzony na podstawie modelu aplikacji.
 */
- (NSManagedObjectModel *)managedObjectModel {
    
    if (managedObjectModel_ != nil) {
        return managedObjectModel_;
    }
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Core_Data_Persistence" withExtension:@"momd"];
    managedObjectModel_ = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];    
    return managedObjectModel_;
}


/**
 Metoda zwraca koordynatora trwałego magazynu danych aplikacji. Jeżeli koordynator nie istnieje, zostanie utworzony, a magazyn danych zostanie do niego dołączony.
 */
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
    
    if (persistentStoreCoordinator_ != nil) {
        return persistentStoreCoordinator_;
    }
    
    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Core_Data_Persistence.sqlite"];
    
    NSError *error = nil;
    persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
        /*
         Zastąp tę implementację kodem, który prawidłowo obsługuje błędy.
         
         Funkcja abort() powoduje zakończenie działania aplikacji i wygenerowanie odpowiedniego pliku dziennika. Ta funkcja nie powinna być używana w ostatecznej wersji aplikacji choć może być użyteczna podczas prac nad aplikacją. Jeżeli nie będzie możliwości kontynuacji działania po wystąpieniu błędu, wyświetl użytkownikowi komunikat informujący o konieczności zakończenia działania aplikacji poprzez naciśnięcie przycisku Początek.
         
         Typowe przyczyny wystąpienia błędu to między innymi:
         * brak dostępu do trwałego magazynu danych;
         * schemat trwałego magazynu danych jest niezgodny z bieżącym modelem obiektu zarządzanego.
         Sprawdź komunikat błędu w celu określenia rzeczywistej przyczyny błędu.
         
         
         Jeżeli trwały magazyn danych hest niedostępny, problem najczęściej jest związany z błędną ścieżką dostępu do pliku. Bardzo często adres URL pliku prowadzi do katalogu zasobów aplikacji zamiast do katalogu pozwalającego na przeprowadzanie operacji zapisu.
         
         Po wystąpieniu niezgodności schematu, rozwiązaniem może być:
         * po prostu usunięcie istniejącego magazyny danych:
         [[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil]
         
         * przeprowadzenie automatycznej migracji poprzez przekazanie poniższego słownika jako parametru: 
         [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES],NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
         
         Wspomniana migracja działa jedynie względem ograniczonego zestawu zmian schematu; więcej informacji na ten temat znajdziesz w dokumencie zatytułowanym "Core Data Model Versioning and Data Migration Programming Guide".
         
         */
        NSLog(@"Wystąpił błąd niemożliwy do usunięcia %@, %@", error, [error userInfo]);
        abort();
    }    
    
    return persistentStoreCoordinator_;
}


#pragma mark -
#pragma mark Katalog Documents aplikacji

/**
 Metoda zwraca adres URL katalogu Documents aplikacji.
 */
- (NSURL *)applicationDocumentsDirectory {
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}


#pragma mark -
#pragma mark Zarządzanie pamięcią

- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
    /*
     Zwolnienie maksymalnej ilości pamięci poprzez usunięcie wszelkich buforowanych obiektów, które można później ponownie utworzyć (lub wczytać z dysku).
     */
}


- (void)dealloc {
    
    [managedObjectContext_ release];
    [managedObjectModel_ release];
    [persistentStoreCoordinator_ release];
    
    [window release];
    [super dealloc];
}


@end

