/***
 * Excerpted from "Developing for Apple Watch",
 * published by The Pragmatic Bookshelf.
 * Copyrights apply to this code. It may not be used to create training material, 
 * courses, books, articles, and the like. Contact us if you are in doubt.
 * We make no guarantees that this code is fit for any purpose. 
 * Visit http://www.pragmaticprogrammer.com/titles/jkwatch for more book information.
***/
//
//  AppDelegate.m
//  tapalap
//
//  Created by Jeff Kelley on 2/27/15.
//  Copyright (c) 2015 Pragmatic Bookshelf. All rights reserved.
//


#import "AppDelegate.h"


@implementation AppDelegate

@synthesize healthStore = _healthStore;

#pragma mark - AppDelegate Lifecycle

- (HKHealthStore *)healthStore
{
    if (_healthStore == nil) {
        _healthStore = [[HKHealthStore alloc] init];
    }
    
    return _healthStore;
}

#pragma mark - UIApplicationDelegate Protocol Methods

- (BOOL)          application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    return YES;
}

- (void)           application:(UIApplication *)application
handleWatchKitExtensionRequest:(NSDictionary *)userInfo
                         reply:(void (^)(NSDictionary *))reply
{
    UIBackgroundTaskIdentifier backgroundIdentifier =
    [application beginBackgroundTaskWithExpirationHandler:^{ 
        [self replyToWatchKitRequestWithSuccess:NO
                                          error:nil
                                          reply:reply
                       backgroundTaskIdentifier:UIBackgroundTaskInvalid];
    }];
    
    NSDictionary *runToSave = userInfo[@"RunToSave"];
    
    if (runToSave != nil) {
        [self saveRunToHealthKit:runToSave 
                           reply:reply
        backgroundTaskIdentifier:backgroundIdentifier];
    }
    else {
        [self replyToWatchKitRequestWithSuccess:NO  
                                          error:nil
                                          reply:reply
                       backgroundTaskIdentifier:backgroundIdentifier];
    }
}

- (void)saveRunToHealthKit:(NSDictionary *)runToSave
                     reply:(void (^)(NSDictionary *))reply
  backgroundTaskIdentifier:(UIBackgroundTaskIdentifier)identifier;
{
    if (![HKHealthStore isHealthDataAvailable]) { 
        [self replyToWatchKitRequestWithSuccess:NO
                                          error:nil
                                          reply:reply
                       backgroundTaskIdentifier:identifier];
        return;
    }
    
    HKQuantity *runDistance = 
    [HKQuantity quantityWithUnit:[HKUnit meterUnit]
                     doubleValue:[runToSave[@"distance"] doubleValue]];
    
    NSDate *startDate = runToSave[@"startDate"];
    NSTimeInterval duration = [runToSave[@"duration"] doubleValue];
    NSDate *endDate = [startDate dateByAddingTimeInterval:duration];
    
    HKWorkout *workout =
    [HKWorkout workoutWithActivityType:HKWorkoutActivityTypeRunning
                             startDate:startDate
                               endDate:endDate
                              duration:duration
                     totalEnergyBurned:nil
                         totalDistance:runDistance
                              metadata:nil];
    
    __weak typeof(self) welf = self;
    
    [self.healthStore saveObject:workout 
                  withCompletion:^(BOOL success, NSError *error) {
                      // Samples can only be added after you save.
                      if (success) {
                          [welf addLapsFromDictionary:runToSave
                                            toWorkout:workout
                                      withRunDistance:runDistance
                                                reply:reply
                             backgroundTaskIdentifier:identifier];
                      }
                      else {
                          [welf replyToWatchKitRequestWithSuccess:success
                                                            error:error
                                                            reply:reply
                                         backgroundTaskIdentifier:identifier];
                      }
                  }];
}

- (void)addLapsFromDictionary:(NSDictionary *)runToSave
                    toWorkout:(HKWorkout *)workout
              withRunDistance:(HKQuantity *)runDistance
                        reply:(void (^)(NSDictionary *))reply
     backgroundTaskIdentifier:(UIBackgroundTaskIdentifier)identifier
{
    NSArray *laps = runToSave[@"laps"];
    
    if ([laps count] == 0) {
        [self replyToWatchKitRequestWithSuccess:NO
                                          error:nil
                                          reply:reply
                       backgroundTaskIdentifier:identifier];
        return;
    }
    
    NSMutableArray *samples = [[NSMutableArray alloc] init];
    
    HKQuantity *distance = 
    [HKQuantity quantityWithUnit:[HKUnit meterUnit]
                     doubleValue:([runToSave[@"distance"] doubleValue] /
                                  [laps count])];
    
    NSDate *startDate = runToSave[@"startDate"];
    
    HKQuantityType *distanceType =  
    [HKObjectType quantityTypeForIdentifier:
     HKQuantityTypeIdentifierDistanceWalkingRunning];
    
    for (NSNumber *duration in laps) {
        NSDate *endDate = [startDate dateByAddingTimeInterval:  
                           [duration doubleValue]];
        
        HKQuantitySample *sample =  
        [HKQuantitySample quantitySampleWithType:distanceType
                                        quantity:distance
                                       startDate:startDate
                                         endDate:endDate];
        
        [samples addObject:sample];
        
        // The next lap begins when this one ends.
        startDate = endDate;
    }
    
    __weak typeof(self) welf = self;
    
    [self.healthStore addSamples:samples  
                       toWorkout:workout
                      completion:^(BOOL success,
                                   NSError *error) {
                          [welf replyToWatchKitRequestWithSuccess:success  
                                                            error:error
                                                            reply:reply
                                         backgroundTaskIdentifier:identifier];
                      }];
}

- (void)replyToWatchKitRequestWithSuccess:(BOOL)success
                                    error:(NSError *)error
                                    reply:(void (^)(NSDictionary *))reply
                 backgroundTaskIdentifier:(UIBackgroundTaskIdentifier)identifier
{
    NSMutableDictionary *replyInfo = 
    [[NSMutableDictionary alloc] init];
    
    replyInfo[@"Success"] = @(success);
    
    if (error != nil) {
        replyInfo[@"Error"] = [error localizedDescription];
    } 
    
    reply(replyInfo); 
    
    if (identifier != UIBackgroundTaskInvalid) {
        // Wait two seconds before ending the background task to give WatchKit
        // time to communicate with the device.
        dispatch_time_t twoSecondsFromNow = dispatch_time(DISPATCH_TIME_NOW,
                                                          2 * NSEC_PER_SEC);
        
        dispatch_after(twoSecondsFromNow, dispatch_get_main_queue(), ^{ 
            [[UIApplication sharedApplication] endBackgroundTask:identifier]; 
        });
    }
}

#pragma mark -

@end
