#import "Responsys.h"

static NSString *deviceId = nil;
static NSString *userId = nil;
static Boolean isLocation = true;
static Responsys *theRNResponsys = nil;
static Boolean handleMessage = true;

@implementation Responsys
{
    bool hasListeners;
}

+ (nonnull instancetype)instance {
    return theRNResponsys;
}

- (id)init {
    self = [super init];
    if (self != nil) {
        NSLog(@"Setting up Responsys instance");
        [self configure];
    }
    return self;
}

- (dispatch_queue_t)methodQueue
{
    return dispatch_get_main_queue();
}

+ (BOOL)requiresMainQueueSetup
{
    return NO;
}

- (void)configure {
    
    // Set static instance for use from AppDelegate
    theRNResponsys = self;
}


- (BOOL) didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    //2. Set the UNUserNotificationCenter delegate
    [UNUserNotificationCenter currentNotificationCenter].delegate = self;
    
    //Call at the end
    [[PushIOManager sharedInstance] didFinishLaunchingWithOptions:launchOptions];
    return YES;
}

- (void) didRegisterForRemoteNotificationsWithDeviceToken:
(NSData *)deviceToken
{
    [[PushIOManager sharedInstance]  didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}


- (void) didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
    [[PushIOManager sharedInstance] didFailToRegisterForRemoteNotificationsWithError:error];
}

-(void) didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo
{
    
    if ([[PushIOManager sharedInstance] isResponsysPayload: userInfo]) {
        [[PushIOManager sharedInstance] didReceiveRemoteNotification:userInfo];
    } else {
        //** Call Other SDKs ``didReceiveRemoteNotification:`` method
        [[PushIOManager sharedInstance] didReceiveRemoteNotification:userInfo];
    }
    [self sendEvent:self someBody:userInfo];
    NSLog(@"send Event has listener didreceiveremotenotification");
}

- (void) didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
    if ([[PushIOManager sharedInstance] isResponsysPayload:userInfo ]) {
        [[PushIOManager sharedInstance] didReceiveRemoteNotification:userInfo
                                               fetchCompletionResult:UIBackgroundFetchResultNewData fetchCompletionHandler:completionHandler];
    } else {
        [[PushIOManager sharedInstance] didReceiveRemoteNotification:userInfo
                                               fetchCompletionResult:UIBackgroundFetchResultNewData fetchCompletionHandler:completionHandler];
    }
    [self sendEvent:self someBody:userInfo];
    NSLog(@"send Event has listener application");
}

// UNUserNotificationCenterDelegate methods

- (void) userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
    
    if ([[PushIOManager sharedInstance] isResponsysPayload: notification.request.content.userInfo ]) {
        [[PushIOManager sharedInstance] userNotificationCenter:center willPresentNotification:notification
                                         withCompletionHandler:completionHandler];
        [self sendEvent:self someBody:notification];
    } else {
        [[PushIOManager sharedInstance] userNotificationCenter:center willPresentNotification:notification
                                         withCompletionHandler:completionHandler];
        [self sendEvent:self someBody:notification];
    }
    NSLog(@"send Event has listener willPresentNotification");
}

- (void) userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler {
    if ([[PushIOManager sharedInstance] isResponsysPayload: response.notification.request.content.userInfo ]) {
        [[PushIOManager sharedInstance] userNotificationCenter:center didReceiveNotificationResponse:response
                                         withCompletionHandler:completionHandler];
        [self sendEvent:self someBody:response];
    } else {
        [[PushIOManager sharedInstance] userNotificationCenter:center didReceiveNotificationResponse:response
                                         withCompletionHandler:completionHandler];
        //        [self sendEvent:response];
        [self sendEvent:self someBody:response];
    }
    NSLog(@"send Event has listener userNotificationCenter");
}

RCT_EXPORT_MODULE()

RCT_EXPORT_METHOD(sampleMethod:(NSString *)stringArgument numberParameter:(nonnull NSNumber *)numberArgument callback:(RCTResponseSenderBlock)callback)
{
    // TODO: Implement some actually useful functionality
	callback(@[[NSString stringWithFormat: @"numberArgument: %@ stringArgument: %@", numberArgument, stringArgument]]);
}

