<commit_before>//
//  HealthKitSampleStore.swift
//  Naterade
//
//  Created by <NAME> on 1/24/16.
//  Copyright © 2016 <NAME>. All rights reserved.
//

import Foundation
import HealthKit
import os.log


extension Notification.Name {
    public static let StoreAuthorizationStatusDidChange = Notification.Name(rawValue: "com.loudnate.LoopKit.AuthorizationStatusDidChangeNotification")
}


public enum HealthKitSampleStoreResult<T> {
    case success(T)
    case failure(HealthKitSampleStore.StoreError)
}


public class HealthKitSampleStore {
    /// Describes the source of an update notification. Value is of type `UpdateSource.RawValue`
    public static let notificationUpdateSourceKey = "com.loopkit.UpdateSource"
    
    private let observerQueryUpdateHandlerQueue: DispatchQueue

    public enum StoreError: Error {
        case authorizationDenied
        case healthKitError(HKError)
    }
    
    /// The sample type managed by this store
    public let sampleType: HKSampleType

    /// The health store used for underlying queries
    public let healthStore: HKHealthStore
    
    /// Whether the store should fetch data that was written to HealthKit from current app
    private let observeHealthKitSamplesFromCurrentApp: Bool

    /// Whether the store should fetch data that was written to HealthKit from other apps
    private let observeHealthKitSamplesFromOtherApps: Bool

    /// Whether the store is observing changes to types
    public let observationEnabled: Bool

    /// For unit testing only.
    internal var testQueryStore: HKSampleQueryTestable?

    /// Allows for controlling uses of the system date in unit testing
    internal var test_currentDate: Date?

    internal func currentDate(timeIntervalSinceNow: TimeInterval = 0) -> Date {
        let date = test_currentDate ?? Date()
        return date.addingTimeInterval(timeIntervalSinceNow)
    }
    
    /// Allows unit test to inject a mock for HKObserverQuery
    internal var createObserverQuery: (HKSampleType, NSPredicate?, @escaping (HKObserverQuery, @escaping HKObserverQueryCompletionHandler, Error?) -> Void) -> HKObserverQuery = { (sampleType, predicate, updateHandler) in
        return HKObserverQuery(sampleType: sampleType, predicate: predicate, updateHandler: updateHandler)
    }
    
    /// Allows unit test to inject a mock for HKAnchoredObjectQuery
    internal var createAnchoredObjectQuery: (HKSampleType, NSPredicate?, HKQueryAnchor?, Int, @escaping (HKAnchoredObjectQuery, [HKSample]?, [HKDeletedObject]?, HKQueryAnchor?, Error?) -> Void) -> HKAnchoredObjectQuery = { (sampleType, predicate, anchor, limit, resultsHandler) in
        return HKAnchoredObjectQuery(type: sampleType, predicate: predicate, anchor: anchor, limit: limit, resultsHandler: resultsHandler)
    }

    private let log: OSLog

    public init(
        healthStore: HKHealthStore,
        observeHealthKitSamplesFromCurrentApp: Bool = true,
        observeHealthKitSamplesFromOtherApps: Bool = true,
        type: HKSampleType,
        observationStart: Date,
        observationEnabled: Bool,
        test_currentDate: Date? = nil
    ) {
        self.healthStore = healthStore
        self.observeHealthKitSamplesFromCurrentApp = observeHealthKitSamplesFromCurrentApp
        self.observeHealthKitSamplesFromOtherApps = observeHealthKitSamplesFromOtherApps
        self.sampleType = type
        self.observationStart = observationStart
        self.observationEnabled = observationEnabled
        self.test_currentDate = test_currentDate
        self.lockedQueryAnchor = Locked<HKQueryAnchor?>(nil)

        self.log = OSLog(category: String(describing: Swift.type(of: self)))
 
        self.observerQueryUpdateHandlerQueue = DispatchQueue(label: "com.loopkit.HealthKitSampleStore.observerQueryUpdateHandlerQueue.\(Swift.type(of: self))", qos: .utility)
    }

