//
//  CDMDataManSystem.h
//
//  Copyright (c) 2014 Cognex Corporation. All rights reserved.
//

/*! \mainpage Cognex Mobile Barcode iOS SDK

You can find detailed information about using cmbSDK in our programmer guide: https://cmbdn.cognex.com/knowledge/-cognex-mobile-barcode-sdk-for-ios

 */

#import <Foundation/Foundation.h>
#import <ExternalAccessory/ExternalAccessory.h>
#import <cmbSDK/CDMDataManSystemDelegate.h>
#import <CoreBluetooth/CoreBluetooth.h>
@class MDMAuthCredentials;

/**
 *  Image size.
 */
typedef NS_ENUM(NSInteger, CDMImageSize)
{
    /**
     *  Full sized image
     */
    kCDMImageSizeFull,
    /**
     *  Image scaled down by 1/4
     */
    kCDMImageSizeQuarter,
    /**
     *  Image scaled down by 1/16
     */
    kCDMImageSizeSixteenth,
    /**
     *  Image scaled down by 1/64
     */
    kCDMImageSizeSixtyFourth
};

/**
 *  Image quality used when getting live image or process monitor images.
 */
typedef NS_ENUM(NSInteger, CDMImageQuality)
{
    /**
     *  Low image quality for jpeg format
     */
    kCDMImageQualityLow = 10,
    /**
     *  Medium image quality for jpeg format
     */
    kCDMImageQualityMedium = 50,
    /**
     *  High image quality for jpeg format
     */
    kCDMImageQualityHigh = 90
};

/**
 *  Indicates the image format type for live displays or process monitor images
 */
typedef NS_ENUM(NSInteger, CDMImageFormat)
{
    /**
     *  Bitmap format
     */
    kCDMImageFormatBitmap = 0,
    /**
     *  Jpeg format
     */
    kCDMImageFormatJpeg = 1
};

/**
 *  Specifies the result types, that the application can receive. All other result types are ignored.
 */
typedef NS_OPTIONS(NSInteger, CDMResultTypes)
{
    /**
     *  No results of any kind are requested from the reader
     */
    kCDMResultTypeNone = 0,
    /**
     *  Represents a simple read result string
     */
    kCDMResultTypeReadString = 1,
    /**
     *  Represents a read result in xml format
     */
    kCDMResultTypeReadXml = 2,
    /**
     *  Represents read statistics in xml format
     */
    kCDMResultTypeXmlStatistics = 4,
    /**
     *  Represents a read image
     */
    kCDMResultTypeImage = 8,
    /**
     *  Represent an image graphics xml
     */
    kCDMResultTypeImageGraphics = 16,
    /**
     *  Represents training results in xml format
     */
    kCDMResultTypeTrainingResults = 32,
    /**
     *  Represents code quality information in xml format
     */
    kCDMResultTypeCodeQualityData = 64,
    /**
     *  Represents code content information in xml format
     */
    kCDMResultTypeXmlContent = 128
};

/**
 *  Specifies the connection states, that the DataManSystem can have.
 */
typedef NS_ENUM(NSInteger, CDMConnectionState) {
    kCDMConnectionStateDisconnected = 0,
    kCDMConnectionStateConnecting = 1,
    kCDMConnectionStateConnected = 2,
    kCDMConnectionStateDisconnecting = 3
};

/**
 *  Specifies the device types of a CDMDataManSystem instance.
 */
typedef enum : NSUInteger {
    DataManDeviceClass_MX,
    DataManDeviceClass_Network,
    DataManDeviceClass_PhoneCamera,
    DataManDeviceClass_BT_L2CAP
} DataManDeviceClass;

/**
 * Specifies the preview/illumination mode when using the Mobile device camera.
 */
typedef NS_ENUM(NSInteger, CDMCameraMode)
{
    /**
     * Use camera with no aimer. Preview is on, illumination is available.
     */
    kCDMCameraModeNoAimer,
    /**
     * Use camera with a basic aimer (e.g., StingRay). Preview is off, illumination is not available.
     */
    kCDMCameraModePassiveAimer,
    /**
     * Use mobile device front camera. Preview is on, illumination is not available.
     */
    kCDMCameraModeFrontCamera
};

