/********* CMBScanner.m Cordova Plugin Implementation *******/

#import <Cordova/CDV.h>
#import <cmbSDK/cmbSDK.h>
#import <CMBCrossPlatform/CMBCrossPlatform.h>

#pragma INTERFACE
@interface CMBScanner : CDVPlugin {
    
}

// CMBReaderDeviceDelegate Cordova callbacks
-(void)didReceiveReadResultFromReaderCallback:(CDVInvokedUrlCommand*)cdvCommand;
-(void)availabilityDidChangeOfReaderCallback:(CDVInvokedUrlCommand*)cdvCommand;
-(void)connectionStateDidChangeOfReaderCallback:(CDVInvokedUrlCommand*)cdvCommand;

// public methods
-(void)loadScanner:(CDVInvokedUrlCommand*)cdvCommand;
-(void)getAvailability:(CDVInvokedUrlCommand*)cdvCommand;
-(void)getSdkVersion:(CDVInvokedUrlCommand*)cdvCommand;
-(void)enableImage:(CDVInvokedUrlCommand*)cdvCommand;
-(void)enableImageGraphics:(CDVInvokedUrlCommand*)cdvCommand;
-(void)getConnectionState:(CDVInvokedUrlCommand*)cdvCommand;
-(void)connect:(CDVInvokedUrlCommand*)cdvCommand;
-(void)startScanning:(CDVInvokedUrlCommand*)cdvCommand;
-(void)stopScanning:(CDVInvokedUrlCommand*)cdvCommand;
-(void)getDeviceBatteryLevel:(CDVInvokedUrlCommand*)cdvCommand;
-(void)setSymbologyEnabled:(CDVInvokedUrlCommand*)cdvCommand;
-(void)isSymbologyEnabled:(CDVInvokedUrlCommand*)cdvCommand;
-(void)setLightsOn:(CDVInvokedUrlCommand*)cdvCommand;
-(void)isLightsOn:(CDVInvokedUrlCommand*)cdvCommand;
-(void)resetConfig:(CDVInvokedUrlCommand*)cdvCommand;
-(void)sendCommand:(CDVInvokedUrlCommand*)cdvCommand;
-(void)setPreviewContainerPositionAndSize:(CDVInvokedUrlCommand*)cdvCommand;
-(void)setPreviewContainerBelowStatusBar:(CDVInvokedUrlCommand*)cdvCommand;
-(void)setPreviewContainerFullScreen:(CDVInvokedUrlCommand*)cdvCommand;
-(void)setCameraMode:(CDVInvokedUrlCommand*)cdvCommand;
-(void)setPreviewOptions:(CDVInvokedUrlCommand*)cdvCommand;
-(void)disconnect:(CDVInvokedUrlCommand*)cdvCommand;
-(void)beep:(CDVInvokedUrlCommand*)cdvCommand;
-(void)registerSDK:(CDVInvokedUrlCommand*)cdvCommand;
-(void)enableCameraFlag:(CDVInvokedUrlCommand*)cdvCommand;
-(void)disableCameraFlag:(CDVInvokedUrlCommand*)cdvCommand;
-(void)setCameraParam:(CDVInvokedUrlCommand*)cdvCommand;
-(void)setCameraDuplicatesTimeout:(CDVInvokedUrlCommand*)cdvCommand;
-(void)setPreviewOverlayMode:(CDVInvokedUrlCommand*)cdvCommand;
-(void)showToast:(CDVInvokedUrlCommand*)cdvCommand;
-(void)hideToast:(CDVInvokedUrlCommand*)cdvCommand;
-(void)checkCameraPermission:(CDVInvokedUrlCommand*)cdvCommand;
-(void)requestCameraPermission:(CDVInvokedUrlCommand*)cdvCommand;
-(void)setParser:(CDVInvokedUrlCommand*)cdvCommand;
-(void)setReadStringEncoding:(CDVInvokedUrlCommand*)cdvCommand;
-(void)setStopScannerOnRotate:(CDVInvokedUrlCommand*)cdvCommand;
-(void)scanImageFromUri:(CDVInvokedUrlCommand*)cdvCommand;
-(void)scanImageFromBase64:(CDVInvokedUrlCommand*)cdvCommand;
-(void)setMDMReportingEnabled:(CDVInvokedUrlCommand*)cdvCommand;
-(void)createMDMAuthCredentials:(CDVInvokedUrlCommand*)cdvCommand;
-(void)getCameraExposureCompensationRange:(CDVInvokedUrlCommand*)cdvCommand;
-(void)setCameraExposureCompensation:(CDVInvokedUrlCommand*)cdvCommand;
-(void)loadCameraConfig:(CDVInvokedUrlCommand*)cdvCommand;
-(void)setPairedBluetoothDevice:(CDVInvokedUrlCommand*)cdvCommand;
-(void)getPairedBluetoothDevice:(CDVInvokedUrlCommand*)cdvCommand;
@end

