//
//  GHDeviceManager.h
//  Garmin Health
//
//  Created by Timar, Mihai.
//  Copyright © 2016 Garmin International, Inc. or its affiliates. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "GHDeviceTypes.h"
#import "GHRequestDataTypes.h"

@class GHScanner;
@class GHDevice;
@class GHScannedDevice;
@class GHDeviceManager;
@class GHPairingCompletion;
@class GHCustomSettings;
@class GHUserSettings;
@class GHFetchResult;
@protocol GHPairingDelegate;
@protocol GHDeviceConnectionDelegate;
@protocol GHSyncDelegate;
@protocol GHIntervalDurationDelegate;
@protocol GHScanDelegate;


/**
 *  Enum of possible pairing errors.
 */
typedef NS_ENUM(NSInteger, GHPairingError) {
    /**
     * Unexpected error
     */
    GHPairingErrorUndefined = 0,
    /**
     *  Timed out while trying to establish device connection
     */
    GHPairingErrorTimeout = 1,
    /**
     *  Settings are invalid.
     */
    GHPairingErrorSettingsInvalid = 2,
    /**
     *  Connection failed while handshaking
     */
    GHPairingErrorConnectionFailed = 3,
};

/**
 *  Type definition for Block.
 */
typedef void (^GHFetchRequestResults)(GHFetchResult *results);



#pragma mark -
/**
 *  Static interface providing access to Garmin devices.
 */
@interface GHDeviceManager : NSObject

/** Exposes the single instance of the GHDeviceManager class. */
+ (GHDeviceManager *)sharedManager;

/**
 *  Pair to a specific device discovered during a scan. If the device has not been previously
 *  paired with Garmin Connect then you should use pairDevice:userSettings:delegate
 *
 *  @param scannedDevice Device to pair.
 *  @param delegate      Delegate to provide information on pairing status <GHPairingDelegate>
 */
- (void)pairDevice:(GHScannedDevice*)scannedDevice delegate:(id<GHPairingDelegate>)delegate;

/**
 *  Pair to a specific device discovered during a scan.
 *
 *  @param scannedDevice Device to pair.
 *  @param userSettings  User settings to save during pairing
 *  @param delegate      Delegate to provide information on pairing status <GHPairingDelegate>
 */
- (void)pairDevice:(GHScannedDevice*)scannedDevice userSettings:(GHUserSettings *)userSettings delegate:(id<GHPairingDelegate>)delegate;

/**
 * Cancels the attempted pairing with the device.
 * @param device The GHScannedDevice to canel pairing
 */
- (void)cancelPairingWithDevice:(GHScannedDevice *)device;

/**
 * Forgets a device that has been paired. Device will not be forgotten by the phone.
 * @param device The GHDevice to forget
 */
- (void)forgetDevice:(GHDevice*)device;

/**
 * Gets a device that has been paired.
 * @param identifier    Identifier of device
 */
- (GHDevice*)getDevice:(NSUUID*)identifier;

/**
 * Gets all devices that have been paired.
 */
- (NSArray<GHDevice*>*)getPairedDevices;

/**
 *  Adds a GHDeviceConnectionDelegate delegate to be called for connection events.
 *  @param delegate GHDeviceConnectionDelegate to add.
 */
- (void)addConnectionDelegate:(id<GHDeviceConnectionDelegate>)delegate;

/**
 *  Removes previously added GHDeviceConnectionDelegate delegate.
 *  @param delegate GHDeviceConnectionDelegate to remove.
 */
- (void)removeConnectionDelegate:(id<GHDeviceConnectionDelegate>)delegate;

/**
 *  Adds a sync delegate GHSyncDelegate to be called for sync events.
 *  @warning At least one delegate must implement a didComplete method for sync to run.
 *  @param delegate GHSyncDelegate to add.
*/
- (void)addSyncDelegate:(id<GHSyncDelegate>)delegate;

/**
 *  Removes previously added sync delegate
 *  @param delegate GHSyncDelegate to remove.
 */
- (void)removeSyncDelegate:(id<GHSyncDelegate>)delegate;

/**
 *  Sets the interval delegate. To clear set to nil.
 *  @param delegate GHIntervalDurationDelegate to set.
 */
- (void)setIntervalDelegate:(id<GHIntervalDurationDelegate>)delegate;

/**
 *  Scan for specific types of devices. When a device is found it will be sent to the delegate.
 *  If BT is disabled or not yet ready, it will register the callback and wait for BT access before scanning.
 *  @param deviceTypes  Options style GHDeviceTypes combined with '|'. Only types specified here will be returned.
 */
- (void)scanForDevices:(GHDeviceTypes)deviceTypes;

/**
 *  Stop a scan. It is safe to call even if no scan is in progress.
 */
- (void)stopScan;

/**
 *  Sets the scan delegate.
 *  @param delegate GHScanDelegate to set.
 */
- (void)setScannerDelegate:(id<GHScanDelegate>)delegate;

/**
 *  Makes a request for the data types in the date range for the device.
 *  @param device GHDevice the device the data is associated with
 *  @param types GHRequestDataTypes the desired types of data requested
 *  @param fromDate NSDate the start time for the requested data
 *  @param toDate NSDate the end time for the requested data
 *  @param completionHandler GHFetchRequestResults block that is called
 *  when the fetch is completed.
 */
- (void)getDataForDevice:(GHDevice *)device dataTypes:(GHRequestDataTypes)types fromDate:(NSDate *)fromDate toDate:(NSDate *)toDate completionHandler:(GHFetchRequestResults)completionHandler;

/**
 *  Deletes stored data for the data types in the date range for the device.
 *  @param device GHDevice the device the data is associated with
 *  @param types GHRequestDataTypes the desired types of data requested
 *  @param fromDate NSDate the start time for the requested data
 *  @param toDate NSDate the end time for the requested data
 */
- (void)deleteDataForDevice:(GHDevice *)device dataTypes:(GHRequestDataTypes)types fromDate:(NSDate *)fromDate toDate:(NSDate *)toDate;

/**
 *  Deletes all stored data for the data types for the device.
 *  @param device GHDevice the device the data is associated with
 *  @param types GHRequestDataTypes the desired types of data requested
 */
- (void)deleteAllDataForDevice:(GHDevice *)device dataTypes:(GHRequestDataTypes)types;

/**
 *  Deletes all stored data for the device.
 *  @param device GHDevice the device the data is associated with
 */
- (void)deleteAllDataForDevice:(GHDevice *)device;

/** NS_UNAVAILABLE */
+ (instancetype)new NS_UNAVAILABLE;
/** NS_UNAVAILABLE */
- (instancetype)init NS_UNAVAILABLE;


@end