- (NSString *)stringWithDate:(NSDate *)date
{
    return [NSDateFormatter localizedStringFromDate:date
                                          dateStyle:NSDateFormatterMediumStyle
                                          timeStyle:NSDateFormatterNoStyle];
}
RCT_EXPORT_METHOD(fetchMessagesForMessageCenter:(NSString *)messageCenter  callback:(RCTResponseSenderBlock)callback){
    __block NSArray *messageList = nil;
//    __block NSString *jsonString = nil;
    __block NSString *errorMessage = nil;
//    __weak typeof (self) weakSelf = self;
//    NSEnumerator *arrenum = [messageList objectEnumerator];
//    id cobj;
    [[PushIOManager sharedInstance]setMessageCenterEnabled:YES];
    [[PushIOManager sharedInstance] isMessageCenterEnabled];
    NSMutableArray *myArray = [NSMutableArray array];
    [[PushIOManager sharedInstance] fetchMessagesForMessageCenter:messageCenter CompletionHandler:^(NSError *error, NSArray *messages) {
        if (nil != error) {
            switch (error.code) {
                case PIOErrorCodeInvalidURL:
                    errorMessage = @"Message URL is invalid, check the provided message center name and retry.";
                    break;
                case PIOErrorCodeNoNetwork:
                    errorMessage = @"No Network available, check the device network and try again.";
                    break;
                case PIOErrorCodeMaximumRetryReached:
                    errorMessage = @"Maximum retrial for message fetch has reached, that's due to because response received was either 500 or 429.";
                    break;
                case PIOErrorCodeEmptyResponse:
                    errorMessage = @"Message list is empty.";
                    break;
                case PIOErrorCodeInvalidPayload:
                    errorMessage = @"Invalid response received.";
                    break;
                case PIOHTTTPStatusCodeInvalidAppOrAccountToken:
                    errorMessage = error.userInfo[@"ErrorStatus"];
                    break;
                case PIOHTTTPStatusCodeMCDisabled:
                    errorMessage = error.userInfo[@"ErrorStatus"];
                    break;
                case PIOHTTTPStatusCodeMCFailure:
                    errorMessage = error.userInfo[@"ErrorStatus"];
                    break;
                default:
                    errorMessage = error.description;
                    break;
            }
            callback(@[errorMessage, [NSNull null]]);
        }else{
            messageList = messages;
            for (PIOMCMessage *mcMessage in messageList) {
                NSLog(@"Message Subject: %@, %@, %@, %@, %@, %@, %@, %@, %@, %@", mcMessage.messageID, mcMessage.message, mcMessage.subject, mcMessage.sentTimestamp, mcMessage.expiryTimestamp, mcMessage.messageCenterName, mcMessage.iconURL, mcMessage.deeplinkURL, mcMessage.richMessageHTML, mcMessage.richMessageURL);
                NSMutableDictionary *bookListing = [NSMutableDictionary dictionary];
                [bookListing setObject: mcMessage.messageID  forKey: @"id"];
                if(mcMessage.message == nil)
                    [bookListing setObject: @"" forKey: @"message"];
                else
                    [bookListing setObject: mcMessage.message forKey: @"message"];
                if(mcMessage.subject == nil)
                    [bookListing setObject: @""  forKey: @"subject"];
                else
                    [bookListing setObject: mcMessage.subject  forKey: @"subject"];
                if(mcMessage.sentTimestamp == nil)
                    [bookListing setObject: @""  forKey: @"sentTimestamp"];
                else
                    [bookListing setObject: [self stringWithDate:mcMessage.sentTimestamp]  forKey: @"sentTimestamp"];
                if(mcMessage.expiryTimestamp == nil)
                    [bookListing setObject: @"" forKey:@"expiryTimestamp"];
                else
                    [bookListing setObject: [self stringWithDate:mcMessage.expiryTimestamp] forKey:@"expiryTimestamp"];
                if(mcMessage.messageCenterName == nil)
                    [bookListing setObject: @"" forKey:@"messageCenterName"];
                else
                    [bookListing setObject: mcMessage.messageCenterName forKey:@"messageCenterName"];
                if(mcMessage.iconURL == nil)
                    [bookListing setObject: @""  forKey: @"iconUrl"];
                else
                    [bookListing setObject: mcMessage.iconURL  forKey: @"iconUrl"];
                if(mcMessage.deeplinkURL == nil)
                    [bookListing setObject: @"" forKey:@"deeplinkURL"];
                else
                    [bookListing setObject: mcMessage.deeplinkURL forKey:@"deeplinkURL"];
                if(mcMessage.richMessageHTML == nil)
                    [bookListing setObject: @"" forKey:@"richMessageHTML"];
                else
                    [bookListing setObject: mcMessage.richMessageHTML forKey:@"richMessageHTML"];
                if(mcMessage.richMessageURL == nil)
                    [bookListing setObject: @"" forKey:@"richMessageURL"];
                else
                    [bookListing setObject: mcMessage.richMessageURL forKey:@"richMessageURL"];
                [myArray addObject:bookListing];
            }
            callback(@[[NSNull null], myArray]);
        }
    }];
}

RCT_EXPORT_METHOD(fetchRichContentForMessage:(NSString *)msgID callback:(RCTResponseSenderBlock)callback){
    [[PushIOManager sharedInstance] fetchRichContentForMessage:msgID CompletionHandler:^(NSError *error, NSString *messageID, NSString *content) {
        NSLog(@"MessageID: %@ RichContent: %@ Error: %@", messageID, content, error);
        if(error == nil){
            callback(@[[NSNull null], content]);
        }else{
            callback(@[error, [NSNull null]]);
        }
    }];
}

RCT_EXPORT_METHOD(setMessageCenterEnabled:(BOOL) value){
    if(value == true){
        [[PushIOManager sharedInstance]setMessageCenterEnabled:YES];
        [[PushIOManager sharedInstance] isMessageCenterEnabled];
    }else{
        [[PushIOManager sharedInstance]setMessageCenterEnabled:NO];
    }
}

RCT_EXPORT_METHOD(setCrashLoggingEnabled:(BOOL) value){
    if(value == true){
        [[PushIOManager sharedInstance] setCrashLoggingEnabled:YES];
    }else{
        [[PushIOManager sharedInstance] setCrashLoggingEnabled:NO];
    }
}

RCT_EXPORT_METHOD(setBadgeCount:(int) value){
    [[PushIOManager sharedInstance] setBadgeCount:value completionHandler:^(NSError *error, NSString *response) {
        if (nil == error) {
            // Badge count set and synced successfully.
        } else {
            // Error occurred, unable to sync and set badge count
            // Handle error. If required you can set app badge count locally by calling iOS API [[UIApplication sharedApplication] setApplicationIconBadgeNumber:2];
            NSLog(@"Unable to set badge count, reason: %@", error.description);
        }
    }];
}

RCT_EXPORT_METHOD(resetBadgeCount:(BOOL) forceSetBadge:(RCTResponseSenderBlock)callback){
    [[PushIOManager sharedInstance] resetBadgeCountWithCompletionHandler:^(NSError *error, NSString *response) {
        if (nil == error) {
            // Badge count set and synced successfully.
            callback(@[[NSNull null], response]);
        } else {
            // Error occurred, unable to sync and set badge count
            // Handle error. If required you can set app badge count locally by calling iOS app [[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
            callback(@[error.description, [NSNull null]]);
            NSLog(@"Unable to reset the badge count, reason: %@", error.description);
        }
    }];
}

RCT_EXPORT_METHOD(getBadgeCount:(RCTResponseSenderBlock)callback){
    int badgeCount = [[PushIOManager sharedInstance] getBadgeCount];
    callback(@[[NSNull null], @(badgeCount)]);
}

-(void) showAlert:(NSString *)message{
    dispatch_async(dispatch_get_main_queue(), ^{
        UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Message" message:message preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {}];
        [alert addAction:defaultAction];
        //    [self presentViewController:alert animated:YES completion:nil];
    });
}

RCT_EXPORT_METHOD(setPreference:(NSString *)Item:(NSString *)isi:(NSString *)type){
    if([type  isEqual: @"boolean"]){
        [[PushIOManager sharedInstance] setBoolPreference:isi forKey:Item];
    }
    if([type  isEqual: @"string"]){
        [[PushIOManager sharedInstance] setStringPreference:isi forKey:Item];
    }
    if([type  isEqual: @"number"]){
        [[PushIOManager sharedInstance] setNumberPreference:isi forKey:Item];
    }
}

