//
//  Sorting_Data_in_Core_DataAppDelegate.m
//  Sorting Data in Core Data
//
//  Created by Vandad Nahavandipoor on 23/07/2011.
//  Copyright 2011 Pixolity Ltd. All rights reserved.
//

#import "Sorting_Data_in_Core_DataAppDelegate.h"
#import "Person.h"

@implementation Sorting_Data_in_Core_DataAppDelegate

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

- (BOOL) createNewPersonWithFirstName:(NSString *)paramFirstName
                             lastName:(NSString *)paramLastName
                                  age:(NSUInteger)paramAge{
  
  BOOL result = NO;
  
  if ([paramFirstName length] == 0 ||
      [paramLastName length] == 0){
    NSLog(@"Podanie imienia i nazwiska jest obowiązkowe.");
    return NO;
  }
  
  Person *newPerson = [NSEntityDescription 
                       insertNewObjectForEntityForName:@"Person"
                       inManagedObjectContext:self.managedObjectContext];
  
  if (newPerson == nil){
    NSLog(@"Nie udało się utworzyć nowego rekordu.");
    return NO;
  }
  
  newPerson.firstName = paramFirstName;
  newPerson.lastName = paramLastName;
  newPerson.age = [NSNumber numberWithUnsignedInteger:paramAge];
  
  NSError *savingError = nil;
  
  if ([self.managedObjectContext save:&savingError]){
    return YES;
  } else {
    NSLog(@"Nie udało się utworzyć nowego rekordu. Błąd = %@", savingError);
  }
  
  return result;
  
}

/* 1 */
- (BOOL)            application:(UIApplication *)application 
  didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
  
  [self createNewPersonWithFirstName:@"Jan"
                            lastName:@"Kowalski"
                                 age:61];
  
  [self createNewPersonWithFirstName:@"Adam"
                            lastName:@"Nowak"
                                 age:51];
  
  /* Najpierw tworzymy żądanie pobrania danych. */
  NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
  
  /* To jest encja, z której będziemy odczytywać dane. */
  NSEntityDescription *entity = 
  [NSEntityDescription entityForName:@"Person"
              inManagedObjectContext:self.managedObjectContext];
  
  NSSortDescriptor *ageSort = 
  [[NSSortDescriptor alloc] initWithKey:@"age"
                              ascending:YES];
  
  NSSortDescriptor *firstNameSort = 
  [[NSSortDescriptor alloc] initWithKey:@"firstName"
                              ascending:YES];
  
  NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:
                              ageSort,
                              firstNameSort, nil];
  
  fetchRequest.sortDescriptors = sortDescriptors;
  
  /* Określenie w żądaniu, że będzie odczytywana zawartość encji Person. */
  [fetchRequest setEntity:entity];
  
  NSError *requestError = nil;
  
  /* Wykonanie w kontekście żądania pobrania danych. */
  NSArray *persons = 
  [self.managedObjectContext executeFetchRequest:fetchRequest
                                           error:&requestError];
  
  for (Person *person in persons){
    
    NSLog(@"Imię = %@", person.firstName);
    NSLog(@"Nazwisko = %@", person.lastName);
    NSLog(@"Wiek = %lu", (unsigned long)[person.age unsignedIntegerValue]);
    
  }
  
  self.window = [[UIWindow alloc] initWithFrame:
                 [[UIScreen mainScreen] bounds]];
  
  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:@"Sorting_Data_in_Core_Data" 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:@"Sorting_Data_in_Core_Data.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