// CMBReaderDevice delegate
@interface CMBScanner() <CMBReaderDeviceDelegate, CMBObserversDelegate>

@property CCPBridge *cmb;

@end
#pragma END INTERFACE


#pragma IMPLEMENTATION
@implementation CMBScanner

// CMBReaderDeviceDelegate Cordova callbacks
NSString *didReceiveReadResultFromReaderCallbackID;
NSString *availabilityDidChangeOfReaderCallbackID;
NSString *connectionStateDidChangeOfReaderCallbackID;
NSString *scanningStateChangedCallbackID;

- (CCPCompletionWithResponse)createResponseForCommand:(CDVInvokedUrlCommand *)cdvCommand {
    NSString *callbackId = cdvCommand.callbackId;
    
    return ^(NSString *errorCode, NSString *response) {
        CDVPluginResult *result;
        
        if ([errorCode intValue] != 0) {
            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:response];
        } else {
            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:response];
        }
        
        [self.commandDelegate sendPluginResult:result callbackId:callbackId];
    };
}

- (void)pluginInitialize {
    self.cmb = [[CCPBridge alloc] init];
    self.cmb.ccpPluginDelegate = self;
    self.cmb.ccpPluginScanningStateDelegate = self;
}

-(void)loadScanner:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb initReaderWithClass:[cdvCommand.arguments.firstObject intValue] callback:^{
        CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool:YES];
        [self.commandDelegate sendPluginResult:result callbackId:cdvCommand.callbackId];
    }];
}

-(void)connect:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb connect:[self createResponseForCommand:cdvCommand]];
}

-(void)disconnect:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb disconnect:[self createResponseForCommand:cdvCommand]];
}

-(void)startScanning:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb startScanning:[self createResponseForCommand:cdvCommand]];
}

-(void)stopScanning:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb stopScanning:[self createResponseForCommand:cdvCommand]];
}

-(void)setSymbologyEnabled:(CDVInvokedUrlCommand*)cdvCommand {
    int symbology = [cdvCommand.arguments[0] intValue];
    BOOL enabled = [cdvCommand.arguments[1] boolValue];
    
    [self.cmb setSymbology:symbology enabled:enabled completion:[self createResponseForCommand:cdvCommand]];
}

-(void)isSymbologyEnabled:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb isSymbologyEnabled:[cdvCommand.arguments.firstObject intValue] completion:[self createResponseForCommand:cdvCommand]];
}

-(void)setCameraMode:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb setCameraMode:[cdvCommand.arguments.firstObject intValue]];
}

-(void)setPreviewOptions:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb setPreviewOptions:[cdvCommand.arguments.firstObject intValue]];
}

-(void)setPreviewOverlayMode:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb setPreviewOverlayMode:[cdvCommand.arguments.firstObject intValue]];
}

-(void)setPreviewContainerPositionAndSize:(CDVInvokedUrlCommand*)cdvCommand {
    float positionX = [cdvCommand.arguments[0] floatValue];
    float positionY = [cdvCommand.arguments[1] floatValue];
    float width = [cdvCommand.arguments[2] floatValue];
    float height = [cdvCommand.arguments[3] floatValue];
    
    [self.cmb setPreviewContainerPositionAndSizeX:positionX Y:positionY width:width height:height];
}

-(void)setPreviewContainerBelowStatusBar:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb setPreviewContainerBelowStatusBar:[cdvCommand.arguments.firstObject boolValue]];
}

-(void)setPreviewContainerFullScreen:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb setPreviewContainerFullScreenWithCompletion:[self createResponseForCommand:cdvCommand]];
}

-(void)setLightsOn:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb setLightsOn:[cdvCommand.arguments.firstObject boolValue] completion:[self createResponseForCommand:cdvCommand]];
}

-(void)isLightsOn:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb isLightsOnWithCompletion:[self createResponseForCommand:cdvCommand]];
}