/**
 * Controls the preview/scanning options when using the Mobile device camera.
 * Preview defaults are set by the {@link CDMCameraMode} but can be overridden.
 * Multiple options can be OR'd together.
 */
typedef NS_OPTIONS(NSInteger, CDMPreviewOption)
{
    /**
     * Use defaults (no overrides).
     */
    kCDMPreviewOptionDefaults = 0,
    /**
     * Disable zoom feature (removes zoom button from preview).
     */
    kCDMPreviewOptionNoZoomBtn = 1,
    /**
     * Disable illumination (removes illumination button from preview).
     */
    kCDMPreviewOptionNoIllumBtn = 2,
    /**
     * Enables the simulated hardware trigger (the volume down button).
     */
    kCDMPreviewOptionHwTrigger = 4,
    /**
     * When scanning starts, the preview is displayed but decoding is paused until a trigger (either the on screen button or the volume down button, if enabled) is pressed.
     */
    kCDMPreviewOptionPaused = 8,
    /**
     * Force the preview to be displayed, even if off by default (e.g., when using kCDMCameraModePassiveAimer).
     */
    kCDMPreviewOptionAlwaysShow = 16,
    /**
     * Use higher resolution if the device supports it. Default is 1280x720, with this param 1920x1080 will be used.
     */
    kCDMPreviewOptionHighResolution = 32,
    /**
     * Use higher framerate if the device supports it. Default is 30 FPS, with this param 60 FPS will be used.
     */
    kCDMPreviewOptionHighFrameRate = 64,
    /**
     * Show close button in partial view.
     */
    kCDMPreviewOptionShowCloseBtn = 128,
    /**
     * Keep the preview in paused state after read
     */
    kCDMPreviewOptionKeepPreviewInPausedState = 256
};

/**
 *  Represents a remote DataMan system.
 */
@interface CDMDataManSystem : NSObject

/**
 * Gets the device type of the CDMDataManSystem instance.
 */
@property (readonly) DataManDeviceClass deviceClass;

/**
 * Gets the current connection state of the CDMDataManSystem instance.
 */
@property (readonly) CDMConnectionState connectionState;

/**
 * Sets or gets the delegate where the messages will be sent to.
 * @see CDMDataManSystemDelegate
 */
@property (weak) id<CDMDataManSystemDelegate> _Nullable delegate;

/**
 * Sets which result types the application wants to receive.
 */
@property (nonatomic) CDMResultTypes resultTypes;

/**
 * Read-only state of the heartbeat function.
 */
@property (readonly, getter = isHeartbeatEnabled) BOOL heartbeatEnabled;

/**
 * Read-only state of live image mode.
 */
@property (readonly, getter = isLiveImageEnabled) BOOL liveImageEnabled;

/**
 * Timeout for commands and connection, default value is 6 sec.
 */
@property (nonatomic) NSTimeInterval timeout;

/**
 * Default credentials for MDM communication. Credentials provided by managed app configuration will override this property per field basis.
 */
@property (nonatomic) MDMAuthCredentials * _Nullable defaultMDMAuthCredentials;

/**
 * Enables reporting properties of the connected MX device to an MDM system. Default value is false.
 */
@property (nonatomic) BOOL MDMReportingEnabled;

/**
 * Read-only connection state of the system.
 */
@property (readonly, getter = isConnected) BOOL connected;

/**
 * Returns the current version of the library
 * @returns current DataMan SDK version
 */
+ (NSString *_Nonnull)getVersion;

/**
 
Constructs a DataMan system with hostname and port.

This factory method constructs a new DataMan system with an ethernet connector configured inside.
@param hostname The hostname of the remote system
@param port The port of the remote system
@param delegate The delegate where the messages will be sent to
@return DataMan system with ethernet connection configured
 
@see CDMDataManSystemDelegate
*/
+ (CDMDataManSystem *_Nonnull)dataManSystemWithHostname:(NSString * _Nonnull)hostname port:(int)port delegate:(id<CDMDataManSystemDelegate>_Nonnull)delegate;