    deinit {
        if let query = observerQuery {
            healthStore.stop(query)
        }
        observerQuery = nil
    }

    // MARK: - Authorization
    
    /// Requests authorization from HealthKit to share and read the sample type.
    ///
    /// This operation is performed asynchronously and the completion will be executed on an arbitrary background queue.
    ///
    /// - Parameters:
    ///   - toShare: Whether to request write authorization. Defaults to true.
    ///   - read: Whether to request read authorization. Defaults to true.
    ///   - completion: A closure called after the authorization is completed
    ///   - result: The authorization result
    public func authorize(toShare: Bool = true, read: Bool = true, _ completion: @escaping (_ result: HealthKitSampleStoreResult<Bool>) -> Void) {
        healthStore.requestAuthorization(toShare: toShare ? [sampleType] : [], read: read ? [sampleType] : []) { (completed, error) -> Void in
            if completed && !self.sharingDenied {
                self.log.default("Authorize completed: creating HK query")
                self.createQuery()
                completion(.success(true))
            } else {
                let authError: StoreError
                
                if let error = error {
                    authError = .healthKitError(HKError(_nsError: error as NSError))
                } else {
                    authError = .authorizationDenied
                }
                
                completion(.failure(authError))
            }
            
            NotificationCenter.default.post(name: .StoreAuthorizationStatusDidChange, object: self)
        }
    }

    // MARK: - Query support

    /// The active observer query
    internal var observerQuery: HKObserverQuery? {
        didSet {
            if let query = oldValue {
                healthStore.stop(query)
            }

            if let query = observerQuery {
                log.debug("Executing observerQuery %@", query)
                healthStore.execute(query)
            }
        }
    }<commit_msg>Check preferred unit after authorization<commit_after>//
//  HealthKitSampleStore.swift
//  Naterade
//
//  Created by <NAME> on 1/24/16.
//  Copyright © 2016 <NAME>. All rights reserved.
//

import Foundation
import HealthKit
import os.log


extension Notification.Name {
    public static let StoreAuthorizationStatusDidChange = Notification.Name(rawValue: "com.loudnate.LoopKit.AuthorizationStatusDidChangeNotification")
}


public enum HealthKitSampleStoreResult<T> {
    case success(T)
    case failure(HealthKitSampleStore.StoreError)
}


public class HealthKitSampleStore {
    /// Describes the source of an update notification. Value is of type `UpdateSource.RawValue`
    public static let notificationUpdateSourceKey = "com.loopkit.UpdateSource"
    
    private let observerQueryUpdateHandlerQueue: DispatchQueue

    public enum StoreError: Error {
        case authorizationDenied
        case healthKitError(HKError)
    }
    
    /// The sample type managed by this store
    public let sampleType: HKSampleType

    /// The health store used for underlying queries
    public let healthStore: HKHealthStore
    
    /// Whether the store should fetch data that was written to HealthKit from current app
    private let observeHealthKitSamplesFromCurrentApp: Bool

    /// Whether the store should fetch data that was written to HealthKit from other apps
    private let observeHealthKitSamplesFromOtherApps: Bool

    /// Whether the store is observing changes to types
    public let observationEnabled: Bool

    /// For unit testing only.
    internal var testQueryStore: HKSampleQueryTestable?

    /// Allows for controlling uses of the system date in unit testing
    internal var test_currentDate: Date?

    internal func currentDate(timeIntervalSinceNow: TimeInterval = 0) -> Date {
        let date = test_currentDate ?? Date()
        return date.addingTimeInterval(timeIntervalSinceNow)
    }
    
    /// Allows unit test to inject a mock for HKObserverQuery
    internal var createObserverQuery: (HKSampleType, NSPredicate?, @escaping (HKObserverQuery, @escaping HKObserverQueryCompletionHandler, Error?) -> Void) -> HKObserverQuery = { (sampleType, predicate, updateHandler) in
        return HKObserverQuery(sampleType: sampleType, predicate: predicate, updateHandler: updateHandler)
    }
    
