/*---------------------------------------------------------------------------*/
/* NotificationService.m                                                     */
/* copyright (c) innovaphone 2015                                            */
/*                                                                           */
/*---------------------------------------------------------------------------*/

#import "NotificationService.h"

#import "platform/platform.h"
#import "platform/IosNamespace.h"
#import "client/ios/ios_ilib/JsonIo.h"
#import "client/ios/ios_ilib/Cipher.h"

Dl_info dlinfo_ = {0,0,0,0};
void nslog_print(const char *line) {}
void nslog_printv(const char *format, va_list ap) {}

@interface NotificationService ()

@property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
@property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;

@end

@implementation NotificationService

static byte hex_to_byte(char hi, char lo)
{
    return ((byte)(((hi - (((hi >= '0') && (hi <= '9')) ? '0' : (((hi >= 'a') && (hi <= 'z')) ? 'a' - 10 : 'A' - 10))) << 4) |
        (lo - (((lo >= '0') && (lo <= '9')) ? '0' : (((lo >= 'a') && (lo <= 'z')) ? 'a' - 10 : 'A' - 10)))));
}

- (void) didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler
{
    unsigned i;

    self.contentHandler = contentHandler;
    self.bestAttemptContent = [request.content mutableCopy];
    NSDictionary *userData = request.content.userInfo[@"data"];
    NSString *payloadData = userData[@"payloadData"];
    if (payloadData == nil) {
        self.bestAttemptContent.body = @"Error: no payload data";
    }
    else {
        JsonIo *payloadDataJson = [JsonIo jsonIo];
        if (!payloadDataJson.decode(payloadData)) {
            self.bestAttemptContent.body = @"Error: payload data not json";
        }
        else {
            word dataRoot = payloadDataJson.get_object(JSON_ID_ROOT, nil);
            NSString *type = payloadDataJson.get_string(dataRoot, @"type");
            NSString *salt = payloadDataJson.get_string(dataRoot, @"salt");
            NSString *dataString = payloadDataJson.get_string(dataRoot, @"data");
            if ((type == nil) || (salt == nil) || (dataString == nil)) {
                self.bestAttemptContent.body = @"Error: no type salt data";
            }
            else {
                NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@PHONE_IOS_APP_GROUP_ID];
                NSString *pushPassword = [userDefaults stringForKey:@"pushPassword"];
                if (pushPassword == nil) {
                    self.bestAttemptContent.body = @"Error: no password";
                }
                else {
                    unsigned passwordLen = (unsigned)(pushPassword.length / 2);
                    NSMutableData *key = [NSMutableData dataWithLength:salt.length + 1 + passwordLen];
                    for (i = 0; i < salt.length; i++) {
                        ((byte *)(key.mutableBytes))[i] = (byte)([salt characterAtIndex:i]);
                    }
                    ((byte *)(key.mutableBytes))[salt.length] = ':';
                    for (i = 0; i < passwordLen; i++) {
                        ((byte *)(key.mutableBytes))[salt.length + 1 + i] = hex_to_byte([pushPassword characterAtIndex:2*i], [pushPassword characterAtIndex:2*i+1]);
                    }
                    unsigned dataLen = (unsigned)(dataString.length / 2);
                    NSMutableData *data = [NSMutableData dataWithLength:dataLen];
                    for (i = 0; i < dataLen; i++) {
                        ((byte *)(data.mutableBytes))[i] = hex_to_byte([dataString characterAtIndex:2*i], [dataString characterAtIndex:2*i+1]);
                    }
                    Cipher *cipher = [[Cipher alloc] init];
                    cipher.Init(CIPHER_RC4, (byte *)(key.mutableBytes), (int)(key.length), false);
                    NSMutableData *payload = [NSMutableData dataWithLength:dataLen];
                    cipher.Crypt((byte *)(data.mutableBytes), (byte *)(payload.mutableBytes), dataLen);
                    NSString *payloadString = [[NSString alloc] initWithData:payload encoding:NSUTF8StringEncoding];
                    if (payloadString == nil) {
                        self.bestAttemptContent.body = @"Error: cannot decrypt payload";
                    }
                    else {
                        JsonIo *payloadJson = [JsonIo jsonIo];
                        if (!payloadJson.decode(payloadString)) {
                            self.bestAttemptContent.body = @"Error: failed decrypt payload";
                        }
                        else {
                            word root = payloadJson.get_object(JSON_ID_ROOT, nil);
                            if ([type isEqualToString:@"notification"]) {
                                NSString *ref = payloadJson.get_string(root, @"ref");
                                if (ref == nil) {
                                    ref = @"";
                                }
                                NSString *title = payloadJson.get_string(root, @"title");
                                NSString *text = payloadJson.get_string(root, @"text");
                                NSString *soundUrl = payloadJson.get_string(root, @"soundUrl");

                                if ((title != nil) && (title.length != 0)) {
                                    self.bestAttemptContent.title = title;
                                }
                                self.bestAttemptContent.body = ((text != nil) && (text.length != 0)) ?
                                    [text stringByReplacingOccurrencesOfString:@"%" withString:@"%%"] : @" ";
                                if ((soundUrl != nil) && (soundUrl.length != 0)) {
                                    self.bestAttemptContent.sound = [soundUrl isEqualToString:@"*"] ? [UNNotificationSound defaultSound] : [UNNotificationSound soundNamed:soundUrl];
                                }
                            }
                            else {
                                self.bestAttemptContent.body = @"Error: unknown type";
                            }
                        }
                    }
                }
            }
        }
    }
    self.contentHandler(self.bestAttemptContent);
}

- (void) serviceExtensionTimeWillExpire
{
    // Called just before the extension will be terminated by the system.
    // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
    self.contentHandler(self.bestAttemptContent);
}

@end