RCT_EXPORT_METHOD(getPreference:(NSString *)Item callback:(RCTResponseSenderBlock)callback){
    PIOPreference *test = [[PushIOManager sharedInstance] getPreference:Item];
    NSMutableDictionary *bookListing = [NSMutableDictionary dictionary];
    NSString *tipe = nil;
    if(test == nil){
        callback(@[[NSNull null], [NSNull null]]);
    }else{
        if(test.type == 0){
            tipe = @"STRING";
        }
        if(test.type == 1){
            tipe = @"NUMBER";
        }
        if(test.type == 2){
            tipe = @"BOOLEAN";
        }
        [bookListing setObject: test.key  forKey: @"mKey"];
        [bookListing setObject: test.label  forKey: @"mLabel"];
        [bookListing setObject: tipe forKey: @"mType"];
        if(test.value == nil){
            [bookListing setObject: [NSNull null]  forKey: @"mValue"];
        }else{
            [bookListing setObject: test.value  forKey: @"mValue"];
        }
        callback(@[[NSNull null], bookListing]);
    }
    
}

RCT_EXPORT_METHOD(getPreferences:(RCTResponseSenderBlock)callback){
    NSArray *newsPreference = [[PushIOManager sharedInstance] getPreferences];
    NSLog(@"getPreferences value --> %@",newsPreference);
    if(newsPreference != nil){
        NSEnumerator *arrenum = [newsPreference objectEnumerator];
        id cobj;
        NSMutableArray *myArray = [NSMutableArray array];
        while ( cobj = [arrenum nextObject] ) {
            NSLog(@"isi preference --> %@", cobj);
            PIOPreference *test = cobj;
            NSMutableDictionary *bookListing = [NSMutableDictionary dictionary];
            NSString *tipe = nil;
            if(test.type == 0){
                tipe = @"STRING";
            }
            if(test.type == 1){
                tipe = @"NUMBER";
            }
            if(test.type == 2){
                tipe = @"BOOLEAN";
            }
            [bookListing setObject: test.key  forKey: @"mKey"];
            [bookListing setObject: test.label  forKey: @"mLabel"];
            [bookListing setObject: tipe forKey: @"mType"];
            if(test.value == nil){
                [bookListing setObject: [NSNull null]  forKey: @"mValue"];
            }else{
                [bookListing setObject: test.value  forKey: @"mValue"];
            }
            NSLog(@"Hasilnya --> %@, %@, %lu, %@", test.key, test.label, (unsigned long)test.type, test.value);
            [myArray addObject:bookListing];
        }
        callback(@[[NSNull null], myArray]);
    }else{
        callback(@[[NSNull null], [NSNull null]]);
    }
}

RCT_EXPORT_METHOD(clearAllPreferences){
    //Clear all preferences
    [[PushIOManager sharedInstance] clearAllPreferences];
}

RCT_EXPORT_METHOD(clearAllPreferences:(NSString *)value){
    //Remove individual preference
    NSError *error = nil;
    [[PushIOManager sharedInstance] removePreference:value error:&error];
    if(nil != error){
        NSLog(@"Unable to remove preference, reason: %@",error);
    }
}

RCT_EXPORT_METHOD(resetBadgeCountWithCompletionHandler:(RCTResponseSenderBlock)callback){
    NSError *error = nil;
    [[PushIOManager sharedInstance] resetBadgeCountWithCompletionHandler:^(NSError *error, NSString *response) {
        if (nil == error) {
            // Badge count set and synced successfully.
        } else {
            // Error occurred, unable to sync and set badge count
            // Handle error. If required you can set app badge count locally by calling iOS app [[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
            NSLog(@"Unable to reset the badge count, reason: %@", error.description);
        }
    }];
}

RCT_EXPORT_METHOD(declarePreference:(NSString *)Item forIsi:(NSString *)isi forType:(NSString *)type){
    NSError *error = nil;
    NSLog(@"set declarePreference bridge");
    if([type  isEqual: @"boolean"]){
        [[PushIOManager sharedInstance] declarePreference:Item label:isi type:PIOPreferenceTypeBoolean error:&error];
        if (error != nil) {
            // Examine error
        }
    }
    if([type  isEqual: @"string"]){
        [[PushIOManager sharedInstance] declarePreference:Item label:isi type:PIOPreferenceTypeString error:&error];
        if (error != nil) {
            // Examine error
        }
    }
    if([type  isEqual: @"number"]){
        [[PushIOManager sharedInstance] declarePreference:Item label:isi type:PIOPreferenceTypeNumeric error:&error];
        if (error != nil) {
            // Examine error
        }
    }
}

