//
//  Creating_a_Core_Data_Model_with_XcodeAppDelegate.m
//  Creating a Core Data Model with Xcode
//
//  Created by Vandad Nahavandipoor on 23/07/2011.
//  Copyright 2011 Pixolity Ltd. All rights reserved.
//

#import "Creating_a_Core_Data_Model_with_XcodeAppDelegate.h"

@implementation Creating_a_Core_Data_Model_with_XcodeAppDelegate

@synthesize window = _window;
@synthesize managedObjectContext = __managedObjectContext;
@synthesize managedObjectModel = __managedObjectModel;
@synthesize persistentStoreCoordinator = __persistentStoreCoordinator;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Miejsce na przeprowadzenie własnej konfiguracji po uruchomieniu aplikacji.
    self.window.backgroundColor = [UIColor whiteColor];
    [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:.
   */
}

- (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.
   */
}

- (void)applicationWillTerminate:(UIApplication *)application
{
  // Metoda applicationWillTerminate: zapisuje zmiany w kontekście obiektu zarządzanego aplikacji przed zakończeniem działania aplikacji.
  [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 - 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:@"Creating_a_Core_Data_Model_with_Xcode" 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:@"Creating_a_Core_Data_Model_with_Xcode.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 - Katalog Documents aplikacji

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

@end