/**
 Constructs a DataMan system with accessory connector. To properly detect and connect to the device, be sure to declare UISupportedExternalAccessoryProtocols key with Cognex DMCC protocol (com.cognex.dmcc) item in Info.plist.
 @param accessory The EAAccessory object with information about the connected device
 @param delegate The delegate where the messages will be sent to
 @return DataMan system with external accessory connection configured or nil, if the accessory is not a CDM device
 
 @see CDMDataManSystemDelegate
 */
+ (CDMDataManSystem *_Nonnull)dataManSystemWithAccessory:(EAAccessory*_Nullable)accessory delegate:(id<CDMDataManSystemDelegate>_Nonnull)delegate;

/**
 Constructs a DataMan system with accessory connector. To properly detect and connect to the device, be sure to declare UISupportedExternalAccessoryProtocols key with Cognex DMCC protocol (com.cognex.dmcc) item in Info.plist.
 @param delegate The delegate where the messages will be sent to
 @return DataMan system with external accessory connection configured or nil, if there is no supported accessory connected
 
 @see CDMDataManSystemDelegate
 */
+ (CDMDataManSystem *_Nonnull)dataManSystemOfExternalAccessoryWithDelegate:(id<CDMDataManSystemDelegate>_Nonnull)delegate;

/**
 Constructs a DataMan system with iOS camera. To properly detect and connect to the device, be sure to declare NSCameraUsageDescription key with Cognex DMCC protocol (com.cognex.dmcc) item in Info.plist.
 @param cameraMode Check {@link CDMCameraMode} for possible values.
 @param previewOptions Check {@link CDMPreviewOption} for possible values.
 @param previewView Camera preview will be attached on that view, can be null (in which case, camera preview will be in full screen).
 @param delegate The delegate where the messages will be sent to
 @return DataMan system using the devices built in camera
 
 @see CDMDataManSystemDelegate
 */
+ (CDMDataManSystem *_Nonnull)dataManSystemWithCameraMode:(CDMCameraMode)cameraMode
                                           previewOptions:(CDMPreviewOption)previewOptions
                                      nullablePreviewView:(UIView*_Nullable)previewView
                                                 delegate:(id<CDMDataManSystemDelegate>_Nonnull)delegate;

/**
 Constructs a DataMan system with iOS camera. To properly detect and connect to the device, be sure to declare NSCameraUsageDescription key with Cognex DMCC protocol (com.cognex.dmcc) item in Info.plist.
 @param cameraMode Check {@link CDMCameraMode} for possible values.
 @param previewOptions Check {@link CDMPreviewOption} for possible values.
 @param delegate The delegate where the messages will be sent to
 @return DataMan system using the devices built in camera
 
 @see CDMDataManSystemDelegate
 */
+ (CDMDataManSystem *_Nonnull)dataManSystemWithCameraMode:(CDMCameraMode)cameraMode
                                           previewOptions:(CDMPreviewOption)previewOptions
                                                 delegate:(id<CDMDataManSystemDelegate>_Nonnull)delegate;

/**
 Constructs a DataMan system with iOS camera. To properly detect and connect to the device, be sure to declare NSCameraUsageDescription key with Cognex DMCC protocol (com.cognex.dmcc) item in Info.plist.
 @param cameraMode Check {@link CDMCameraMode} for possible values.
 @param previewOptions Check {@link CDMPreviewOption} for possible values.
 @param previewView Camera preview will be attached on that view, can be null (in which case, camera preview will be in full screen).
 @param registrationKey The license key for registering the camera scanner.
 @param delegate The delegate where the messages will be sent to
 @return DataMan system using the devices built in camera
 
 @see CDMDataManSystemDelegate
 */