RCT_EXPORT_METHOD(initializeApp:(NSString *)apiKey forAccountToken:(NSString *)accountToken){
    NSLog(@"initializeApp module");
    //------------------------------  Toggle Logging  --------------------------------//
    /*Default log level is set to Info. Refer to PushIOManager.h to know about other different log levels available.*/
    
#ifdef DEBUG
    [[PushIOManager sharedInstance] setLoggingEnabled:YES];
    [[PushIOManager sharedInstance] setLogLevel:PIOLogLevelVerbose];
#else
    [[PushIOManager sharedInstance] setLoggingEnabled:NO];
#endif
    
    //---------------------------- Configure and Register the SDK ------------------------//
    
    NSError *error = nil;
    
    [[PushIOManager sharedInstance] configureAndRegisterWithAPIKey:apiKey accountToken:accountToken completionHandler:^(NSError *error, NSString *response){
        if (nil == error){
            NSLog(@"Application registered successfully");
        }else{
            NSLog(@"Unable to configure and register, reason:%@",error.description);
        }
    }];
    
    //--------------------------- Register for Push with Responsys Backend ---------------------//
    /*The application is registered with Oracle Responsys Push backend without prompting for opt-in to push notifications.*/
    
    NSError *regTrackError = nil;
    
    [[PushIOManager sharedInstance] registerApp:&regTrackError completionHandler:^(NSError *regAppError, NSString *response)
     {
         if (nil == regAppError){
             NSLog(@"Application registered successfully!");
         }else{
             NSLog(@"Unable to register application, reason: %@", regAppError.description);
         }
     }];
    
    
    
    //------------------------------  Opt-in to Push Notifications ------------------------------//
    /*The user is prompted a dialogue to opt-in for push notifications. If the user chooses to opt-in ,the following sync event's permissions will include permissions needed for Push.
     If the user chooses to opt-out now, then inorder to opt-in to Push notifications in the future they will have to go to system settings -> notifications ,then select the application and use the toggle switch.*/
    
    [[PushIOManager sharedInstance] registerForAllRemoteNotificationTypes:^(NSError *error, NSString *deviceToken)
     {
         if (nil == error) {
             NSError *regTrackError = nil;
             [[PushIOManager sharedInstance] registerApp:&regTrackError completionHandler:^(NSError *regAppError, NSString *response)
              {
                  if (nil == regAppError){
                      NSLog(@"Application registered successfully!");
                  }else{
                      NSLog(@"Unable to register application, reason: %@", regAppError.description);
                  }
              }];
             if (nil == regTrackError) {
                 NSLog(@"Registration locally stored successfully.");
             }else{
                 NSLog(@"Unable to store registration, reason: %@", regTrackError.description);
             }
         }
     }];
    
    
    //------------------------------  Opt-in for location  ------------------------------//
    /*The user is prompted a dialogue to opt-in for location updates. If the user chooses to opt-in, the following sync with Responsys backend server will have updated value for permissions field now including 'location_active' . Furthermore all future syncs will have latitude and longitude values as a part of the sync event data unless they opt-out of it.*/
    
    [[PushIOManager sharedInstance] setDesiredLocationAccuracy:10.0];
    [[PushIOManager sharedInstance] setDistanceFilter:500];
    [[PushIOManager sharedInstance] startUpdatingLocationForPush];
}

//RCT_EXPORT_METHOD(initializeApp){
//    NSLog(@"initializeApp");
//    //------------------------------  Toggle Logging  --------------------------------//
//    /*Default log level is set to Info. Refer to PushIOManager.h to know about other different log levels available.*/
//
//#ifdef DEBUG
//    [[PushIOManager sharedInstance] setLoggingEnabled:YES];
//    [[PushIOManager sharedInstance] setLogLevel:PIOLogLevelVerbose];
//#else
//    [[PushIOManager sharedInstance] setLoggingEnabled:NO];
//#endif
//
//    //---------------------------- Configure and Register the SDK ------------------------//
//
//    NSString *apiKey = @"ABEvnYpCLWVqXrfE69HvQ8W5E";
//    NSString *accountToken = @"ABEqWKT9aENU0Sbr-iPuf9mY0";
//
//    NSError *error = nil;
//
//    [[PushIOManager sharedInstance] configureAndRegisterWithAPIKey:apiKey accountToken:accountToken completionHandler:^(NSError *error, NSString *response){
//        if (nil == error){
//            NSLog(@"Application registered successfully");
//        }else{
//            NSLog(@"Unable to configure and register, reason:%@",error.description);
//        }
//    }];
//
//    //--------------------------- Register for Push with Responsys Backend ---------------------//
//    /*The application is registered with Oracle Responsys Push backend without prompting for opt-in to push notifications.*/
//
//    NSError *regTrackError = nil;
//
//    [[PushIOManager sharedInstance] registerApp:&regTrackError completionHandler:^(NSError *regAppError, NSString *response)
//     {
//         if (nil == regAppError){
//             NSLog(@"Application registered successfully!");
//         }else{
//             NSLog(@"Unable to register application, reason: %@", regAppError.description);
//         }
//     }];
//
//
//
//    //------------------------------  Opt-in to Push Notifications ------------------------------//
//    /*The user is prompted a dialogue to opt-in for push notifications. If the user chooses to opt-in ,the following sync event's permissions will include permissions needed for Push.
//     If the user chooses to opt-out now, then inorder to opt-in to Push notifications in the future they will have to go to system settings -> notifications ,then select the application and use the toggle switch.*/
//
//    [[PushIOManager sharedInstance] registerForAllRemoteNotificationTypes:^(NSError *error, NSString *deviceToken)
//     {
//         if (nil == error) {
//             NSError *regTrackError = nil;
//             [[PushIOManager sharedInstance] registerApp:&regTrackError completionHandler:^(NSError *regAppError, NSString *response)
//              {
//                  if (nil == regAppError){
//                      NSLog(@"Application registered successfully!");
//                  }else{
//                      NSLog(@"Unable to register application, reason: %@", regAppError.description);
//                  }
//              }];
//             if (nil == regTrackError) {
//                 NSLog(@"Registration locally stored successfully.");
//             }else{
//                 NSLog(@"Unable to store registration, reason: %@", regTrackError.description);
//             }
//         }
//     }];
//
//
//    //------------------------------  Opt-in for location  ------------------------------//
//    /*The user is prompted a dialogue to opt-in for location updates. If the user chooses to opt-in, the following sync with Responsys backend server will have updated value for permissions field now including 'location_active' . Furthermore all future syncs will have latitude and longitude values as a part of the sync event data unless they opt-out of it.*/
//
//    [[PushIOManager sharedInstance] setDesiredLocationAccuracy:10.0];
//    [[PushIOManager sharedInstance] setDistanceFilter:500];
//    [[PushIOManager sharedInstance] startUpdatingLocationForPush];
//}

RCT_EXPORT_METHOD(trackEvent:(NSString *)strTrackEvent){
    [[PushIOManager sharedInstance] trackEvent:strTrackEvent];
}