-(void)enableImage:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb enableImage:[cdvCommand.arguments.firstObject boolValue] completion:[self createResponseForCommand:cdvCommand]];
}

-(void)enableImageGraphics:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb enableImageGraphics:[cdvCommand.arguments.firstObject boolValue] completion:[self createResponseForCommand:cdvCommand]];
}

-(void)sendCommand:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb sendCommand:cdvCommand.arguments.firstObject completion:[self createResponseForCommand:cdvCommand]];
}

-(void)resetConfig:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb resetConfigWithCompletion:[self createResponseForCommand:cdvCommand]];
}

-(void)registerSDK:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb registerSDK:cdvCommand.arguments.firstObject];
}

-(void)getAvailability:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb getAvailability:[self createResponseForCommand:cdvCommand]];
}

-(void)getConnectionState:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb getConnectionState:[self createResponseForCommand:cdvCommand]];
}

-(void)beep:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb beep:[self createResponseForCommand:cdvCommand]];
}

-(void)getDeviceBatteryLevel:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb getDeviceBatteryLevel:[self createResponseForCommand:cdvCommand]];
}

-(void)getSdkVersion:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb getSdkVersion:[self createResponseForCommand:cdvCommand]];
}

-(void)setStopScannerOnRotate:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb setStopScannerOnRotate:[cdvCommand.arguments.firstObject boolValue]];
}

-(void)enableCameraFlag:(CDVInvokedUrlCommand*)cdvCommand {
    int mask = [cdvCommand.arguments.firstObject intValue];
    int flag = [cdvCommand.arguments[1] intValue];
    
    [self.cmb enableCameraFlag:flag forMask:mask completion:[self createResponseForCommand:cdvCommand]];
}

-(void)disableCameraFlag:(CDVInvokedUrlCommand*)cdvCommand {
    int mask = [cdvCommand.arguments.firstObject intValue];
    int flag = [cdvCommand.arguments[1] intValue];
    
    [self.cmb disableCameraFlag:flag forMask:mask completion:[self createResponseForCommand:cdvCommand]];
}

-(void)setCameraParam:(CDVInvokedUrlCommand*)cdvCommand {
    int mask = [cdvCommand.arguments.firstObject intValue];
    int param = [cdvCommand.arguments[1] intValue];
    int value = [cdvCommand.arguments[2] intValue];
    
    [self.cmb setCameraParam:param paramValue:value forMask:mask completion:[self createResponseForCommand:cdvCommand]];
}

-(void)setCameraDuplicatesTimeout:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb sendCommand:[NSString stringWithFormat:@"SET DECODER.REREAD-TIME %d", ([cdvCommand.arguments.firstObject intValue] * 1000)] completion:[self createResponseForCommand:cdvCommand]];
}

- (void)getCameraExposureCompensationRange:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb getCameraExposureCompensationRange:[self createResponseForCommand:cdvCommand]];
}

- (void)setCameraExposureCompensation:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb setCameraExposureCompensation:[cdvCommand.arguments.firstObject floatValue] completion:[self createResponseForCommand:cdvCommand]];
}

-(void)setParser:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb setParser:[cdvCommand.arguments.firstObject boolValue] completion:[self createResponseForCommand:cdvCommand]];
}

-(void)setReadStringEncoding:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb setReadStringEncoding:[cdvCommand.arguments.firstObject intValue] completion:[self createResponseForCommand:cdvCommand]];
}

-(void)setMDMReportingEnabled:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb setMDMReportingEnabled:[cdvCommand.arguments.firstObject boolValue]];
}

-(void)createMDMAuthCredentials:(CDVInvokedUrlCommand*)cdvCommand {
    NSDictionary *commandArguments = [[cdvCommand arguments] firstObject];
    NSString *username = commandArguments[@"username"];
    NSString *password = commandArguments[@"password"];
    NSString *clientID = commandArguments[@"clientID"];
    NSString *clientSecret = commandArguments[@"clientSecret"];
    
    [self.cmb createMDMAuthCredentialsWithUsername:username password:password clientID:clientID clientSecret:clientSecret];
}

-(void)showToast:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb showMessage:[cdvCommand.arguments firstObject]];
}

-(void)hideToast:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb hideMessage];
}