    /// Allows unit test to inject a mock for HKAnchoredObjectQuery
    internal var createAnchoredObjectQuery: (HKSampleType, NSPredicate?, HKQueryAnchor?, Int, @escaping (HKAnchoredObjectQuery, [HKSample]?, [HKDeletedObject]?, HKQueryAnchor?, Error?) -> Void) -> HKAnchoredObjectQuery = { (sampleType, predicate, anchor, limit, resultsHandler) in
        return HKAnchoredObjectQuery(type: sampleType, predicate: predicate, anchor: anchor, limit: limit, resultsHandler: resultsHandler)
    }

    private let log: OSLog

    public init(
        healthStore: HKHealthStore,
        observeHealthKitSamplesFromCurrentApp: Bool = true,
        observeHealthKitSamplesFromOtherApps: Bool = true,
        type: HKSampleType,
        observationStart: Date,
        observationEnabled: Bool,
        test_currentDate: Date? = nil
    ) {
        self.healthStore = healthStore
        self.observeHealthKitSamplesFromCurrentApp = observeHealthKitSamplesFromCurrentApp
        self.observeHealthKitSamplesFromOtherApps = observeHealthKitSamplesFromOtherApps
        self.sampleType = type
        self.observationStart = observationStart
        self.observationEnabled = observationEnabled
        self.test_currentDate = test_currentDate
        self.lockedQueryAnchor = Locked<HKQueryAnchor?>(nil)

        self.log = OSLog(category: String(describing: Swift.type(of: self)))
 
        self.observerQueryUpdateHandlerQueue = DispatchQueue(label: "com.loopkit.HealthKitSampleStore.observerQueryUpdateHandlerQueue.\(Swift.type(of: self))", qos: .utility)
    }

    deinit {
        if let query = observerQuery {
            healthStore.stop(query)
        }
        observerQuery = nil
    }

    // MARK: - Authorization
    
    /// Requests authorization from HealthKit to share and read the sample type.
    ///
    /// This operation is performed asynchronously and the completion will be executed on an arbitrary background queue.
    ///
    /// - Parameters:
    ///   - toShare: Whether to request write authorization. Defaults to true.
    ///   - read: Whether to request read authorization. Defaults to true.
    ///   - completion: A closure called after the authorization is completed
    ///   - result: The authorization result
    public func authorize(toShare: Bool = true, read: Bool = true, _ completion: @escaping (_ result: HealthKitSampleStoreResult<Bool>) -> Void) {
        healthStore.requestAuthorization(toShare: toShare ? [sampleType] : [], read: read ? [sampleType] : []) { (completed, error) -> Void in
            if completed && !self.sharingDenied {
                self.log.default("Authorize completed: creating HK query")
                self.createQuery()
                completion(.success(true))
            } else {
                let authError: StoreError
                
                if let error = error {
                    authError = .healthKitError(HKError(_nsError: error as NSError))
                } else {
                    authError = .authorizationDenied
                }
                
                completion(.failure(authError))
            }

            NotificationCenter.default.post(name: .StoreAuthorizationStatusDidChange, object: self)

            // Do not remove this log: it actually triggers a query by calling preferredUnit, and can update the cache
            // And trigger a unit change notification after authorization happens.
            self.log.default("Checking units after authorization: %{public}@", String(describing: self.preferredUnit))
        }
    }

    // MARK: - Query support

    /// The active observer query
    internal var observerQuery: HKObserverQuery? {
        didSet {
            if let query = oldValue {
                healthStore.stop(query)
            }

            if let query = observerQuery {
                log.debug("Executing observerQuery %@", query)
                healthStore.execute(query)
            }
        }
    }
{'fraction_non_alphanumeric': 0.07737560258191029, 'fraction_numerical': 0.0016341204346760356, 'mean_word_length': 2.7385461209529627, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5375730', 'n_tokens_mistral': 3236, 'n_tokens_neox': 3028, 'n_words': 926}