RCT_EXPORT_METHOD(registerApp:(NSString *)apiKeyDebug forAccountToken:(NSString *)accountTokenDebug
                  apiKeyRelease:(NSString *)apiKeyRelease accountTokenRelease:(NSString *)accountTokenRelease){
    NSString *apiKey = nil;
    NSString *accountToken = nil;
    #ifdef DEBUG
        apiKey = apiKeyDebug; //Copy the apiKey value from pushio_config_debug.json
        accountToken = accountTokenDebug; //Copy the accountToken value from pushio_config_debug.json. Assign nil if no value available.
    #else
        apiKey = apiKeyRelease; //Copy the apiKey value from pushio_config.json.
        accountToken = accountTokenRelease;//Copy the accountToken value from pushio_config.json. Assign nil if no value available.
    #endif
    #ifdef DEBUG
        [[PushIOManager sharedInstance] setLoggingEnabled:YES];
//        [[PushIOManager sharedInstance] setLogLevel:PIOLogLevelVerbose];
    #else
        [[PushIOManager sharedInstance] setLoggingEnabled:NO];
    #endif
    
    //---------------------------- Configure and Register the SDK ------------------------//
    
    NSError *error = nil;
    
    [[PushIOManager sharedInstance] registerForAllRemoteNotificationTypes:^(NSError *error, NSString *deviceToken)
     {
         if (nil == error) {
             NSError *regTrackError = nil;
//             [[PushIOManager sharedInstance] registerApp:&regTrackError completionHandler:^(NSError *regAppError, NSString *response)
//              {
//                  if (nil == regAppError){
//                      NSLog(@"Application registered successfully!");
//                  }else{
//                      NSLog(@"Unable to register application, reason: %@", regAppError.description);
//                  }
//              }];
             [[PushIOManager sharedInstance] configureAndRegisterWithAPIKey:apiKey accountToken:accountToken completionHandler:^(NSError *error, NSString *response){
                 if (nil == error){
                     NSLog(@"Application registered successfully");
                 }else{
                     NSLog(@"Unable to configure and register, reason:%@",error.description);
                 }
             }];
             if (nil == regTrackError) {
                 NSLog(@"Registration locally stored successfully.");
             }else{
                 NSLog(@"Unable to store registration, reason: %@", regTrackError.description);
             }
         }
     }];
    //--------------------------- Register for Push with Responsys Backend ---------------------//
    /*The application is registered with Oracle Responsys Push backend without prompting for opt-in to push notifications.*/
    
    NSError *regTrackError = nil;
    
//    [[PushIOManager sharedInstance] registerApp:&regTrackError completionHandler:^(NSError *regAppError, NSString *response)
//     {
//         if (nil == regAppError){
//             NSLog(@"Application registered successfully!");
//         }else{
//             NSLog(@"Unable to register application, reason: %@", regAppError.description);
//         }
//     }];
    
    [[PushIOManager sharedInstance] setDesiredLocationAccuracy:10.0];
    [[PushIOManager sharedInstance] setDistanceFilter:500];
    [[PushIOManager sharedInstance] startUpdatingLocationForPush];
    
//    [[PushIOManager sharedInstance] configureWithFileName:@"c.json" completionHandler:^(NSError *error, NSString *response) {
//        if(nil == error)
//        {
//            NSLog(@"SDK Configured Successfully");
//            [[PushIOManager sharedInstance] registerForAllRemoteNotificationTypes:^(NSError *error, NSString *deviceToken)
//             {
//                 if (nil == error) {
//                     NSError *regTrackError = nil;
//                     [[PushIOManager sharedInstance] registerApp:&regTrackError completionHandler:^(NSError *regAppError, NSString *response)
//                      {
//                          if (nil == regAppError){
//                              NSLog(@"Application registered successfully!");
//                          }else{
//                              NSLog(@"Unable to register application, reason: %@", regAppError.description);
//                          }
//                      }];
//                 } else {
//                     NSLog(@"Unable to register application, reason: %@", error.description);
//                 }
//             }];
//            
//        }
//        else
//        {
//            NSLog(@"Unable to configure SDK, reason: %@", error.description);
//        }
//        
//    }];
    deviceId = [[PushIOManager sharedInstance] getDeviceID];
//    [[PushIOManager sharedInstance] didFinishLaunchingWithOptions:launchOptions];
}

RCT_EXPORT_METHOD(getDeviceId:(RCTResponseSenderBlock)callback){
    deviceId = [[PushIOManager sharedInstance] getDeviceID];
    if(deviceId == nil){
        callback(@[[NSNull null], [NSNull null]]);
    }else{
        callback(@[[NSNull null], deviceId]);
    }
}

RCT_EXPORT_METHOD(getUserId:(RCTResponseSenderBlock)callback){
    userId = [[PushIOManager sharedInstance] getUserID];
    if(userId == nil){
        callback(@[[NSNull null], [NSNull null]]);
    }else{
        callback(@[[NSNull null], userId]);
    }
}

RCT_EXPORT_METHOD(getRegisteredUserId:(RCTResponseSenderBlock)callback){
    userId = [[PushIOManager sharedInstance] getUserID];
    if(userId == nil){
        callback(@[[NSNull null], [NSNull null]]);
    }else{
        callback(@[[NSNull null], userId]);
    }
}

RCT_EXPORT_METHOD(registerUserId:(NSString *) userId){
    [[PushIOManager sharedInstance] registerUserID:userId];
}

RCT_EXPORT_METHOD(unregisterUserId){
    [[PushIOManager sharedInstance] registerUserID:nil];
}

RCT_EXPORT_METHOD(setLoggingEnabled:(NSString *)isian){
    NSLog(@"setLogLevel to logLevel");
}

RCT_EXPORT_METHOD(startUpdatingLocationForPush){
    [[PushIOManager sharedInstance] startUpdatingLocationForPush];
}

RCT_EXPORT_METHOD(setInAppFetchEnabled:(BOOL *)isian){
//    if([isian isEqualToString:@"YES"])
        [[PushIOManager sharedInstance] setInAppMessageFetchEnabled:isian];
//    if([isian isEqualToString:@"NO"])
//        [[PushIOManager sharedInstance] setInAppMessageFetchEnabled:NO];
}