+ (CDMDataManSystem *_Nonnull)dataManSystemWithCameraMode:(CDMCameraMode)cameraMode
                                           previewOptions:(CDMPreviewOption)previewOptions
                                      nullablePreviewView:(UIView*_Nullable)previewView
                                          registrationKey:(NSString*_Nullable)registrationKey
                                                 delegate:(id<CDMDataManSystemDelegate>_Nonnull)delegate;

/**
 Constructs a DataMan system with iOS camera. To properly detect and connect to the device, be sure to declare NSCameraUsageDescription key with Cognex DMCC protocol (com.cognex.dmcc) item in Info.plist.
 @param cameraMode Check {@link CDMCameraMode} for possible values.
 @param previewOptions Check {@link CDMPreviewOption} for possible values.
 @param previewView Camera preview will be attached on that view, can be null (in which case, camera preview will be in full screen).
 @param registrationKey The license key for registering the camera scanner.
 @param customData Custom string to be send to the licensing server for tracking purposes.
 @param delegate The delegate where the messages will be sent to
 @return DataMan system using the devices built in camera
 
 @see CDMDataManSystemDelegate
 */
+ (CDMDataManSystem *_Nonnull)dataManSystemWithCameraMode:(CDMCameraMode)cameraMode
                                           previewOptions:(CDMPreviewOption)previewOptions
                                      nullablePreviewView:(UIView*_Nullable)previewView
                                          registrationKey:(NSString*_Nullable)registrationKey
                                               customData:(NSString*_Nullable)customData
                                                 delegate:(id<CDMDataManSystemDelegate>_Nonnull)delegate;

/**
 Constructs a DataMan system with a Bluetooth device. You should first scan for a Bluetooth device or load its saved UUID to connect.
 @param peripheralUUID The UUID of the CBPeripheral object you want to connect to.
 @param psm The default value is 192.
 @param delegate The delegate where the messages will be sent to
 @return DataMan system using the Bluetooth device identified by peripheralUUID parameter
 
 @see CDMDataManSystemDelegate
 */
+ (CDMDataManSystem *_Nonnull)datamanSystemWithBluetoothPeripheralUUID:(NSUUID *_Nonnull)peripheralUUID
                                                                   psm:(CBL2CAPPSM)psm
                                                              delegate:(id<CDMDataManSystemDelegate>_Nonnull)delegate API_AVAILABLE(ios(11));
/**
 Sets the container where the camera preview will be placed.
 @param previewContainer The container where the camera preview will be placed.
 @param completionBlock The block will contain an error when used on connector other than the Phone Camera
 Method is only supported for Phone Camera
 */
- (void)setCameraPreviewContainer:(UIView*_Nullable) previewContainer completion:(void (^_Nullable)(NSError * _Nullable error))completionBlock;

/**
 Get camera exposure compensation range (0: lower value, 1: upper value, 2: step) in the completion block. Camera must to be opened before
 @param completionBlock The block will contain an array with the minimum and maximum exposure values, or an error when used on connector other than the Phone Camera
 The camera needs to be started within cmbSDK at least once to get the camera exposure compensation range
 */
- (void)getCameraExposureCompensationRangeWithCompletion:(void (^_Nonnull)(NSArray<NSNumber *>*_Nullable range, NSError *_Nullable error))completionBlock;

/**
 Sets the camera exposure compensation value
 @param exposureCompensation Float value that will be set as exposure compensation
 @param completionBlock The block will contain an error when used on connector other than the Phone Camera
 */
- (void)setCameraExposureCompensation:(float)exposureCompensation completion:(void (^_Nullable)(NSError * _Nullable error))completionBlock;

/**
 Load config from app data if exist
 Method is only supported for Phone Camera
 @param completionBlock The block will contain an error when used on connector other than the Phone Camera
 */
- (void)loadCameraConfig:(void (^_Nullable)(NSError * _Nullable error))completionBlock;

///---------------------------------------------------------------------------------------
/// @name Instance methods
///---------------------------------------------------------------------------------------