-(void)checkCameraPermission:(CDVInvokedUrlCommand*)cdvCommand {
    [CCPUtilities checkCameraPermission:^(BOOL status, int value) {
        CDVCommandStatus resultStatus = status ? CDVCommandStatus_OK : CDVCommandStatus_ERROR;
        CDVPluginResult *result = [CDVPluginResult resultWithStatus:resultStatus messageAsInt:value];
       
        [self.commandDelegate sendPluginResult:result callbackId:cdvCommand.callbackId];
    }];
}

-(void)requestCameraPermission:(CDVInvokedUrlCommand*)cdvCommand {
    [CCPUtilities requestCameraPermission:^(BOOL status, int value) {
        CDVCommandStatus resultStatus = status ? CDVCommandStatus_OK : CDVCommandStatus_ERROR;
        CDVPluginResult *result = [CDVPluginResult resultWithStatus:resultStatus messageAsInt:value];
        
        [self.commandDelegate sendPluginResult:result callbackId:cdvCommand.callbackId];
    }];
}

#pragma MARK CMBReaderDeviceDelegate Cordova callbacks

-(void)didReceiveReadResultFromReaderCallback:(CDVInvokedUrlCommand*)cdvCommand {
    didReceiveReadResultFromReaderCallbackID = cdvCommand.callbackId;
}

-(void)setActiveStartScanningCallback:(CDVInvokedUrlCommand*)cdvCommand {
    scanningStateChangedCallbackID = cdvCommand.callbackId;
}

-(void)availabilityDidChangeOfReaderCallback:(CDVInvokedUrlCommand*)cdvCommand {
    availabilityDidChangeOfReaderCallbackID = cdvCommand.callbackId;
}

-(void)connectionStateDidChangeOfReaderCallback:(CDVInvokedUrlCommand*)cdvCommand {
    connectionStateDidChangeOfReaderCallbackID = cdvCommand.callbackId;
}

#pragma MARK CMBReaderDevice Delegate

- (void)availabilityDidChangeOfReader:(CMBReaderDevice *)reader {
    if (availabilityDidChangeOfReaderCallbackID) {
        CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:(int)reader.availability];
        [result setKeepCallbackAsBool:YES];
        [self.commandDelegate sendPluginResult:result callbackId:availabilityDidChangeOfReaderCallbackID];
    }
}

- (void)connectionStateDidChangeOfReader:(CMBReaderDevice *)reader {
    if (connectionStateDidChangeOfReaderCallbackID) {
        CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:reader?(int)reader.connectionState:0];
        [result setKeepCallbackAsBool:YES];
        [self.commandDelegate sendPluginResult:result callbackId:connectionStateDidChangeOfReaderCallbackID];
    }
}

- (void)didReceiveReadResultFromReader:(CMBReaderDevice *)reader results:(CMBReadResults *)readResults {
    NSString *jsonString = [CCPUtilities getResultsJSONStringFromResults:readResults keyResults:@"readResults" keySubResults:@"subReadResults"];

    NSError *jsonError;
    NSData *objectData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
    NSDictionary *json = [NSJSONSerialization JSONObjectWithData:objectData
                                          options:NSJSONReadingMutableContainers
                                            error:&jsonError];

    CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:json];
    [result setKeepCallbackAsBool:YES];
    [self.commandDelegate sendPluginResult:result callbackId:didReceiveReadResultFromReaderCallbackID];
}

- (void)scanningStateChanged:(BOOL)isScanning {
    if (scanningStateChangedCallbackID) {
        CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool:isScanning];
        [result setKeepCallbackAsBool:YES];
        [self.commandDelegate sendPluginResult:result callbackId:scanningStateChangedCallbackID];
    }
}

-(void)scanImageFromUri:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb scanImageFromUri:[cdvCommand.arguments firstObject] completion:[self createResponseForCommand:cdvCommand]];
}

-(void)scanImageFromBase64:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb scanImageFromBase64:[cdvCommand.arguments firstObject] completion:[self createResponseForCommand:cdvCommand]];
}

-(void)loadCameraConfig:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb loadCameraConfig:[self createResponseForCommand:cdvCommand]];
}

-(void)setPairedBluetoothDevice:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb setPairedBluetoothDevice:[cdvCommand.arguments firstObject]];
}

-(void)getPairedBluetoothDevice:(CDVInvokedUrlCommand*)cdvCommand {
    [self.cmb getPairedBluetoothDevice:[self createResponseForCommand:cdvCommand]];
}

@end