RCT_EXPORT_METHOD(trackEngagement:(NSString *)engagement){
    if([engagement isEqualToString:@"PUSHIO_ENGAGEMENT_METRIC_INAPP_PURCHASE"])
        [[PushIOManager sharedInstance] trackEngagementMetric:PUSHIO_ENGAGEMENT_METRIC_INAPP_PURCHASE];
    if([engagement isEqualToString:@"PUSHIO_ENGAGEMENT_METRIC_PREMIUM_CONTENT"])
        [[PushIOManager sharedInstance] trackEngagementMetric:PUSHIO_ENGAGEMENT_METRIC_PREMIUM_CONTENT];
    if([engagement isEqualToString:@"PUSHIO_ENGAGEMENT_METRIC_SOCIAL"])
        [[PushIOManager sharedInstance] trackEngagementMetric:PUSHIO_ENGAGEMENT_METRIC_SOCIAL];
    if([engagement isEqualToString:@"PUSHIO_ENGAGEMENT_METRIC_OTHER"])
        [[PushIOManager sharedInstance] trackEngagementMetric:PUSHIO_ENGAGEMENT_METRIC_OTHER];
    if([engagement isEqualToString:@"PUSHIO_ENGAGEMENT_METRIC_PURCHASE"])
        [[PushIOManager sharedInstance] trackEngagementMetric:PUSHIO_ENGAGEMENT_METRIC_PURCHASE];
}

RCT_EXPORT_METHOD(trackEngagement:(NSString *)engagement key:(NSString *)key value:(NSString *)value:(RCTResponseSenderBlock)callback){
    if([engagement isEqualToString:@"PUSHIO_ENGAGEMENT_METRIC_INAPP_PURCHASE"])
        [[PushIOManager sharedInstance] trackEngagementMetric:PUSHIO_ENGAGEMENT_METRIC_INAPP_PURCHASE withProperties:@{key:value} completionHandler:^(NSError *error, NSString *response) {
            if(error == nil)
                error = (NSError *)[NSNull null];
            if(response == nil)
                response = (NSString *)[NSNull null];
            callback(@[error, response]);
        }];
    if([engagement isEqualToString:@"PUSHIO_ENGAGEMENT_METRIC_PREMIUM_CONTENT"])
        [[PushIOManager sharedInstance] trackEngagementMetric:PUSHIO_ENGAGEMENT_METRIC_PREMIUM_CONTENT withProperties:@{key:value} completionHandler:^(NSError *error, NSString *response) {
            if(error == nil)
                error = (NSError *)[NSNull null];
            if(response == nil)
                response = (NSString *)[NSNull null];
            callback(@[error, response]);
        }];
    if([engagement isEqualToString:@"PUSHIO_ENGAGEMENT_METRIC_SOCIAL"])
        [[PushIOManager sharedInstance] trackEngagementMetric:PUSHIO_ENGAGEMENT_METRIC_SOCIAL withProperties:@{key:value} completionHandler:^(NSError *error, NSString *response) {
            if(error == nil)
                error = (NSError *)[NSNull null];
            if(response == nil)
                response = (NSString *)[NSNull null];
            callback(@[error, response]);
        }];
    if([engagement isEqualToString:@"PUSHIO_ENGAGEMENT_METRIC_OTHER"])
        [[PushIOManager sharedInstance] trackEngagementMetric:PUSHIO_ENGAGEMENT_METRIC_OTHER withProperties:@{key:value} completionHandler:^(NSError *error, NSString *response) {
            if(error == nil)
                error = (NSError *)[NSNull null];
            if(response == nil)
                response = (NSString *)[NSNull null];
            callback(@[error, response]);
        }];
    if([engagement isEqualToString:@"PUSHIO_ENGAGEMENT_METRIC_PURCHASE"])
        [[PushIOManager sharedInstance] trackEngagementMetric:PUSHIO_ENGAGEMENT_METRIC_PURCHASE withProperties:@{key:value} completionHandler:^(NSError *error, NSString *response) {
            if(error == nil)
                error = (NSError *)[NSNull null];
            if(response == nil)
                response = (NSString *)[NSNull null];
            callback(@[error, response]);
        }];
}

RCT_EXPORT_METHOD(addInteractiveNotificationCategory:(NSString *)category_identifier action_identifier1:(NSString *)action_identifier1 ActionTitle1:(NSString *)ActionTitle1 action_identifier2:(NSString *)action_identifier2 ActionTitle2:(NSString *)ActionTitle2){
    UNNotificationCategoryOptions notificationOptions = UNNotificationCategoryOptionCustomDismissAction; // Define the category options.
//    PIONotificationCategory *newCategory = [[PIONotificationCategory alloc] initWithIdentifier:@"category_identifier" actions:@[] intentIdentifiers:@[] hiddenPreviewsBodyPlaceholder:@"" options:notificationOptions];
    PIONotificationAction *action1 = [[PIONotificationAction alloc]initWithIdentifier:action_identifier1 title:ActionTitle1 isDestructive:NO isForeground:YES isAuthenticationRequired:YES];
    PIONotificationAction *action2 = [[PIONotificationAction alloc]initWithIdentifier:action_identifier2 title:ActionTitle2 isDestructive:NO isForeground:YES isAuthenticationRequired:YES];
    NSArray *intentIdentifiers = @[]; //The intents supported support for notifications of this category. See <Intents/INIntentIdentifiers.h> for possible values.
    NSString *placeholder = @"Awesome content hidden inside the notification"; // When preview is disabled from settings, this placeholder text is displayed.
    // For a category with two buttons, this is where you would put the second button.
    NSArray *actions = @[action1, action2]; // Add the list of actions you want to group together. See next section for what this would look like with two buttons.
//    UNNotificationCategoryOptions notificationOptions = UNNotificationCategoryOptionCustomDismissAction; // Define the category options.
    PIONotificationCategory *newCategory = [[PIONotificationCategory alloc] initWithIdentifier:category_identifier actions:actions intentIdentifiers:intentIdentifiers hiddenPreviewsBodyPlaceholder:placeholder options:notificationOptions];
    [[PushIOManager sharedInstance] registerForAllRemoteNotificationTypesWithCategories:@[newCategory] completionHandler:^(NSError *error, NSString *response) {
        if (nil == error) {
            NSError *regError = nil;
            [[PushIOManager sharedInstance] registerApp:&regError completionHandler:^(NSError *rError, NSString *response) {
                if (nil == rError) {
                    NSLog(@"Registration successful");
                }else{
                    NSLog(@"Error while trying to register. Error: %@", rError);
                }
            }];
            if (nil == regError) {
                NSLog(@"Registration requested successfully");
            }else{
                NSLog(@"Error while trying to request register. Error: %@", regError);
            }
        }else{
            NSLog(@"Error while trying to get device token from APNS. Error: %@", error);
        }
    }];
}