/**
 * Connects to a remote system without authentication
 */
- (BOOL)connect;

/**
 *  Connects to a remote system, authenticating with the specified username and password. If the password is specified but the username is not, the username will be "admin" by default.
 *
 @param username the username for the authentication
 @param password the password for the given user
 @return YES, if the system has successfully started the connection process. (it may return NO mostly with EA devices if the session can't be opened)
 */
- (BOOL)connectWithUsername:(NSString*_Nullable)username password:(NSString*_Nullable)password;

/**
 * Disconnects from the remote system.
 */
- (void)disconnect;

/**
 * Sends the specified command to the connected remote system
 * @param command The command to send to the remote system
 * @return YES, if the system is connected and the command can be sent, NO otherwise
 */
- (BOOL)sendCommand:(NSString *_Nonnull)command;

/**
 * Sends the specified command to the connected remote system
 
 Code samples:
 \code
[self.dataManSystem sendCommand:@"TRIGGER ON" withCallback:^(CDMResponse *response){
    if (response.status == DMCC_STATUS_NO_ERROR) {
        // command has succeed.
    } else {
        // handle error
    }
}];
\endcode
\code
[self.dataManSystem sendCommand:@"GET TRAINED-CODE.INFO" withCallback:^(CDMResponse *response){
    if (response.status == DMCC_STATUS_NO_ERROR) {
        if ([response.payload isEqualToString:@"Untrained"]) {
            // device is untrained
        } else {
            // device is trained
        }
    }
 }];
\endcode
 * @param command The command to send to the remote system
 * @param callback A callback that will be called when the command is completed
 * @return YES, if the system is connected and the command can be sent, NO otherwise
 */
- (BOOL)sendCommand:(NSString *_Nonnull)command withCallback:(void(^_Nullable)(CDMResponse * _Nonnull response))callback;

/**
 * Sends the specified command to the connected remote system.
 * @param command The command to send to the remote system
 * @param data Additional data to send to the remote system
 * @param timeout Timeout for the command
 * @param expectBinaryResponse Flag to signal if we expect binary response
 * @param callback A callback that will be called when the command is completed
 * @return YES, if the system is connected and the command can be sent, NO otherwise
 */
- (BOOL)sendCommand:(NSString *_Nonnull)command withData:(NSData *_Nullable)data timeout:(NSTimeInterval)timeout expectBinaryResponse:(BOOL)expectBinaryResponse callback:(void(^_Nullable)(CDMResponse *_Nonnull response))callback;

/**
 * Sends the specified commands array to the connected remote system
 * @param commands The array of commands to send to the remote system
 * @param complete A callback that will be called when all the commands are sent
 * @return YES, if the system is connected and the command can be sent, NO otherwise
 */
- (BOOL)sendBatchCommands:(NSArray *_Nonnull)commands completed:(void(^_Nonnull)(void))complete;

/** 
Changes whether the DataMan system accepts incoming messages or not. It does not effect an already connected device.
@param accept Flag to signal whether the incoming connection is accepted or not
 */
- (void)acceptIncomingConnection:(BOOL)accept;

/**
Enables heartbeat function and sets its interval.
@param interval Specifies heartbeat interval in seconds
 */
- (void)enableHeartbeatWithInterval:(NSTimeInterval)interval;

/**
 * Disables the heartbeat when enabled.
 */
- (void)disableHeartbeat;

/**
 *  Begins getting the latest image from the connected remote system in live display mode.
 *
 *  @param imageFormat Image format
 *  @param imageSize   Image size
 *  @param quality     Image quality
 *  @param callback    Callback block with image to be called when operation completes
 */
- (void)enableLiveImageWithFormat:(CDMImageFormat)imageFormat imageSize:(CDMImageSize)imageSize imageQuality:(CDMImageQuality)quality callback:(void(^_Nullable)(UIImage*_Nullable image, CDMResponse*_Nonnull response))callback;

/**
 *  Stops a pending live image retrieval operation.
 */
- (void)disableLiveImage;

@end
