Today's Menu  Portugal
journal and plan nutrition
Z5LocalDataController.m
Go to the documentation of this file.
1 //
2 // Z5LocalDataController.m
3 // TodaysMenu
4 //
5 // Created by Don Zeek on 12/9/15.
6 // Copyright © 2015 net.dzeek.y2015.ios.portfolio. All rights reserved.
7 //
8 
9 #import <CoreData/CoreData.h>
10 #import <HealthKit/HealthKit.h>
11 
12 #import "Z5DataController.h"
13 
15 #import "Z5GmailDataListener.h"
16 
17 static NSString *componentNameKey;
18 static NSString *componentValueKey;
19 static NSString *componentSampleKey;
20 static NSString *componentAuthorityKey;
21 static NSString *componentAuthorityDateKey;
22 static NSString *componentHKComponentKey;
23 
24 @implementation Z5LocalDataController
25 {
26  id<Z5HealthConnectionProtocol> healthConnectDelegate;
27 }
28 
29 @synthesize managedObjectContext = _managedObjectContext;
30 @synthesize managedObjectModel = _managedObjectModel;
31 @synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
32 
33 NSString* showTheaterMenu = @"show-theater-list";
34 NSString* showTheaterItem = @"zeroscene-theaterdetail";
35 NSString* showTheaterVersion1 = @"show-molecule-randomkey";
36 NSString* showCurrentScene = @"show-current-scene";
37 NSString* healthDataAuthority = @"healthDataAuthorization";
38 NSString* proposedMenuItemList = @"proposed-todays-menu";
39 NSString* healthkitNutritionKey = @"healthkit-nutrition-key";
40 NSString* healthkitNutritionValidated = @"health-nutrition-validated";
41 NSString* healthkitNutritionAuthorized = @"healthkit-nutrition-authorized";
42 NSString* healthKitAuthorityKey = @"health-kit-authority-key";
43 
44 NSOperationQueue *healthKitOpQueue;
45 /*
46  the following dictionary currently has an NSNumber is each key:hkQuantityName - to be changed to each entry being a dictionary,
47  with the authoriation status, and a date for the last change.
48  */
49 NSMutableDictionary *healthKitNutritionAuthorityDict;
50 
51 HKQuantityTypeIdentifier nutritionTypes[40];
53 
57 UIColor *wheatBackground;
58 
60 //Meal *_todaysMeal;
61 
62 //NSMutableArray *localDataListeners;
63 
64 + (NSString *)componentNameKey
65 {
66  return componentNameKey;
67 }
68 + (NSString *)componentValueKey
69 {
70  return componentValueKey;
71 }
72 + (NSString *)componentSampleKey
73 {
74  return componentSampleKey;
75 }
76 + (NSString *)componentAuthorityKey
77 {
78  return componentAuthorityKey;
79 }
81 {
83 }
85 {
87 }
89 {
90  return panelBackgroundColor;
91 }
93 {
94  return menuHeaderBackground;
95 }
97 {
99 }
100 + (UIColor *)wheatBackground
101 {
102  return wheatBackground;
103 }
104 + (UIColor *) colorForAuthority: (NSNumber *) authorityValue
105 {
106  UIColor *ret;
108  switch ([authorityValue integerValue]) {
109  case HKAuthorizationStatusSharingAuthorized:
110  ret = [z5Data healthKitParamSharedColor];
111  break;
112  case HKAuthorizationStatusNotDetermined:
113  ret = [z5Data healthKitParamNotQueried];
114  break;
115  case HKAuthorizationStatusSharingDenied:
116  ret = [z5Data healthKitParamDeniedAuthColor];
117  break;
118  case HKErrorAuthorizationDenied:
119  ret = [z5Data healthKitParamDeniedAuthColor];
120  break;
121  case HKErrorAuthorizationNotDetermined:
122  ret = [z5Data healthKitParamNotQueried];
123  break;
124  }
125  return ret;
126 }
127 + (NSString *) captionForAuthority: (NSNumber *) authorityValue
128 {
129  NSString *ret;
130  // Z5LocalDataController *localData = [[Z5DataController sharedInstance] localDataController];
131  switch ([authorityValue integerValue]) {
132  case HKAuthorizationStatusSharingAuthorized:
133  // NSLog(@"Z5LocalDataController.colorForAuthority: HKAuthorizationStatusSharingAuthorized");
134  ret = @"sharing authorized";
135  break;
136  case HKAuthorizationStatusNotDetermined:
137  // NSLog(@"Z5LocalDataController.colorForAuthority: HKAuthorizationStatusNotDetermined");
138  ret = @"status not determined";
139  break;
140  case HKAuthorizationStatusSharingDenied:
141  // NSLog(@"Z5LocalDataController.colorForAuthority: HKAuthorizationStatusSharingDenied");
142  ret = @"Sharing denied";
143  break;
144  case HKErrorAuthorizationDenied:
145  // NSLog(@"Z5LocalDataController.colorForAuthority: HKErrorAuthorizationDenied");
146  ret = @"authorization denied";
147  break;
148  case HKErrorAuthorizationNotDetermined:
149  // NSLog(@"Z5LocalDataController.colorForAuthority: HKErrorAuthorizationNotDetermined");
150  ret = @"authorization not determined";
151  break;
152  }
153  return ret;
154 }
155 - (id) init
156 {
157  self = [super init];
158 
159  self.availableNutritionParamArray = [self establishNutritionParameters];
160  healthKitOpQueue = [[NSOperationQueue alloc] init];
161  [healthKitOpQueue setMaxConcurrentOperationCount:36];
162  healthKitNutritionAuthorityDict = [NSMutableDictionary dictionaryWithCapacity:50];
163  [self initNutritionTypes];
164 
165  componentNameKey = @"component-type";
166  componentValueKey = @"component-value";
167  componentSampleKey = @"component-sample";
168  componentAuthorityKey = @"component-HKauthority";
169  componentAuthorityDateKey = @"component-HKauthority-date";
170  componentHKComponentKey = @"component-HKcomponent";
171  panelBackgroundColor = [UIColor colorWithHue:0.15 saturation:0.4 brightness:0.6 alpha:1.0];
172  // menuHeaderBackground = [UIColor colorWithWhite:0.75 alpha:1.0f];
173  menuContentsBackground = [UIColor colorWithRed:0.9351 green:0.8945 blue:0.7421 alpha:1.0];
174  // menuContentsBackground = [UIColor colorWithWhite:0.9 alpha:1.0f];
175  menuHeaderBackground = [UIColor colorWithRed:0.91 green:0.789 blue:0.4843 alpha:1.0];
176  menuContentsBackground = [UIColor colorWithRed:245.0/255.0 green:222.0/255.0 blue:179.0/255.0 alpha:1.0];
177 /*
178  panelBackgroundColor = [UIColor colorWithRed:244/256 green:229/256 blue:190/256 alpha:1];
179  menuHeaderBackground = [UIColor colorWithRed:233/256 green:202/256 blue:124/256 alpha:1];
180  */
181  currentMenuItemGalleryPositions.location = 10;
183  _todaysMeal = nil;
184 
185 // localDataListeners = [[NSMutableArray alloc] initWithCapacity:10];
186 
187  return self;
188 }
189 
190 - (void) logGallery: (NSNumber *)galleryChoice caption: (NSString *) caption
191 {
192  NSLog(@"Z5LocalDataController.logGallery: %@ caption: %@", galleryChoice, caption);
193  // NSNumber *galleryChoice = [NSNumber numberWithInt:1];
194  switch ([galleryChoice integerValue]) {
195  case 0:
196  {
197  NSArray *localDataMenuItems = [self retrieveAllMenuItems:galleryChoice];
198  for (MenuItem *mItem in localDataMenuItems) {
199  NSLog(@"Z5LocalDataController.logGallery: mItem-name: %@", mItem.name);
200  }
201  }
202  break;
203  case 1:
204  {
205  NSArray *localDataMeals = [self retrieveAllMeals:galleryChoice];
206  for (Meal *mItem in localDataMeals) {
207  NSLog(@"Z5LocalDataController.logGallery: meal: %@", mItem);
208  }
209  }
210  break;
211  default:
212  NSLog(@"Z5LocalDataController.logGallery: %@", galleryChoice);
213  }
214 }
215 
219 - (void)saveContext
220 {
221  NSError *error = nil;
222  NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
223  if (managedObjectContext != nil) {
224  if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
225  // Replace this implementation with code to handle the error appropriately.
226  // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
227  NSLog(@"Z5LocalDataController.saveContext: Unresolved error %@, %@", error, [error userInfo]);
228  abort();
229  }
230  }
231 
232  NSLog(@"Z5LocalDataController.saveContext: write user prefs");
236 }
237 
238 
239 
240 #pragma mark - Core Data stack
241 
246 - (NSManagedObjectContext *)managedObjectContext
247 {
248  if (_managedObjectContext != nil) {
249  return _managedObjectContext;
250  }
251 
252  NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
253  if (coordinator != nil) {
254  // _managedObjectContext = [[NSManagedObjectContext alloc] init];
255  _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
256  [_managedObjectContext setPersistentStoreCoordinator:coordinator];
257  }
258  return _managedObjectContext;
259 }
260 
265 - (NSManagedObjectModel *)managedObjectModel
266 {
267  if (_managedObjectModel != nil) {
268  return _managedObjectModel;
269  }
270 
271  NSBundle *mainb = [NSBundle mainBundle];
272 
273  // NSLog(@"LocalData.managedObjectModel: mainb resourceURL: %@", [mainb resourceURL]);
274 
275  NSURL *modelURL = [mainb URLForResource:@"nutritionMenuModel" withExtension:@"momd"];
276  _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
277  return _managedObjectModel;
278 }
279 
284 - (NSPersistentStoreCoordinator *)persistentStoreCoordinator
285 {
286  if (_persistentStoreCoordinator != nil) {
287  return _persistentStoreCoordinator;
288  }
289 
290  NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"ProjectName.sqlite"];
291 
292  NSError *error = nil;
293  _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
294  NSDictionary *options = @{
295  NSMigratePersistentStoresAutomaticallyOption : @YES,
296  NSInferMappingModelAutomaticallyOption: @YES
297  };
298  if (![_persistentStoreCoordinator
299  addPersistentStoreWithType:NSSQLiteStoreType
300  configuration:nil
301  URL:storeURL options:options
302  error:&error]) {
303  /*
304  Replace this implementation with code to handle the error appropriately.
305 
306  abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
307 
308  Typical reasons for an error here include:
309  * The persistent store is not accessible;
310  * The schema for the persistent store is incompatible with current managed object model.
311  Check the error message to determine what the actual problem was.
312 
313  If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory.
314 
315  If you encounter schema incompatibility errors during development, you can reduce their frequency by:
316  * Simply deleting the existing store:
317  [[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil]
318 
319  * Performing automatic lightweight migration by passing the following dictionary as the options parameter:
320  @{NSMigratePersistentStoresAutomaticallyOption:@YES, NSInferMappingModelAutomaticallyOption:@YES}
321 
322  Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.
323 
324  */
325  NSLog(@"Z5LocalDataController.persistentStoreCoordinator: Unresolved error %@, %@", error, [error userInfo]);
326  // abort();
327  // [[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil];
328  }
329 
330  return _persistentStoreCoordinator;
331 }
332 
333 
334 #pragma mark - Meal Data
335 - (NSArray<Meal *> *) findMealsWithDate: (NSDate *)findDate
336 {
337  NSArray<Meal *> *ret = [Meal findMealsWithDate:findDate context:[self managedObjectContext]];
338 
339  return ret;
340 }
341 - (NSArray<Meal *> *) findMealsThisMonthDate: (NSDate *)findDate
342 {
343  NSArray<Meal *> *ret = [Meal findMealsByMonth:findDate context:[self managedObjectContext]];
344 
345  return ret;
346 }
347 - (NSArray<Meal *> *) retrieveAllMeals: (NSNumber *)galleryNo
348 {
349  NSLog(@"Z5LocalDataController.retrieveAllMeals: gallery: %@", galleryNo);
350 
351  NSArray<Meal *> *ret = [Meal retrieveAllMealsForGallery: (NSNumber *) galleryNo context:[self managedObjectContext]];
352 
353  NSLog(@"Z5LocalDataController.retrieveAllMeals: meals retrieved: %lu", (unsigned long)[ret count]);
354 
355  return ret;
356 }
357 
358 - (void) eraseMealsThisMonthDate: (NSDate *)findDate
359 {
361 }
362 
363 - (NSArray<Meal *> *) findOrCreateMealWithDate: (NSDate *)findDate
364 {
365  NSArray<Meal *> *ret = [Meal findOrCreateMealWithDate:findDate context:[self managedObjectContext]];
366  NSLog(@"Z5LocalDataController.findOrCreateMealWithDate: returning %lu meal(s)", (unsigned long)[ret count]);
367  return ret;
368 }
369 - (Boolean) removeMealWithRandomkey: (NSString *)removeKey
370 {
372 
373  return YES;
374 }
375 - (void) todaysMealRequested: (NSDate *)date
376 {
377  NSArray<Meal *> *dailyMeal = [self findOrCreateMealWithDate: date];
378  _todaysMeal = [dailyMeal lastObject];
379  NSArray<MenuItem *> *todaysMenuItems = [self todaysMenuItems];
380  _todaysMeal.containedItem = [NSSet setWithArray:todaysMenuItems];
381  _todaysMeal.orderDate = date;
382  _todaysMeal.randomkey = [Z5DataController produceRandomkey];
383 
384  [_todaysMenuItems removeAllObjects];
385  _todaysMenuItems = nil;
386 }
387 
388 - (void) todaysMealConsumed: (NSDate *)date forDelegate: (id<Z5HealthConnectionProtocol>)jingo
389 {
390  [self goHealthData:[self todaysMenuComponents] forDelegate:jingo];
391 
392  // instead of right-now, take meal date from date-picker
393  // NSDate *rightNow = [NSDate dateWithTimeIntervalSinceNow:0];
394 
395  // mmm
396 
397 /*
398  NSArray<Meal *> *dailyMeal = [self findOrCreateMealWithDate: date];
399  Meal *meal = [dailyMeal lastObject];
400  NSArray<MenuItem *> *todaysMenuItems = [self todaysMenuItems];
401  meal.containedItem = [NSSet setWithArray:todaysMenuItems];
402  */
403  _todaysMeal.consumeDate = date;
404  NSLog(@"Z5LocalDataController.todaysMealConsumed: rating: %3.2f", [_todaysMeal.rating floatValue]);
405 
406 }
407 - (void) todaysMealRated: (float)rating
408 {
409  NSNumber *ratingNumber = [NSNumber numberWithFloat:rating];
410  [_todaysMeal setRating:ratingNumber];
411 }
412 
414 {
415  NSLog(@"Z5LocalDataController.todaysMealSkipped: _todaysMeal: %@", _todaysMeal);
416  if (_todaysMeal) {
418  }
419 }
421 {
422  NSString *removeKey = [_todaysMeal randomkey];
423  [self removeMealWithRandomkey:removeKey];
424 }
425 - (NSDate *) toLocalTime: (NSDate *)grenwich
426 {
427  NSCalendar *gregorian = [[NSCalendar alloc]
428  initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
429  NSDateComponents *dayComponents =
430  [gregorian components:(NSCalendarUnitDay |
431  NSCalendarUnitMonth |
432  NSCalendarUnitYear) fromDate:grenwich];
433  NSInteger day = [dayComponents day];
434  NSInteger month = [dayComponents month];
435  NSInteger year = [dayComponents year];
436 
437  NSCalendar *calendar = [NSCalendar currentCalendar];
438  [calendar setTimeZone: [NSTimeZone systemTimeZone]];
439 
440  // Specify the date components manually (year, month, day, hour, minutes, etc.)
441  NSDateComponents *timeZoneComps=[[NSDateComponents alloc] init];
442  [timeZoneComps setSecond:0];
443  [timeZoneComps setMinute:0];
444  [timeZoneComps setHour:0];
445  [timeZoneComps setDay:day];
446  [timeZoneComps setMonth:month];
447  [timeZoneComps setYear:year];
448  [timeZoneComps setSecond:0];
449 
450  NSDate *ret = [calendar dateFromComponents:timeZoneComps];
451 
452  return ret;
453 }
454 
455 #pragma mark - MenuItem Data
456 - (MenuItem *) findMenuItemWithRandomkey: (NSString *)randomkey
457 {
460 
461  return ret;
462 }
463 
464 
465 - (MenuItem *) findOrCreateMenuItemWithRandomkey: (NSString *)randomkey
466 {
469  NSLog(@"Z5LocalDataController.findOrCreateMenuItemWithRandomkey: randomkey: %@ name: %@", randomkey, [ret name]);
470 
471  ret.galleryPositionNo = [NSNumber numberWithLong:[self getNextGalleryPositionIdx]];
472  ret.galleryNumber = [NSNumber numberWithLong:1];
473 
474  return ret;
475 }
476 - (MenuItem *) findMenuItemWithFileIdentification: (NSString *)googlefileid
477 {
480 
481  return ret;
482 }
483 - (MenuItem *) findOrCreateMenuItemWithFileIdentification: (NSString *)googlefileid
484 {
486  if (!ret.randomkey) {
488  ret.galleryPositionNo = [NSNumber numberWithLong:[self getNextGalleryPositionIdx]];
489  ret.galleryNumber = [NSNumber numberWithLong:1];
490  }
491  return ret;
492 }
493 
494 - (NSArray<MenuItem *> *) retrieveAllMenuItems: (NSNumber *)galleryNo
495 {
496  NSArray<MenuItem *> *ret = [MenuItem retrieveAllMenuItemsForGallery: (NSNumber *) galleryNo context:[self managedObjectContext]];
497 
498 
499  return ret;
500 }
501 - (void) removeMenuItemWithKey:(NSString *)moleculekey fromTree:(NSDictionary *)tree
502 {
503 
504  // NSString *moleculeKey; // need key from tree when molecule found
505  // this call works on the common theater list, not the local list
506 
507 
508  // --todo- [self removeMenuItemKey:moleculekey fromTheaterList:tree];
509 
510 
511 
512  // [self.managedObjectContext deleteObject:molecule];
513  [self saveContext];
514 }
515 
516 - (MenuItem *) findNextMenuItemForGallery: (NSNumber *) galleryNo afterPosition: (NSNumber *) positionInGallery
517 {
518  MenuItem *ret = [MenuItem findNextMenuItemForGallery: (NSNumber *) galleryNo afterPosition: (NSNumber *) positionInGallery context:[self managedObjectContext]];
519 
520  return ret;
521 }
523 {
526  return currentMenuItemGalleryPositions.location;
527 
528 }
530 {
533 }
534 - (void) initGalleryPositionsRange: (NSRange) fetchAllRange
535 {
536  currentMenuItemGalleryPositions.location = fetchAllRange.location;
537  currentMenuItemGalleryPositions.length = fetchAllRange.length;
538 }
539 
540 - (void) logTodaysMenu: (NSString *) caption
541 {
542  NSLog(@"Z5LocalDataController.logTodaysMenu");
543  NSLog(@"%@(logTodaysMenu) count: %ld", caption, (unsigned long)[[self todaysMenuItems] count]);
544  for (MenuItem *mItem in [self todaysMenuItems]) {
545  // get a list of components for the menu item - json avail, use compiled products
546  NSLog(@"(logTodaysMenu) item: %@", mItem.name);
547 
548  NSArray<NSDictionary *> *todaysParameters = [self todaysMenuComponents];
549  // if there are parameters to check, go to local data for authorization
550  // to put in the health-kit database.
551  if (0 < [todaysParameters count]) {
552  // [localData goHealthData:todaysParameters forDelegate:self];
553  }
554  }
555  NSLog(@"Z5LocalDataController.logTodaysMenu: end");
556 }
557 
558 #pragma mark - JSON formatter
559 
560 - (NSString *)unitsForParameter:(NSString *)paramKeyStr
561 {
562  NSString *ret;
563  if ([paramKeyStr isEqualToString:@"sodium"]) {
564  ret = @"mg";
565  } else if ([paramKeyStr isEqualToString:@"total-fat"]) {
566  ret = @"grams";
567  } else {
568  ret = @"";
569  }
570  NSLog(@"Z5LocalDataController.unitsForParameter: WHAT IS HERE? key: %@ ret: %@", paramKeyStr, ret);
571  return ret;
572 }
573 
574 - (NSMutableDictionary *) mergeJsonForUsdaNumbers:(NSDictionary *)usdaDictionary inMenuItem:(MenuItem *)menuItem inContext:(UIView *) screen
575 {
576  NSMutableDictionary *ret = [[NSMutableDictionary alloc] initWithDictionary:[self jsonForUsdaNumbersInMenuItem:menuItem]];
577 
578  // for every entry in the incoming dictionary, check current menu
579  NSEnumerator *enumerator = [usdaDictionary keyEnumerator];
580  id key;
581  while ((key = [enumerator nextObject])) {
582  /* code that uses the returned key - sodium, total-fat*/
583  NSString *keyStr = (NSString *)key;
584  NSLog(@"Z5LocalDataController.mergeJsonForUsdaNumbers: keyStr: %@", keyStr);
585  id value = [usdaDictionary objectForKey:key];
586  if (![(NSString *)value isEqualToString:@""]) {
587  NSString *valueStr = [NSString stringWithFormat:@"%@%@",(NSString *)value, [self unitsForParameter:keyStr]];
588  [ret setObject:valueStr forKey:keyStr];
589  }
590  NSLog(@"Z5LocalDataController.mergeJsonForUsdaNumbers: ret: %@", ret);
591 
592  // if (value) {
593  // [Z5DataController showQuery:@"new or old" message:@"Which?"];
594  // }
595  }
596  // if parameter is not found, add
597  // if parameter is found, pop up a notice dialog 'new' or 'old'
598  // update or ignore as directed
599  return ret;
600 }
601 - (NSDictionary *) jsonForUsdaNumbersInMenuItem:(MenuItem *)menuItem
602 {
603  /*
604  * Existing data
605  */
606  // NSLog(@"Z5LocalDataController.jsonForUsdaNumbersInMenuItem: menuItem: %@", menuItem);
607  NSString *usdaNumbers = [menuItem usdaNumbers];
608  if (usdaNumbers) {
609  if (![usdaNumbers isEqualToString:@""]) {
610  NSData *existingUsdaNumbersData = [usdaNumbers dataUsingEncoding:NSUTF8StringEncoding];
611  NSError *err_init_json;
612  NSObject *extantUsdaJsonObj = [NSJSONSerialization JSONObjectWithData:existingUsdaNumbersData options:NSJSONReadingAllowFragments error:&err_init_json];
613  if (!err_init_json) {
614  if (extantUsdaJsonObj) {
615  if ([extantUsdaJsonObj isKindOfClass:[NSDictionary class]]) {
616 
617  // NSDictionary *jsonUsdaIn = (NSDictionary *)extantUsdaJsonObj;
618  // NSLog(@"Z5LocalDataController.jsonForUsdaNumbersInMenuItem: jsonUsdaIn: %@", jsonUsdaIn);
619 
620  return (NSDictionary *)extantUsdaJsonObj;
621  } else {
622  NSLog(@"Z5LocalDataController.jsonForUsdaNumbersInMenuItem: class: %@", NSStringFromClass([extantUsdaJsonObj class]));
623  return nil;
624  }
625  }
626  } else { // err_init_json YES
627  NSLog(@"Z5LocalDataController.vjsonForUsdaNumbersInMenuItem: err_init_json: %@", err_init_json);
628  NSLog(@"Z5LocalDataController.jsonForUsdaNumbersInMenuItem: usdaNumbers: %@", usdaNumbers);
629  }
630  } else {
631  NSLog(@"Z5LocalDataController.jsonForUsdaNumbersInMenuItem: no usdaNumbers");
632  }
633  } else {
634  NSLog(@"Z5LocalDataController.jsonForUsdaNumbersInMenuItem: nil usdaNumbers");
635  }
636  return nil;
637 }
638 #pragma mark - Health Kit
639 
642 - (void) setUseHealthKit:(Boolean)useHealthKit
643 {
644  if (useHealthKit) {
645  _usingHealthKit = [[NSNumber alloc] initWithBool:YES];
646  } else {
647  _usingHealthKit = [[NSNumber alloc] initWithBool:NO];
648  }
649  NSLog(@"LocalData.setUsingHealthKit: %@", _usingHealthKit);
650  if ([_usingHealthKit boolValue]) {
651 
653  [self setupHealthKit];
654 
656  }
657 }
664 {
665  if (self.healthStore) {
666  NSLog(@"LocalData.setupHealthKit: healthStore all ready set");
667  } else if ([HKHealthStore isHealthDataAvailable]) {
668  self.healthStore = [[HKHealthStore alloc] init];
669 
670  // do not pre-query anything, user to authorize as needed
671  // need to remove and reinstall to initialize testing
673  }
674 }
675 
676 - (void) getAddedAuthorizationToShare: (NSSet *)writeNutrTypes
677  forDelegate: (id<Z5HealthConnectionProtocol>) requestFrom
678 {
679  healthConnectDelegate = requestFrom;
680  [self.healthStore requestAuthorizationToShareTypes:writeNutrTypes
681  readTypes:writeNutrTypes
682  completion:^(BOOL success, NSError *error) {
683  if (!success) {
684  NSLog(@"Z5LocalDataController.getAddedAuthorizationToWrite: You didn't allow HealthKit to access these read/write data types. In your app, try to handle this error gracefully when a user decides not to provide access. The error was: %@", error);
685 
686  return;
687  } else {
688  NSLog(@"Z5LocalDataController.getAddedAuthorizationToShare: authorization success");
689 
690  dispatch_async(dispatch_get_main_queue(), ^{
691  // Update the user interface based on the current user's health information.
692  // with follow two lines: Unbalanced calls to begin/end appearance transitions for <UIViewController
693  // further - i even get unbalanced message without these lines
695  [self->healthConnectDelegate updateToAuthorizationOK];
696  });
697  }
698  }];
699  NSLog(@"Z5LocalDataController.getAddedAuthorizationToWrite: end");
700 }
706 {
707  // NSArray<HKQuantityTypeIdentifier> *qtyTypes
708  _hkQuantityTypes = [[NSArray alloc] initWithObjects:
709  HKQuantityTypeIdentifierDietaryBiotin,
710  HKQuantityTypeIdentifierDietaryCaffeine,
711  HKQuantityTypeIdentifierDietaryCalcium,
712  HKQuantityTypeIdentifierDietaryCarbohydrates,
713  HKQuantityTypeIdentifierDietaryChloride,
714  HKQuantityTypeIdentifierDietaryCholesterol,
715  HKQuantityTypeIdentifierDietaryChromium,
716  HKQuantityTypeIdentifierDietaryCopper,
717  HKQuantityTypeIdentifierDietaryEnergyConsumed,
718  HKQuantityTypeIdentifierDietaryFatMonounsaturated,
719  HKQuantityTypeIdentifierDietaryFatPolyunsaturated,
720  HKQuantityTypeIdentifierDietaryFatSaturated,
721  HKQuantityTypeIdentifierDietaryFatTotal,
722  HKQuantityTypeIdentifierDietaryFiber,
723  HKQuantityTypeIdentifierDietaryFolate,
724  HKQuantityTypeIdentifierDietaryIodine,
725  HKQuantityTypeIdentifierDietaryIron,
726  HKQuantityTypeIdentifierDietaryMagnesium,
727  HKQuantityTypeIdentifierDietaryManganese,
728  HKQuantityTypeIdentifierDietaryMolybdenum,
729  HKQuantityTypeIdentifierDietaryNiacin,
730  HKQuantityTypeIdentifierDietaryPantothenicAcid,
731  HKQuantityTypeIdentifierDietaryPhosphorus,
732  HKQuantityTypeIdentifierDietaryPotassium,
733  HKQuantityTypeIdentifierDietaryProtein,
734  HKQuantityTypeIdentifierDietaryRiboflavin,
735  HKQuantityTypeIdentifierDietarySelenium,
736  HKQuantityTypeIdentifierDietarySodium,
737  HKQuantityTypeIdentifierDietarySugar,
738  HKQuantityTypeIdentifierDietaryThiamin,
739  HKQuantityTypeIdentifierDietaryVitaminA,
740  HKQuantityTypeIdentifierDietaryVitaminB12,
741  HKQuantityTypeIdentifierDietaryVitaminB6,
742  HKQuantityTypeIdentifierDietaryVitaminC,
743  HKQuantityTypeIdentifierDietaryVitaminD,
744  HKQuantityTypeIdentifierDietaryVitaminE,
745  HKQuantityTypeIdentifierDietaryVitaminK,
746  HKQuantityTypeIdentifierDietaryWater,
747  HKQuantityTypeIdentifierDietaryZinc,
748  nil];
749 
750  nutritionTypeCount = [_hkQuantityTypes count];
751  for (int j = 0; j < nutritionTypeCount; j++) {
752  NSString *thisone = [_hkQuantityTypes[j] description];
753  // NSLog(@"LocalData.initNutritionTypes: thisone: %@", thisone);
754  nutritionTypes[j] = [[NSString alloc] initWithString:thisone];
755  }
756 }
757 
764 {
765  int notDetermined = 0;
766  int itemDenied = 0;
767  int itemAuthorized = 0;
768  for (int j = 0; j < nutritionTypeCount; j++) {
769 
770  NSString *hkQtypeString = nutritionTypes[j];
771  HKQuantityType *hkQtype = [HKObjectType quantityTypeForIdentifier:hkQtypeString];
772 
773  // NSNumber *previousAuthority = [healthKitNutritionAuthorityDict objectForKey:hkQtypeString];
774  HKAuthorizationStatus status = [self.healthStore authorizationStatusForType:hkQtype];
775  NSNumber *statusNumb = [NSNumber numberWithInt:status];
776  NSDate *freshAuthorityDate;
777 
778  NSMutableDictionary *knownAuthority = [healthKitNutritionAuthorityDict objectForKey:hkQtypeString];
779  // TODO: check for knownDict inadequat, check knownDict->value != 0
780  if (knownAuthority) {
781  NSNumber *previousAuthority = [knownAuthority objectForKey:@"value"];
782  NSDate *knownAuthorityDate = [knownAuthority objectForKey:@"data"];
783 
784  if ([statusNumb isEqualToNumber:previousAuthority]) {
785  // TODO: if 0 == 0, then freshDate = nil;
786  freshAuthorityDate = knownAuthorityDate;
787  } else {
788  // NSDate *authorityDate = [NSDate dateWithTimeIntervalSinceNow:0];
789  // [healthKitNutritionAuthorityDict setObject:authorityDate forKey:healthKitAuthorityKey];
790  NSLog(@"LocalData.validateHealthKitAuthority: old auth: %@ new auth: %@", previousAuthority, statusNumb);
791  freshAuthorityDate = [NSDate dateWithTimeIntervalSinceNow:0];
792  }
793  } else {
794  freshAuthorityDate = [NSDate dateWithTimeIntervalSinceNow:0];
795  }
796  NSDictionary *freshAuthorityDict = [[NSDictionary alloc] initWithObjectsAndKeys:statusNumb, @"value", freshAuthorityDate, @"date", nil];
797  // [knownAuthority setObject:statusNumb forKey:@"value"];
798  // [knownAuthority setObject:freshAuthorityDate forKey:@"date"];
799  // [healthKitNutritionAuthorityDict setObject:statusNumb forKey:hkQtypeString];
800  [healthKitNutritionAuthorityDict setObject:freshAuthorityDict forKey:hkQtypeString];
801 
802  switch (status) {
803  case HKAuthorizationStatusNotDetermined:
804  // NSLog(@"LocalData.validateHealthKitAuthority: %@ not determined", hkQtypeString);
805  notDetermined++;
806  break;
807  case HKAuthorizationStatusSharingDenied:
808  // NSLog(@"LocalData.validateHealthKitAuthority: %@ denied", hkQtypeString);
809  itemDenied++;
810  break;
811  case HKAuthorizationStatusSharingAuthorized:
812  // NSLog(@"LocalData.validateHealthKitAuthority: %@ authorized", hkQtypeString);
813  itemAuthorized++;
814  break;
815  } // end switch
816  } // end for
817  NSLog(@"LocalData.validateHealthKitAuthority: notDetermined: %d itemDenied: %d itemAuthorized: %d", notDetermined, itemDenied, itemAuthorized);
818 }
820 {
821  NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
822 
823  [userDefaults setObject:healthKitNutritionAuthorityDict forKey:healthKitAuthorityKey];
824 
825  [userDefaults synchronize];
826 
827 }
828 /*
829  * this method updates the global dictionary 'healthKitNutritionAuthorityDict'
830  * from user defaults.
831  */
833 {
834  NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
835 
836  [userDefaults synchronize];
837 
838  NSDictionary *hkUd = [userDefaults dictionaryForKey:healthKitAuthorityKey];
839 
840  NSLog(@"LocalData.getHealthKitAuthorityFromUserDefaults: prior on-board count: %ld user-defaults: %@", (unsigned long)[healthKitNutritionAuthorityDict count], hkUd);
841 
842  Boolean hkDictionaryEmpty = (0 == [healthKitNutritionAuthorityDict count]);
843  if (0 < [hkUd count]) {
844  for (int j = 0; j < nutritionTypeCount; j++) {
845  NSString *hkQtypeString = nutritionTypes[j].description;
846  // Boolean stat = NO;
847  NSDictionary *authorityInfo;
848  NSNumber *statNumb;
849  // HKQuantityType *hkQtype = [HKObjectType quantityTypeForIdentifier:hkQtypeString];
850  if (!hkDictionaryEmpty) {
851  // NSObject* priorAuthority = [healthKitNutritionAuthorityDict objectForKey:hkQtypeString];
852  authorityInfo = [healthKitNutritionAuthorityDict objectForKey:hkQtypeString];
853  statNumb = [authorityInfo objectForKey:@"@value"];
854  // statNumb = (NSNumber *)priorAuthority;
855  // stat = [priorAuthNumb boolValue];
856  }
857  // NSLog(@"LocalData.getHealthKitAuthorityFromUserDefaults: stat: %@", ( stat ? @"true" : @"false"));
858 
859  // NSObject* nextAuthority = [hkUd objectForKey:hkQtypeString];
860  // NSNumber *nextAuthNumb = (NSNumber *)nextAuthority; /* 0 - no query, 1 - denied, 2 - shared, ... */
861  NSMutableDictionary* userDefInfoDict = [hkUd objectForKey:hkQtypeString];
862  NSNumber *udAuthNumb = [userDefInfoDict objectForKey:@"value"]; /* 0 - no query, 1 - denied, 2 - shared, ... */
863  // Boolean next = [nextAuthNumb boolValue];
864  // NSLog(@"LocalData.getHealthKitAuthorityFromUserDefaults: next: %@", ( next ? @"true" : @"false"));
865 // RESTART HERE - healthKitNutritionAuthorityDict to be dictionary of dictionary, not auth values
866  if ((nil != udAuthNumb) && (nil != statNumb) && (![udAuthNumb isEqualToNumber:statNumb])) {
867  NSLog(@"LocalData.getHealthKitAuthorityFromUserDefaults: type: %@ updated: new auth: %@", hkQtypeString, udAuthNumb);
868  NSDate *authChangeDate = [NSDate dateWithTimeIntervalSinceNow:0];
869  [userDefInfoDict setObject:authChangeDate forKey:@"date"];
870 
871 // if (next && !stat) {
872 // NSLog(@"LocalData.getHealthKitAuthorityFromUserDefaults: adding %@:%@", hkQtypeString, ( next ? @"true" : @"false"));
873 // } else if (!next && stat) {
874 // NSLog(@"LocalData.getHealthKitAuthorityFromUserDefaults: removing %@", hkQtypeString);
875 // }
876  }
877  if (userDefInfoDict) {
878  // replace previous dictionary with dictionary from u/d, updated with date-of-change,
879  // if applicable
880  [healthKitNutritionAuthorityDict setObject:userDefInfoDict forKey:hkQtypeString];
881  }
882  }
883  } else {
884  NSLog(@"LocalData.getHealthKitAuthorityFromUserDefaults: no %@ dictionary entries in user defaults", healthKitAuthorityKey);
885  }
886 }
887 - (NSNumber *) askAgain: (HKQuantityType *) quantityType
888 {
889  __block NSNumber *statusFlag = [NSNumber numberWithBool:NO];
890  NSSet *writeDataTypes = [NSSet setWithObjects:quantityType, nil];
891  NSSet *readDataTypes = [[NSSet alloc] init];
892  [self.healthStore requestAuthorizationToShareTypes:writeDataTypes readTypes:readDataTypes completion:^(BOOL success, NSError *error) {
893  if (!success) {
894  NSLog(@"Z5LocalDataController.askAgain: The error was: %@", error);
895  return;
896  } else {
897  NSLog(@"Z5LocalDataController.askAgain: authorization success");
898  statusFlag = [NSNumber numberWithBool:YES];
899  }
900 
901  dispatch_async(dispatch_get_main_queue(), ^{
902  [self->healthConnectDelegate updateToAuthorizationOK];
903  // Update the user interface based on the current user's health information.
904  // this is inside a completion handler
905  /* [self updateUsersAgeLabel];
906  [self updateUsersHeightLabel];
907  [self updateUsersWeightLabel]; */
908  });
909  }];
910  return statusFlag;
911 }
912 
913 #pragma mark - HealthKit Permissions
914 
915 // Returns the types of data that Fit wishes to write to HealthKit.
916 - (NSSet *)dataTypesToWrite {
917 
918  __block NSMutableSet *retSet = [[NSMutableSet alloc] init];
919 
920  [healthKitNutritionAuthorityDict enumerateKeysAndObjectsUsingBlock:^(id key, id object, BOOL *stop) {
921  NSString *keyString = (NSString *)key;
922  NSNumber *objectNumber = (NSNumber *)object;
923  Boolean objBoolean = [objectNumber boolValue];
924  if (objBoolean) {
925  HKQuantityType *keyHkQtype = [HKObjectType quantityTypeForIdentifier:keyString];
926  [retSet addObject:keyHkQtype];
927  }
928  }];
929  // empty sets to check-authorization crashes app
930  if (0 == [retSet count]) {
931  HKQuantityType *sodiumType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietarySodium];
932  [retSet addObject:sodiumType];
933  }
934  return retSet;
935 }
936  - (NSArray<HKQuantityType *> *)typesForWriting
937 {
938  __block NSMutableArray *retArray = [[NSMutableArray alloc] init];
939  [healthKitNutritionAuthorityDict enumerateKeysAndObjectsUsingBlock:^(id key, id object, BOOL *stop) {
940  NSString *keyString = (NSString *)key;
941  NSNumber *objectNumber = (NSNumber *)object;
942  Boolean objBoolean = [objectNumber boolValue];
943  if (objBoolean) {
944  HKQuantityType *keyHkQtype = [HKObjectType quantityTypeForIdentifier:keyString];
945  [retArray addObject:keyHkQtype];
946  }
947  }];
948  return retArray;
949 }
950 - (NSArray<HKQuantityType *> *)allHkTypes
951 {
952  NSMutableArray<HKQuantityType *> *returHkArray = [[NSMutableArray alloc] init];
953 
954  for (NSString *param in [self establishNutritionParameters]) {
955  HKQuantityType *hkQtype = [HKObjectType quantityTypeForIdentifier:param];
956  [returHkArray addObject:hkQtype];
957  }
958  return returHkArray;
959 }
960 - (NSMutableArray<NSString *> *)establishNutritionParameters
961 {
962  NSMutableArray<NSString *> *availableNutritionParamArray = [[NSMutableArray alloc] init];
963 
964  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietarySodium];
965  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryBiotin];
966  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryCaffeine];
967  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryCalcium];
968  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryCarbohydrates];
969  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryChloride];
970  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryCholesterol];
971  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryChromium];
972  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryCopper];
973  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryEnergyConsumed];
974  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryFatMonounsaturated];
975  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryFatPolyunsaturated];
976  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryFatSaturated];
977  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryFatTotal];
978  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryFiber];
979  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryFolate];
980  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryIodine];
981  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryIron];
982  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryMagnesium];
983  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryManganese];
984  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryMolybdenum];
985  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryNiacin];
986  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryPantothenicAcid];
987  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryPhosphorus];
988  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryPotassium];
989  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryProtein];
990  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryRiboflavin];
991  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietarySelenium];
992  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietarySugar];
993  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryThiamin];
994  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryVitaminA];
995  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryVitaminB12];
996  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryVitaminB6];
997  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryVitaminC];
998  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryVitaminD];
999  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryVitaminE];
1000  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryVitaminK];
1001  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryWater];
1002  [availableNutritionParamArray addObject:HKQuantityTypeIdentifierDietaryZinc];
1003 
1005 }
1006 
1007 
1013 - (NSNumber *) checkTypeAuthorization: (HKQuantityType *) quantityType
1014 {
1015  bool doDebug = NO;
1016 
1017  NSString *hkQtypeString = quantityType.description;
1018  // NSNumber *knownAuthStatus = [healthKitNutritionAuthorityDict objectForKey:hkQtypeString];
1019  NSMutableDictionary *knownAuthStatusDict = [healthKitNutritionAuthorityDict objectForKey:hkQtypeString];
1020  NSNumber *knownAuthStatus = [knownAuthStatusDict objectForKey:@"value"];
1021  NSDate *knownAuthStatusDate = [knownAuthStatusDict objectForKey:@"date"];
1022  if (doDebug) NSLog(@"LocalData.checkTypeAuthorization: knownAuthStatus: for %@: %@", hkQtypeString, knownAuthStatus);
1023 // NSLog(@"LocalData.checkTypeAuthorization: healthKitNutritionAuthorityDict: %@", healthKitNutritionAuthorityDict);
1024  NSInteger knownAuthStatusInt = [knownAuthStatus integerValue];
1025  if (doDebug) NSLog(@"LocalData.checkTypeAuthorization: type: %@:previous auth: %ld, date: %@", hkQtypeString, (long)[knownAuthStatus integerValue], [knownAuthStatusDate description]);
1026 
1027 
1028  NSInteger authStatus = [self.healthStore authorizationStatusForType:quantityType];
1029 
1030  if (authStatus != knownAuthStatusInt) {
1031  if (doDebug) NSLog(@"LocalData.checkTypeAuthorization: AUTH CHANGE: was %ld now %ld", (long)knownAuthStatusInt, (long)authStatus);
1032  }
1033  switch (authStatus) {
1034  case HKAuthorizationStatusSharingAuthorized:
1035  if (doDebug) NSLog(@"Z5LocalDataController.checkTypeAuthorization: %@ HKAuthorizationStatusSharingAuthorized", [quantityType description]);
1036  break;
1037  case HKAuthorizationStatusNotDetermined:
1038  if (doDebug) NSLog(@"Z5LocalDataController.checkTypeAuthorization: %@ HKAuthorizationStatusNotDetermined", [quantityType description]);
1039  break;
1040  case HKAuthorizationStatusSharingDenied:
1041  if (doDebug) NSLog(@"Z5LocalDataController.checkTypeAuthorization: %@ HKAuthorizationStatusSharingDenied", [quantityType description]);
1042  break;
1043  case HKErrorAuthorizationDenied:
1044  if (doDebug) NSLog(@"Z5LocalDataController.checkTypeAuthorization: %@ HKErrorAuthorizationDenied", [quantityType description]);
1045  break;
1046  case HKErrorAuthorizationNotDetermined:
1047  if (doDebug) NSLog(@"Z5LocalDataController.checkTypeAuthorization: %@ HKErrorAuthorizationNotDetermined", [quantityType description]);
1048  break;
1049  }
1050  NSNumber *ret = [NSNumber numberWithInteger:authStatus];
1051  return ret;
1052 }
1053 
1054 // This method takes an array of dictionary items, one item per nutrition component,
1055 // dictionary elements are component-Name-Key (input to authority check), and
1056 // componen-Authority-key, added if it is not there already. The array and dictionary
1057 // input are simple, this is copied to mutable elements.
1058 //
1059 // Update: include the last authority change time. The array of dictionaries is saved to user-defaults
1060 // at synchronization.
1061 //
1062 - (NSMutableArray<NSMutableDictionary *> *) annotateAuthority:(NSArray *)componentArray
1063 {
1064 // // log authority-dictionary information
1065 // [healthKitNutritionAuthorityDict enumerateKeysAndObjectsUsingBlock:^(id key, id object, BOOL *stop) {
1066 // NSString *keyString = (NSString *)key;
1067 // NSNumber *objectNumber = (NSNumber *)object;
1068 // Boolean objBoolean = [objectNumber boolValue];
1069 // if (objBoolean) {
1070 // NSLog(@"LocalData.annotateAuthority: key: %@ Authorized", keyString);
1071 // } else {
1072 // NSLog(@"LocalData.annotateAuthority: key: %@ Denied", keyString);
1073 // }
1074 // }];
1075 // // END -- log authority-dictionary information
1076 
1077 
1078  NSMutableArray *ret = [[NSMutableArray alloc] init];
1079 
1080  for (NSDictionary *component in componentArray) {
1081  NSString *componentType = [component objectForKey:[Z5LocalDataController componentNameKey]];
1082  if (componentType) {
1083  NSString *fullyQualifiedCompoName = [@"HKQuantityTypeIdentifierDietary" stringByAppendingString:componentType];
1084  HKQuantityType *rowQuantityType = [HKObjectType quantityTypeForIdentifier:fullyQualifiedCompoName];
1085 
1086  // get new authority info
1087  NSNumber *shareOK = [self checkTypeAuthorization:rowQuantityType];
1088  NSMutableDictionary *withAuthMarkDict = [[NSMutableDictionary alloc] initWithDictionary:component];
1089  [withAuthMarkDict setValue:shareOK forKey:[Z5LocalDataController componentAuthorityKey]];
1090 
1091  NSDate *authorityDate = [NSDate dateWithTimeIntervalSinceNow:0]; // TODO
1092 
1093  [withAuthMarkDict setValue:authorityDate forKey:[Z5LocalDataController componentAuthorityDateKey]];
1094 
1095  [ret addObject:withAuthMarkDict];
1096  }
1097  }
1098  return ret;
1099 }
1100 
1101 #pragma mark - Writing HealthKit Data
1102 - (Boolean) goHealthData:(NSArray<NSDictionary *> *) parametersForHK forDelegate: (id<Z5HealthConnectionProtocol>)jingo
1103 {
1104  healthConnectDelegate = jingo;
1105 
1106  Boolean ret = [HKHealthStore isHealthDataAvailable];
1107  if (ret) {
1108  NSLog(@"LocalData.goHealthData: addMenuItemOnToday: HKHealthStore is available");
1109  [[[Z5DataController sharedInstance] localDataController] setupHealthKit];
1110 
1111  for (NSDictionary *datum in parametersForHK) {
1112  NSLog(@"LocalData.goHealthData: datum: %@", datum);
1113 
1114  NSString *nutriType = [datum objectForKey:[Z5LocalDataController componentNameKey]];
1115  NSString *hkTypeStr = [@"HKQuantityTypeIdentifierDietary" stringByAppendingString:nutriType];
1116  HKQuantityType *hkType = [HKQuantityType quantityTypeForIdentifier:hkTypeStr];
1117  HKUnit *massUnit = [HKUnit unitFromString:@"g"];
1118  HKUnit *energyUnit = [HKUnit unitFromString:@"cal"];
1119 
1120  HKUnit *hkUnit = nil;
1121  NSString *nutriValue = [datum objectForKey:componentValueKey];
1122  NSLog(@"LocalData.goHealthData: nutriValue: %@", nutriValue);
1123  NSArray<NSString *> *pieces = [nutriValue componentsSeparatedByString:@" "];
1124  // HKUnit *hkUnit = nil;
1125  float quantityScalar = [pieces[0] floatValue];
1126  if ([hkType isCompatibleWithUnit:energyUnit])
1127  {
1128  if ([@"cal" isEqualToString:pieces[1]]) {
1129  HKMetricPrefix microPrefix = HKMetricPrefixNone;
1130  hkUnit = [HKUnit jouleUnitWithMetricPrefix:microPrefix];
1131  }
1132  } else if ([hkType isCompatibleWithUnit:massUnit]){
1133  if ([@"mcg" isEqualToString:pieces[1]]) {
1134  HKMetricPrefix microPrefix = HKMetricPrefixMicro;
1135  hkUnit = [HKUnit gramUnitWithMetricPrefix:microPrefix];
1136  } else if ([@"mg" isEqualToString:pieces[1]]) {
1137  HKMetricPrefix milliPrefix = HKMetricPrefixMilli;
1138  hkUnit = [HKUnit gramUnitWithMetricPrefix:milliPrefix];
1139  }
1140  }
1141  HKQuantity *hkQuantity = [HKQuantity quantityWithUnit:hkUnit doubleValue:quantityScalar];
1142 
1143  NSDictionary *opQueueIn = [[NSDictionary alloc] initWithObjectsAndKeys:hkType, @"HKtype", hkQuantity, @"HKquantity", nil];
1144  [healthKitOpQueue addOperation:[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(tryHealthStore:) object:opQueueIn]];
1145 
1146  }
1147  [healthKitOpQueue waitUntilAllOperationsAreFinished];
1148  NSLog(@"LocalData.goHealthData: done waiting");
1149  }
1150  return ret;
1151 }
1152 
1153 - (void) tryHealthStore:(id)arg
1154 {
1155  NSDictionary *inputVars = arg;
1156 
1157  HKQuantityType *hkType = [inputVars objectForKey:@"HKtype"];
1158  HKQuantity *hkQuantity = [inputVars objectForKey:@"HKquantity"];
1159  [self saveQuantityToHealthStore:hkType amount:hkQuantity];
1160 }
1161 
1162 - (void) saveQuantityToHealthStore:(HKQuantityType *)quantityType amount:(HKQuantity *)quantityAmount
1163 {
1164  NSDate *now = [NSDate date];
1165  // Boolean isSuccess = NO;
1166  HKQuantitySample *quantitySample = [HKQuantitySample quantitySampleWithType:quantityType quantity:quantityAmount startDate:now endDate:now];
1167  NSInteger authStatus = [self.healthStore authorizationStatusForType:quantityType];
1168  NSString *quantityAuthority = @"none";
1169  switch (authStatus) {
1170  case HKAuthorizationStatusSharingAuthorized:
1171  NSLog(@"Z5LocalDataController.saveQuantityToHealthStore: HKAuthorizationStatusSharingAuthorized");
1172  quantityAuthority = @"HKAuthorizationStatusSharingAuthorized";
1173  break;
1174  case HKAuthorizationStatusNotDetermined:
1175  NSLog(@"Z5LocalDataController.saveQuantityToHealthStore: HKAuthorizationStatusNotDetermined");
1176  quantityAuthority = @"HKAuthorizationStatusNotDetermined";
1177  break;
1178  case HKAuthorizationStatusSharingDenied:
1179  NSLog(@"Z5LocalDataController.saveQuantityToHealthStore: HKAuthorizationStatusSharingDenied");
1180  quantityAuthority = @"HKAuthorizationStatusSharingDenied";
1181  break;
1182  case HKErrorAuthorizationDenied:
1183  NSLog(@"Z5LocalDataController.saveQuantityToHealthStore: HKErrorAuthorizationDenied");
1184  quantityAuthority = @"HKErrorAuthorizationDenied";
1185  break;
1186  case HKErrorAuthorizationNotDetermined:
1187  NSLog(@"Z5LocalDataController.saveQuantityToHealthStore: HKErrorAuthorizationNotDetermined");
1188  quantityAuthority = @"HKErrorAuthorizationNotDetermined";
1189  break;
1190  }
1191 
1192  NSLog(@"Z5LocalDataController.saveQuantityToHealthStore: type: %@ authority: %@ quantitySample: %@", quantityType, quantityAuthority, quantitySample);
1193 
1194  switch (authStatus) {
1195  case HKAuthorizationStatusSharingAuthorized:
1196  {
1197  [self.healthStore saveObject:quantitySample withCompletion:^(BOOL success, NSError *error) {
1198  if (!success) {
1199  NSLog(@"An error occured saving the quantity sample %@. In your app, try to handle this gracefully. The error was: %@.", quantitySample, error);
1200  // abort();
1201  NSLog(@"Z5LocalDataController.saveQuantityToHealthStore: ERR code: %ld", (long)error.code);
1202  return;
1203  }
1204  NSLog(@"Z5LocalDataController.saveQuantityToHealthStore: success with %@", quantityType);
1205  // [healthConnectDelegate healthQuantityTypeData:quantityType success:YES];
1206 // dispatch_async(dispatch_get_main_queue(), ^{
1207 // [healthConnectDelegate healthQuantityTypeData:quantityType success:YES];
1208 // });
1209  }];
1210  }
1211  break;
1212 /* case HKAuthorizationStatusNotDetermined:
1213  NSLog(@"Z5LocalDataController.saveQuantityToHealthStore: HKAuthorizationStatusNotDetermined");
1214  [healthConnectDelegate healthQuantityTypeData:quantityType success:NO];
1215  break;
1216  case HKAuthorizationStatusSharingDenied:
1217  NSLog(@"Z5LocalDataController.saveQuantityToHealthStore: HKAuthorizationStatusSharingDenied");
1218  [healthConnectDelegate healthQuantityTypeData:quantityType success:NO];
1219  break;
1220  case HKErrorAuthorizationDenied:
1221  NSLog(@"Z5LocalDataController.saveQuantityToHealthStore: HKErrorAuthorizationDenied");
1222  [healthConnectDelegate healthQuantityTypeData:quantityType success:NO];
1223  break;
1224  case HKErrorAuthorizationNotDetermined:
1225  NSLog(@"Z5LocalDataController.saveQuantityToHealthStore: HKErrorAuthorizationNotDetermined");
1226  [healthConnectDelegate healthQuantityTypeData:quantityType success:NO];
1227  break;
1228  */
1229  }
1230 }
1231 
1232 + (HKQuantity *) hkQuantityForString: (NSString *) quantityDescript
1233 {
1234  NSArray<NSString *> *pieces = [quantityDescript componentsSeparatedByString:@" "];
1235  HKUnit *hkUnit = nil;
1236  float quantityScalar = [pieces[0] floatValue];
1237  // NSLog(@"Z5LocalDataController.hkQuantityForString: quantityScalar: %3.2f", quantityScalar);
1238 
1239  if ([@"mcg" isEqualToString:pieces[1]]) {
1240  HKMetricPrefix microPrefix = HKMetricPrefixMicro;
1241  hkUnit = [HKUnit gramUnitWithMetricPrefix:microPrefix];
1242  } else if ([@"mg" isEqualToString:pieces[1]]) {
1243  HKMetricPrefix milliPrefix = HKMetricPrefixMilli;
1244  hkUnit = [HKUnit gramUnitWithMetricPrefix:milliPrefix];
1245  }
1246  HKQuantity *hkQuantity = [HKQuantity quantityWithUnit:hkUnit doubleValue:quantityScalar];
1247  //double quantDbl = [hkQuantity doubleValueForUnit:[HKUnit gramUnit]];
1248  //NSLog(@"Z5LocalDataController.hkQuantityForString: quantDbl: %f", quantDbl);
1249 
1250  return hkQuantity;
1251 }
1252 
1253 #pragma mark - Email Credentials / User Defaults
1254 
1256 {
1257  NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
1258 
1259 // NSString *enteredUsername = [[Z5DataController sharedInstance] remoteDataController].emailDataController.username;
1260 // [userDefaults setObject:enteredUsername forKey:@"username"];
1261 // NSString *enteredPassword = [[Z5DataController sharedInstance] remoteDataController].emailDataController.password;
1262 // [userDefaults setObject:enteredPassword forKey:@"password"];
1263 
1264  [userDefaults synchronize];
1265 
1266 }
1268 {
1269  // NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
1270 
1271 // [[Z5DataController sharedInstance] remoteDataController].emailDataController.username = [userDefaults stringForKey:@"username"];
1272 // [[Z5DataController sharedInstance] remoteDataController].emailDataController.password = [userDefaults stringForKey:@"password"];
1273 
1274 }
1275 
1276 #pragma mark - EmailMessage Data
1277 //- (EmailMessage *) findEmailMessageWithRandomkey: (NSString *)randomkey
1278 //{
1279 // NSLog(@"LocalData.findEmailMessageWithRandomkey");
1280 // EmailMessage *ret = [EmailMessage findEmailMessageWithKey:randomkey
1281 // context:[self managedObjectContext]];
1282 //
1283 // return ret;
1284 //}
1285 
1286 // - (EmailMessage *) findOrCreateEmailMessageWithRandomkey: (NSString *)randomkey
1287 // {
1288 // NSLog(@"LocalData.findOrCreateEmailMessageWithRandomkey");
1289 // EmailMessage *ret = [EmailMessage findOrCreateEmailMessageWithRandomkey:randomkey
1290 // context:[self managedObjectContext]];
1291 //
1292 // return ret;
1293 // }
1294 // - (EmailMessage *) findOrCreateEmailMessageWithUID: (NSNumber *)uidkey
1295 // {
1296 // NSLog(@"LocalData.findOrCreateEmailMessageWithUID");
1297 // EmailMessage *ret = [EmailMessage findOrCreateEmailMessageWithUID:uidkey
1298 // context:[self managedObjectContext]];
1299 //
1300 // return ret;
1301 // }
1302 - (EmailMessage *) findOrCreateEmailMessageWithFileIdentification: (NSString *)googlefileid
1303 {
1304  NSLog(@"LocalData.findEmailMessageWithFileIdentification");
1306  context:[self managedObjectContext]];
1307 
1308  return ret;
1309 }
1310 - (EmailMessage *) findEmailMessageWithFileIdentification:(NSString *) googlefileid
1311 {
1312  NSArray *msgs = [EmailMessage emailMessageWithFileid:googlefileid
1313  context:[self managedObjectContext]];
1314  EmailMessage *ret;
1315  if (nil == msgs) {
1316  ret = nil;
1317  } else {
1318  ret = [msgs objectAtIndex:0];
1319  }
1320  return ret;
1321 }
1323 {
1324 
1325  NSManagedObjectContext *moc = [self managedObjectContext];
1326  NSEntityDescription *entityDescription = [NSEntityDescription
1327  entityForName:@"EmailMessage" inManagedObjectContext:moc];
1328  NSFetchRequest *request = [[NSFetchRequest alloc] init];
1329  [request setEntity:entityDescription];
1330 
1331  NSError *error;
1332  NSArray *objects = [self.managedObjectContext executeFetchRequest:request error:&error];
1333 
1334  return objects;
1335 }
1336 //- (void) removeEmailMessageWithKey:(NSString *)moleculekey fromTree:(NSDictionary *)tree
1337 //{
1338 //
1339 // // NSString *moleculeKey; // need key from tree when molecule found
1340 // // this call works on the common theater list, not the local list
1341 //
1342 //
1343 // // --todo- [self removeEmailMessageKey:moleculekey fromTheaterList:tree];
1344 //
1345 //
1346 //
1347 // // [self.managedObjectContext deleteObject:molecule];
1348 // [self saveContext];
1349 //}
1350 
1351 - (Boolean) deleteEmailMessageWithFileIdentification:(NSString *)googlefileid
1352 {
1354  context:[self managedObjectContext]];
1355 }
1356 - (BOOL) fetchEmails {
1357  NSManagedObjectContext *context = [self managedObjectContext];
1358  NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
1359  // Configure the request's entity, and optionally its predicate.
1360  NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:YES];
1361  NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
1362  [fetchRequest setSortDescriptors:sortDescriptors];
1363 
1364  NSFetchedResultsController *controller = [[NSFetchedResultsController alloc]
1365  initWithFetchRequest:fetchRequest
1366  managedObjectContext:context
1367  sectionNameKeyPath:nil
1368  cacheName:@"TodaysMenu"];
1369  NSError *error;
1370  BOOL success = [controller performFetch:&error];
1371  return success;
1372 }
1373 
1374 
1375 #pragma mark - Write Defaults
1376 
1378 {
1379  NSNumber *galleryChoice = [NSNumber numberWithInt:1];
1380  NSArray *objects = [self retrieveAllMenuItems:galleryChoice];
1381  for (NSManagedObject *menuItem in objects) {
1382  MenuItem *dbMenuItem = (MenuItem *)menuItem;
1383  NSLog(@"RemoteData.fillMenuItemList: menuItem into list: %@", [dbMenuItem name]);
1384  }
1385 }
1386 - (void) putMenuItemOnToday: (MenuItem *)focusMenuItem
1387 {
1388  if (!focusMenuItem) {
1389  NSLog(@"Z5LocalData.putMenuItemOnToday: FAIL, nil input");
1390  return;
1391  }
1392  if (!_todaysMenuItems) {
1393  _todaysMenuItems = [[NSMutableArray alloc] init];
1394  NSLog(@"Z5LocalData.putMenuItemOnToday: todays-menu-items array created");
1395  }
1396  [_todaysMenuItems addObject:focusMenuItem];
1397 }
1399 {
1400  NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
1401 
1402  NSMutableArray *menuItemKeys = [[NSMutableArray alloc] init];
1403  for (NSManagedObject *menuItem in _todaysMenuItems) {
1404  MenuItem *dbMenuItem = (MenuItem *)menuItem;
1405  [menuItemKeys addObject:[dbMenuItem randomkey]];
1406  // NSLog(@"RemoteData.fillMenuItemList: menuItem into list: %@", [dbMenuItem name]);
1407  }
1408  [userDefaults setObject:menuItemKeys forKey:proposedMenuItemList];
1409 
1410  [userDefaults synchronize];
1411 }
1413 {
1414  _todaysMeal = nil;
1415 }
1417 {
1418  NSLog(@"Z5LocalData.clearTodaysMenuItems");
1419  [_todaysMenuItems removeAllObjects];
1420 }
1421 - (NSArray<NSDictionary *> *) mealComponents: (Meal *)meal
1422 {
1423  NSMutableArray<NSDictionary *> *totals = [[NSMutableArray alloc] init];
1424  for (MenuItem *mItem in [meal containedItem]) {
1425  // get a list of components for the menu item - json avail, use compiled products
1426  NSDictionary *currentParameters = [self jsonForUsdaNumbersInMenuItem:mItem];
1427  NSArray<NSDictionary *> *usdaParameterArray = [currentParameters objectForKey:@"usdaNumbers"];
1428 
1429  [totals addObjectsFromArray:usdaParameterArray];
1430  } // for each item in todays menu
1431  return totals;
1432 }
1433 - (NSArray<NSDictionary *> *) todaysMenuComponents
1434 {
1435  NSMutableArray<NSDictionary *> *totals = [[NSMutableArray alloc] init];
1436  for (MenuItem *mItem in [self todaysMenuItems]) {
1437  // get a list of components for the menu item - json avail, use compiled products
1438  NSDictionary *currentParameters = [self jsonForUsdaNumbersInMenuItem:mItem];
1439 
1440  if (currentParameters) {
1441  NSArray<NSDictionary *> *usdaParameterArray = [currentParameters objectForKey:@"usdaNumbers"];
1442  [totals addObjectsFromArray:usdaParameterArray];
1443  } else {
1444  NSLog(@"LocalData.todaysMenuComponents: no parameters for %@", mItem.name);
1445  }
1446  } // for each item in todays menu
1447 
1448  // get authorized parameters
1449  NSArray<NSMutableDictionary*> *annotatedArray;
1450  if (0 < [totals count]) {
1451  annotatedArray = [[[Z5DataController sharedInstance]
1452  localDataController]
1453  annotateAuthority:totals];
1454  for (NSDictionary *entr in annotatedArray) {
1455  NSString *name = [entr objectForKey:[Z5LocalDataController componentNameKey]];
1456  NSString *quantStr = [entr objectForKey:[Z5LocalDataController componentValueKey]];
1457  HKQuantity *quant = [Z5LocalDataController hkQuantityForString:quantStr];
1458  double quantDbl = 0.0;
1459  if ([quant isCompatibleWithUnit:[HKUnit gramUnit]]) {
1460  quantDbl = [quant doubleValueForUnit:[HKUnit gramUnit]];
1461  } else if ([quant isCompatibleWithUnit:[HKUnit jouleUnit]]) {
1462  quantDbl = [quant doubleValueForUnit:[HKUnit jouleUnitWithMetricPrefix:HKMetricPrefixMicro]];
1463  }
1464  NSNumber *authority = [entr objectForKey:[Z5LocalDataController componentAuthorityKey]];
1465  Boolean authFlag = [ authority boolValue];
1466 
1467  if (0.0 < quantDbl) {
1468  if (authFlag) {
1469  // NSLog(@"LocalData.todaysMenuComponents: have authority for %@", name);
1470  } else {
1471  // NSLog(@"LocalData.todaysMenuComponents: no authority for %@, entr: %@", name, entr);
1472 
1473  }
1474  } else {
1475  NSLog(@"LocalData.todaysMenuComponents: no quantity for %@", name);
1476  }
1477  }
1478  } else {
1479  NSLog(@"LocalData.todaysMenuComponents: no totals for todays menu");
1480  }
1481 
1482  return annotatedArray;
1483 }
1485 {
1486  NSArray *emObjects = [[[Z5DataController sharedInstance] localDataController] retrieveAllEmailMessages];
1487  for (NSManagedObject *emailMessage in emObjects) {
1488  EmailMessage *dbEmailMessage = (EmailMessage *)emailMessage;
1489  NSLog(@"LocalData.logEmailMessageAndEmailMessageList: menuItem into list: %@", [dbEmailMessage subject]);
1490  }
1491 
1492  NSNumber *galleryChoice = [NSNumber numberWithInt:1];
1493  NSArray *objects = [[[Z5DataController sharedInstance] localDataController] retrieveAllMenuItems:galleryChoice];
1494  for (NSManagedObject *menuItem in objects) {
1495  MenuItem *dbMenuItem = (MenuItem *)menuItem;
1496  NSLog(@"LocalData.logEmailMessageAndMenuItemList: menuItem into list: %@", [dbMenuItem name]);
1497  }
1498 }
1499 
1500 
1501 #pragma mark - Read Defaults
1502 
1504 {
1505  int ret = 0;
1506 
1507  NSUserDefaults *udef = [NSUserDefaults standardUserDefaults];
1508 
1509  NSLog(@"LocalData.getBestAvailableUserDefaultMethod: udef: %@", udef);
1510 
1511  NSArray *theaterMenuArray = [udef arrayForKey:healthDataAuthority];
1512 
1513  NSDictionary *theaterItemDictionary = [udef dictionaryForKey:showTheaterItem];
1514 
1515  NSString *theaterVersion1 = [udef stringForKey:showTheaterVersion1];
1516 
1517  if (theaterMenuArray) {
1518  // if healthDataAuthority is a array
1519  ret = 1;
1520  } else if (theaterItemDictionary) {
1521  // if showTheaterItem is a dictionary
1522  ret = 2;
1523  } else if (theaterVersion1) {
1524  // if showTheaterVerion1 is a string
1525  ret = 3;
1526  }
1527  // this is nuts
1528  NSLog(@"LocalData.getBestAvailableUserDefaultMethod: ret: %d", ret);
1529  return ret;
1530 }
1531 
1540 {
1541  NSUserDefaults *udef = [NSUserDefaults standardUserDefaults];
1542  NSArray *proposedMenuItemArray = [udef arrayForKey:proposedMenuItemList];
1543 
1544  if (!_todaysMenuItems) {
1545  _todaysMenuItems = [[NSMutableArray alloc] init];
1546  }
1547 
1548  if (proposedMenuItemArray) {
1549  // NSLog(@"LocalData.createTodaysMenuFromUserDefaults: %@: %@", proposedMenuItemList, proposedMenuItemArray);
1550  // ret = [[NSMutableArray alloc] init];
1551  for (NSString *menuItemRandomkey in proposedMenuItemArray) {
1552  MenuItem *dbMenuItem = [self findMenuItemWithRandomkey:menuItemRandomkey];
1553  [_todaysMenuItems addObject:dbMenuItem];
1554  // NSLog(@"LocalData.createTodaysMenuFromUserDefaults: adding %@", dbMenuItem.name);
1555  }
1556  }
1557 
1558  NSMutableArray *ret = nil;
1559  return ret;
1560 
1561 }
1562 // - (NSDictionary *) getMenuItemEntryForEmpty
1563 // {
1564 // NSDictionary *ret;
1565 //
1566 // NSDictionary *theaterDictionarySingleItem = [[NSUserDefaults standardUserDefaults] dictionaryForKey:showTheaterItem];
1567 // if (0 < [theaterDictionarySingleItem count]) {
1568 // ret = [[NSMutableDictionary alloc] init];
1569 //
1570 // NSString *menuItemsList = [theaterDictionarySingleItem objectForKey:@"data"]; // 'data' works here
1571 //
1572 // NSLog(@"LocalData.getMenuItemEntryForEmpty: menuItemsList: %@", menuItemsList);
1573 //
1574 // NSDictionary *moleculeEntry = [self createMenuItemFromUserDefaults:menuItemsList];
1575 //
1576 // ret = [self generateTrivialCollection:moleculeEntry];
1577 // }
1578 // return ret;
1579 // }
1580 // - (NSMutableDictionary *) createMenuItemFromUserDefaults: (NSString *)menuItemsList
1581 // {
1582 // NSMutableDictionary * ret;
1583 //
1584 // if (![[menuItemsList class] isSubclassOfClass:[NSString class]]) {
1585 // // this was necessary to get up to write
1586 // // new user profile. NSDictionary will in will blow up.
1587 // return nil;
1588 // }
1589 //
1590 // // get Dictionary in user devault for
1591 // NSArray *menuItemArray = [[NSUserDefaults standardUserDefaults] arrayForKey:menuItemsList];
1592 // NSLog(@"LocalData.createMenuItemFromUserDefaults: for %@ dictionary: %@", menuItemsList, menuItemArray);
1593 // if (menuItemArray) {
1594 // for (MenuItem *miTem in menuItemArray) {
1595 // NSLog(@"LocalData.createMenuItemFromUD: miTem: %@", miTem);
1596 // }
1597 //
1598 // /*
1599 // NSString *theatMolecRandomkey = (NSString *)[theaterMenuItemDictionary objectForKey:@"randomkey"];
1600 //
1601 // // do NOT CREATE at this point
1602 // MenuItem *theaterDbMenuItem = [self findMenuItemWithRandomkey:theatMolecRandomkey];
1603 //
1604 // if (theaterDbMenuItem) {
1605 //
1606 //
1607 // Z6Ma2ChemistryMenuItem *molec = [[Z6Ma2ChemistryMenuItem alloc] initWithDbMolec:theaterDbMenuItem];
1608 // [molec provideDelegate:self]; // originally 'self',anged to 'nil' - will affect textures, no dictionary - dump at GL_TRIANGLES
1609 // GLKMatrix4 moleculeOrientation = GLKMatrix4Identity;
1610 // [molec placeAtPosition:theatMolecPosit andOrientation:moleculeOrientation];
1611 // [molec createAtomCollection];
1612 //
1613 // // [[theaterMenuItemDictionary objectForKey:@"molecule-data"] addObject:molec];
1614 // ret = [[NSMutableDictionary alloc] init];
1615 // [ret setObject:menuItemsList forKey:@"molecule-key"];
1616 // [ret setObject:molec forKey:@"molecule-data"];
1617 //
1618 // } else {
1619 // NSLog(@"LocalData.createMenuItemFromUserDefaults: no local molecule for %@", theatMolecRandomkey);
1620 // }
1621 //
1622 // // determine correctness of randomkey initialization
1623 // // NSLog(@"ViewAmino.viewDidLoad: theater molecule %@ randomkey: %@", menuItemsList, theatMolecRandomkey);
1624 // // MenuItem *menuItemsList = [[[Z5DataController sharedInstance] localDataController] findOrCreateMenuItemWithRandomkey:theatMolecRandomkey];
1625 // // if (menuItemsList) {
1626 // // NSLog(@"ViewAmino.viewDidLoad: theater molecule found");
1627 // // } else {
1628 // // NSLog(@"ViewAmino.viewDidLoad: no theater molecule");
1629 // // }
1630 //
1631 // */
1632 // } else {
1633 // NSLog(@"LocalData.createMenuItemFromUserDefaults: no user data information for %@", menuItemsList);
1634 // }
1635 // return ret;
1636 // }
1637 
1638 // -(NSMutableDictionary *)generateTrivialCollection:(NSDictionary *)moleculeEntry
1639 // {
1640 // NSMutableDictionary *retTheaterCollectionDictionary = [[NSMutableDictionary alloc] init];
1641 // if (moleculeEntry) {
1642 //
1643 // /*
1644 // [retTheaterCollectionDictionary setObject:[Z5LocalDataController produceRandomKeyWithCaption:@"collection-key: "] forKey:@"collection-key"];
1645 // [retTheaterCollectionDictionary setObject:[[NSMutableArray alloc] initWithCapacity:4] forKey: @"collection-data"];
1646 //
1647 // NSMutableDictionary *retTheaterSceneDictionary = [[NSMutableDictionary alloc] init];
1648 // [retTheaterSceneDictionary setObject:[Z5LocalDataController produceRandomKeyWithCaption:@"scene-key"] forKey:@"scene-key"];
1649 // [retTheaterSceneDictionary setObject:[[NSMutableArray alloc] initWithCapacity:4] forKey: @"scene-data"];
1650 // [[retTheaterCollectionDictionary objectForKey:@"collection-data"] addObject:retTheaterSceneDictionary];
1651 //
1652 // // NSMutableDictionary *retTheaterMenuItemDictionary = [[NSMutableDictionary alloc] init];
1653 // // [retTheaterMenuItemDictionary setObject:[Z5LocalDataController produceRandomKey] forKey:@"molecule-key"];
1654 // // [retTheaterMenuItemDictionary setObject:[[NSMutableArray alloc] init] forKey: @"molecule-data"];
1655 // // [[retTheaterMenuItemDictionary objectForKey:@"molecule-data"] addObject: molec];
1656 // [[retTheaterSceneDictionary objectForKey:@"scene-data"] addObject:moleculeEntry];
1657 // */
1658 //
1659 // } else {
1660 // NSLog(@"LocalData.generateTrivialCollection: null input");
1661 // }
1662 // return retTheaterCollectionDictionary;
1663 // }
1664 
1665 #pragma mark - Application's Documents directory
1666 
1671 {
1672  return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
1673 }
1674 
1675 
1676 @end
Boolean goHealthData:forDelegate:(NSArray< NSDictionary * > *parametersForHK, [forDelegate] id< Z5HealthConnectionProtocol > jingo)
NSString * produceRandomkey()
UIColor * wheatBackground
UIColor * menuContentsBackground
NSManagedObjectModel * managedObjectModel
UIColor * healthKitParamSharedColor
NSArray< HKQuantityType * > * allHkTypes()
NSArray< MenuItem * > * retrieveAllMenuItems:(NSNumber *galleryNo)
NSString * showTheaterMenu
Boolean deleteEmailMessageWithFileIdentification:context:(NSString *googlefileid, [context] NSManagedObjectContext *moc)
NSString * showCurrentScene
NSInteger nutritionTypeCount
UIColor * menuHeaderBackground
NSArray * retrieveAllMealsForGallery:context:(NSNumber *mealGallery, [context] NSManagedObjectContext *moc)
static NSString * componentValueKey
NSArray< NSDictionary * > * todaysMenuComponents()
MenuItem * menuItem
instancetype sharedInstance()
NSArray< Meal * > * retrieveAllMeals:(NSNumber *galleryNumber)
NSString * healthKitAuthorityKey
NSString * healthDataAuthority
Boolean removeMealWithRandomkey:(NSString *removeKey)
NSString * healthkitNutritionAuthorized
UIColor * healthKitParamNotQueried
NSPersistentStoreCoordinator * persistentStoreCoordinator
static NSString * componentAuthorityKey
NSMutableArray * availableNutritionParamArray
static NSString * componentNameKey
NSString * proposedMenuItemList
NSOperationQueue * healthKitOpQueue
static NSString * componentSampleKey
NSNumber * galleryPositionNo
MenuItem * findMenuItemWithRandomkey:context:(NSString *randomkey, [context] NSManagedObjectContext *moc)
NSArray< Meal * > * findMealsByMonth:context:(NSDate *nowdate, [context] NSManagedObjectContext *moc)
NSMutableArray * createTodaysMenuFromUserDefaults()
void saveQuantityToHealthStore:amount:(HKQuantityType *quantityType, [amount] HKQuantity *quantityAmount)
static NSString * componentAuthorityDateKey
MenuItem * findMenuItemWithFileIdentification:context:(NSString *googlefileid, [context] NSManagedObjectContext *moc)
HKQuantity * hkQuantityForString:(NSString *quantityDescript)
NSMutableArray * establishNutritionParameters()
NSString * showTheaterItem
NSDictionary * jsonForUsdaNumbersInMenuItem:(MenuItem *menuItem)
NSManagedObjectContext * managedObjectContext
MenuItem * findOrCreateMenuItemWithFileIdentification:context:(NSString *googlefileid, [context] NSManagedObjectContext *moc)
NSString * healthkitNutritionKey
void deleteMealsByMonth:context:(NSDate *nowdate, [context] NSManagedObjectContext *moc)
NSArray< MenuItem * > * retrieveAllMenuItemsForGallery:context:(NSNumber *galleryNo, [context] NSManagedObjectContext *moc)
EmailMessage * findOrCreateEmailMessageWithFileIdentification:context:(NSString *googlefileid, [context] NSManagedObjectContext *moc)
MenuItem * findMenuItemWithRandomkey:(NSString *randomkey)
NSNumber * checkTypeAuthorization:(HKQuantityType *quantityType)
NSArray< HKQuantityType * > * typesForWriting()
NSArray< Meal * > * findOrCreateMealWithDate:(NSDate *findDate)
Singleton interface to both core and remote data sources.
MenuItem * findOrCreateMenuItemWithRandomkey:context:(NSString *key, [context] NSManagedObjectContext *moc)
static NSString * componentHKComponentKey
void deleteMealByRandomkey:context:(NSString *deleteKey, [context] NSManagedObjectContext *moc)
NSArray< Meal * > * findOrCreateMealWithDate:context:(NSDate *findDate, [context] NSManagedObjectContext *moc)
NSMutableDictionary * healthKitNutritionAuthorityDict
NSMutableArray * usdaParameterArray
HKQuantityTypeIdentifier nutritionTypes[40]
NSString * healthkitNutritionValidated
UIColor * panelBackgroundColor
NSRange currentMenuItemGalleryPositions
UIColor * healthKitParamDeniedAuthColor
NSArray< Meal * > * findMealsWithDate:context:(NSDate *findDate, [context] NSManagedObjectContext *moc)
NSString * showTheaterVersion1
NSString * unitsForParameter:(NSString *paramKeyStr)
NSMutableArray< MenuItem * > * todaysMenuItems
NSArray * emailMessageWithFileid:context:(NSString *googlefileid, [context] NSManagedObjectContext *moc)
MenuItem * findNextMenuItemForGallery:afterPosition:context:(NSNumber *galleryNo, [afterPosition] NSNumber *positionInGallery, [context] NSManagedObjectContext *moc)