RCT_EXPORT_METHOD(setExecuteRsysWebURL:(BOOL)param){
    [[PushIOManager sharedInstance] setExecuteRsysWebURL:param];
}

RCT_EXPORT_METHOD(setAdvertisingID:(NSString *)advertisingIdentifierValue){
    [[PushIOManager sharedInstance] setAdvertisingIdentifier:advertisingIdentifierValue];
}

RCT_EXPORT_METHOD(getAdvertisingID:(RCTResponseSenderBlock)callback){
    NSString *advid = [[PushIOManager sharedInstance] advertisingIdentifier];
    if(advid == nil){
        callback(@[[NSNull null], [NSNull null]]);
    }else{
        callback(@[[NSNull null], advid]);
    }
}

RCT_EXPORT_METHOD(setExternalDeviceTrackingID:(NSString *)externalDeviceTrackingIDValue){
    [[PushIOManager sharedInstance] setExternalDeviceTrackingID:externalDeviceTrackingIDValue];
}

RCT_EXPORT_METHOD(getExternalDeviceTrackingID:(RCTResponseSenderBlock)callback){
    NSString *extdid = [[PushIOManager sharedInstance] externalDeviceTrackingID];
    if(extdid == nil){
        callback(@[[NSNull null], [NSNull null]]);
    }else{
        callback(@[[NSNull null], extdid]);
    }
}

RCT_EXPORT_METHOD(getAPIKey:(RCTResponseSenderBlock)callback){
    NSString *apiKey = [[PushIOManager sharedInstance] getAPIKey];
    if(apiKey == nil){
        callback(@[[NSNull null], [NSNull null]]);
    }else{
        callback(@[[NSNull null], apiKey]);
    }
}

RCT_EXPORT_METHOD(resolvedURL:(NSNotification *)notification){
    NSString *deeplinkURL = notification.userInfo[PIOResolvedDeeplinkURL];
    NSString *weblinkURL = notification.userInfo[PIOResolvedWeblinkURL];
    NSString *requestURL = notification.userInfo[PIORequestedWebURL];
    BOOL isPubwebURLType = [notification.userInfo[PIORequestedWebURLIsPubWebType] boolValue];
    NSError *error = notification.userInfo[PIOErrorResolveWebURL];
}

RCT_EXPORT_METHOD(setLogLevel:(NSString *)logLevel) {
    NSLog(@"setLogLevel to logLevel");
#ifdef DEBUG
    [[PushIOManager sharedInstance] setLoggingEnabled:YES];
    if([logLevel  isEqualToString:@"info"])
        [[PushIOManager sharedInstance] setLogLevel:PIOLogLevelInfo]; //PIOLogLevelWarn or PIOLogLevelError
    if([logLevel  isEqualToString:@"verbose"])
        [[PushIOManager sharedInstance] setLogLevel:PIOLogLevelVerbose]; //PIOLogLevelWarn or PIOLogLevelError
    if([logLevel  isEqualToString:@"debug"])
        [[PushIOManager sharedInstance] setLogLevel:PIOLogLevelDebug]; //PIOLogLevelWarn or PIOLogLevelError
    if([logLevel  isEqualToString:@"error"])
        [[PushIOManager sharedInstance] setLogLevel:PIOLogLevelError]; //PIOLogLevelWarn or PIOLogLevelError
    if([logLevel  isEqualToString:@"warn"])
        [[PushIOManager sharedInstance] setLogLevel:PIOLogLevelWarn]; //PIOLogLevelWarn or PIOLogLevelError
    if([logLevel  isEqualToString:@"assert"])
        [[PushIOManager sharedInstance] setLogLevel:PIOLogLevelNone]; //PIOLogLevelWarn or PIOLogLevelError
#else
    [[PushIOManager sharedInstance] setLoggingEnabled:YES];
    if([logLevel  isEqualToString:@"info"])
        [[PushIOManager sharedInstance] setLogLevel:PIOLogLevelInfo]; //PIOLogLevelWarn or PIOLogLevelError
    if([logLevel  isEqualToString:@"verbose"])
        [[PushIOManager sharedInstance] setLogLevel:PIOLogLevelVerbose]; //PIOLogLevelWarn or PIOLogLevelError
    if([logLevel  isEqualToString:@"debug"])
        [[PushIOManager sharedInstance] setLogLevel:PIOLogLevelDebug]; //PIOLogLevelWarn or PIOLogLevelError
    if([logLevel  isEqualToString:@"error"])
        [[PushIOManager sharedInstance] setLogLevel:PIOLogLevelError]; //PIOLogLevelWarn or PIOLogLevelError
    if([logLevel  isEqualToString:@"warn"])
        [[PushIOManager sharedInstance] setLogLevel:PIOLogLevelWarn]; //PIOLogLevelWarn or PIOLogLevelError
    if([logLevel  isEqualToString:@"assert"])
        [[PushIOManager sharedInstance] setLogLevel:PIOLogLevelNone]; //PIOLogLevelWarn or PIOLogLevelError
#endif
}


RCT_EXPORT_METHOD(onGeoRegionEntered:(NSString *)source zoneId:(NSString *)zoneId zoneName:(NSString *)zoneName
                  geofenceId:(NSString *)geofenceId geofenceName:(NSString *)geofenceName deviceSpeed:(double) deviceSpeed  deviceBearing:(double) deviceBearing extra:(NSDictionary *) extra){
//    NSMutableDictionary *dynamicDict=[[NSMutableDictionary alloc] extra];
    NSString *area = (NSString*)[extra objectForKey:@"area"];
    NSString *category = (NSString*)[extra objectForKey:@"category"];
    PIOGeoRegion *geoRegion = [[PIOGeoRegion alloc] initWithGeofenceId:geofenceId geofenceName:geofenceName  speed:deviceSpeed bearing:deviceBearing source:source zoneId:zoneId zoneName:zoneName dwellTime:0  extra:@{@"area":area, @"category":category}];
    [[PushIOManager sharedInstance] didEnterGeoRegion:geoRegion completionHandler:^(NSError *error, NSString *response) {
        if (nil == error) {
            //Geofence Entry Event triggered successfully
        } else {
            NSLog(@"Unable to send Geofence Entry Event, reason: %@", error.description);
        }
    }];
}
                  
 RCT_EXPORT_METHOD(onGeoRegionExited:(NSString *)source zoneId:(NSString *)zoneId zoneName:(NSString *)zoneName
                   geofenceId:(NSString *)geofenceId geofenceName:(NSString *)geofenceName deviceSpeed:(double) deviceSpeed  deviceBearing:(double) deviceBearing extra:(NSDictionary *) extra){
//     NSMutableDictionary *dynamicDict=[[NSMutableDictionary alloc]extra];
     NSString *area = (NSString*)[extra objectForKey:@"area"];
     NSString *category = (NSString*)[extra objectForKey:@"category"];
    PIOGeoRegion *geoRegion = [[PIOGeoRegion alloc] initWithGeofenceId:geofenceId geofenceName:geofenceName  speed:deviceSpeed bearing:deviceBearing source:source zoneId:zoneId zoneName:zoneName dwellTime:0  extra:@{@"area":area, @"category":category}];
    [[PushIOManager sharedInstance] didExitGeoRegion:geoRegion completionHandler:^(NSError *error, NSString *response) {
        if (nil == error) {
            //Geofence Entry Event triggered successfully
        } else {
            NSLog(@"Unable to send Geofence Entry Event, reason: %@", error.description);
        }
    }];
}

RCT_EXPORT_METHOD(setPushNotificationEnable:(Boolean *)val){
    handleMessage = val;
}

RCT_EXPORT_METHOD(onBeaconRegionEntered:(NSString *)source zoneId:(NSString *)zoneId zoneName:(NSString *)zoneName
                  beaconId:(NSString *)beaconId beaconName:(NSString *)beaconName beaconTag:(NSString *)beaconTag
                  iBeaconUUID:(NSString *)iBeaconUUID iBeaconMajor:(NSString *)iBeaconMajor iBeaconMinor:(NSString *)iBeaconMinor eddyStoneId1:(NSString *)eddyStoneId1 eddyStoneId2:(NSString *)eddyStoneId2 proximity:(NSString *)proximity extra:(NSDictionary *) extra){
//    NSMutableDictionary *dynamicDict=[[NSMutableDictionary alloc]extra];
    NSString *area = (NSString*)[extra objectForKey:@"area"];
    NSString *category = (NSString*)[extra objectForKey:@"category"];
    NSString *proximityString;
    if([proximity  isEqual: @"CLProximityUnknown"]){
        proximityString = @"Unknown";
    }
    if([proximity  isEqual: @"CLProximityImmediate"]){
        proximityString = @"Immediate";
    }
    if([proximity  isEqual: @"CLProximityNear"]){
        proximityString = @"Near";
    }
    if([proximity  isEqual: @"CLProximityFar"]){
        proximityString = @"Far";
    }
    PIOBeaconRegion *beaconRegion = [[PIOBeaconRegion alloc] initWithiBeaconUUID:iBeaconUUID iBeaconMajor:iBeaconMajor iBeaconMinor:iBeaconMinor beaconId:beaconId beaconName:beaconName beaconTag:beaconTag proximity:proximityString source:source zoneId:zoneId zoneName:zoneName dwellTime:0 extra:  @{@"area":area, @"category":category}];
    [[PushIOManager sharedInstance] didEnterBeaconRegion:beaconRegion completionHandler:^(NSError *error, NSString *response) {
        if (nil == error) {
            //Beacon Entry Event triggered successfully
        } else {
            NSLog(@"Unable to send Beacon Entry Event, reason: %@", error.description);
        }
    }];
}

RCT_EXPORT_METHOD(onBeaconRegionExited:(NSString *)source zoneId:(NSString *)zoneId zoneName:(NSString *)zoneName
                  beaconId:(NSString *)beaconId beaconName:(NSString *)beaconName beaconTag:(NSString *)beaconTag
                  iBeaconUUID:(NSString *)iBeaconUUID iBeaconMajor:(NSString *)iBeaconMajor iBeaconMinor:(NSString *)iBeaconMinor eddyStoneId1:(NSString *)eddyStoneId1 eddyStoneId2:(NSString *)eddyStoneId2 proximity:(NSString *)proximity extra:(NSDictionary *) extra){
//    NSMutableDictionary *dynamicDict=[[NSMutableDictionary alloc]extra];
    NSString *area = (NSString*)[extra objectForKey:@"area"];
    NSString *category = (NSString*)[extra objectForKey:@"category"];
    NSString *proximityString;
    if([proximity  isEqual: @"CLProximityUnknown"]){
        proximityString = @"Unknown";
    }
    if([proximity  isEqual: @"CLProximityImmediate"]){
        proximityString = @"Immediate";
    }
    if([proximity  isEqual: @"CLProximityNear"]){
        proximityString = @"Near";
    }
    if([proximity  isEqual: @"CLProximityFar"]){
        proximityString = @"Far";
    }
    
    PIOBeaconRegion *beaconRegion = [[PIOBeaconRegion alloc] initWithiBeaconUUID:iBeaconUUID iBeaconMajor:iBeaconMajor iBeaconMinor:iBeaconMinor beaconId:beaconId beaconName:beaconName beaconTag:beaconTag proximity:proximityString source:source zoneId:zoneId zoneName:zoneName dwellTime:10 extra:  @{@"area":area, @"category":category}];
    [[PushIOManager sharedInstance] didExitBeaconRegion:beaconRegion completionHandler:^(NSError *error, NSString *response) {
        if (nil == error) {
            //Beacon Exit Event triggered successfully
        } else {
            NSLog(@"Unable to send Beacon Exit Event, reason: %@", error.description);
        }
    }];
}

- (NSArray<NSString *> *)supportedEvents {
    return @[@"messaging_message_received"];
}

// Will be called when this module's first listener is added.
-(void)startObserving {
    hasListeners = YES;
}

// Will be called when this module's last listener is removed, or on dealloc.
-(void)stopObserving {
    hasListeners = NO;
}

- (void)sendEvent:(RCTEventEmitter *)emitter someBody:(NSObject *) someBody{
    if (hasListeners) {
        NSLog(@"send Event has listener");
        [self sendEventWithName:@"messaging_message_received" body:@{@"body": someBody}];
    }else{
        NSLog(@"send Event has no listener");
        [self sendEventWithName:@"messaging_message_received" body:@{@"body": someBody}];
    }
}

@end
