//
//  NibssSocketManager.m
//  MyBluetoothTest
//
//  Created by Emmanuel Adeyemi on 2/11/16.
//  Copyright © 2016 Emmanuel Adeyemi. All rights reserved.
//

#import "NibssSocketManager.h"
#import "NSMutableData+NSMutableDataWithConversion.h"
#import "ISOBitmap.h"
#import "ISODataElement.h"
#import "ISOMessage.h"
#import "Global.h"
#import "PurchaseResponse.h"


@implementation NibssSocketManager{
    
    NSOutputStream* outputStream;
    NSInputStream* inputStream;
    int byteIndex;
    NSMutableData *dataRead;
    NSNumber *bytesRead;
    NSMutableData *toSend;
    BOOL isDone;
}


-(void)connectToNibss{
    
    byteIndex = 0;
    
    CFReadStreamRef _cfReadStreamRef;
    CFWriteStreamRef _cfWriteStreamRef;
    
    NSString* ip = @"196.6.103.18";
    int port = 5009;
    
    CFStreamCreatePairWithSocketToHost(nil, (__bridge CFStringRef)(ip), (UInt32)port, &_cfReadStreamRef, &_cfWriteStreamRef);
    
    NSDictionary *settings = [ [NSDictionary alloc ]
                              initWithObjectsAndKeys:
                              [NSNumber numberWithBool:YES], kCFStreamSSLAllowsExpiredCertificates,
                              [NSNumber numberWithBool:YES], kCFStreamSSLAllowsExpiredRoots,
                              [NSNumber numberWithBool:YES], kCFStreamSSLAllowsAnyRoot,
                              [NSNumber numberWithBool:NO], kCFStreamSSLValidatesCertificateChain,
                              kCFStreamSocketSecurityLevelTLSv1,kCFStreamSSLLevel,
                              nil ];
    
    CFReadStreamSetProperty(_cfReadStreamRef,
                            kCFStreamPropertySSLSettings, (CFTypeRef)settings);
    CFWriteStreamSetProperty(_cfWriteStreamRef,
                             kCFStreamPropertySSLSettings, (CFTypeRef)settings);
    
    
    inputStream =  ( NSInputStream *)(_cfReadStreamRef);
    outputStream = ( NSOutputStream *)(_cfWriteStreamRef);
    
    [inputStream setDelegate:self];
    [outputStream setDelegate:self];
    //
    [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    //
    [inputStream open];
    [outputStream open];
    
    while (!isDone)
    {
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    }
}


-(void)sendMessageToNibss:(NSMutableData *)data{
    
    toSend = data;

    [self connectToNibss];
    
}

-(void) sendMessage{
    
    NSMutableData *message  = toSend;
    
    uint8_t *readBytes = [message mutableBytes];
    //    readBytes += byteIndex; // instance variable to move pointer
    NSInteger data_len = [message length];
    
    uint8_t header[2];
    
    header[0] = data_len >> 8;
    header[1] = data_len;
    
    NSInteger len = ((data_len - byteIndex >= 1024) ?
                     1024 : (data_len-byteIndex));
    
    uint32_t buf[len];
    memcpy(buf, &readBytes, len);
    
    if(len > 0){
        [outputStream write:(uint8_t *)header maxLength:2];
        len = [outputStream write:readBytes maxLength:len];
    }
    
    byteIndex += len;
    
}

-(void)stream:(NSStream *)aStream
  handleEvent:(NSStreamEvent)eventCode{
    
    switch (eventCode) {
            
        case NSStreamEventErrorOccurred:{
            
            isDone = true;
            
            NSLog(@"Error occured while trying to open connection");
            
            NSError *error = [aStream streamError];
            
            NSLog(@"Error Description %@",[error localizedDescription]);
            
            NSLog(@"Error Reason %@",[error localizedFailureReason]);
            
            if(inputStream != nil){
                [inputStream release];
                inputStream = nil;
            }
            
            if(outputStream != nil){
                [outputStream release];
                outputStream = nil;
            }
            
            if(aStream != nil){
                [aStream release];
                aStream = nil;
            }
            
            // This stores the response code in a temporary storage
            [[NSUserDefaults standardUserDefaults] setObject:@"XX" forKey:RESPONSE_CODE];
            
            [[NSUserDefaults standardUserDefaults] setObject:@"unauthenticated" forKey:AUTH_CODE];
            
            [[NSUserDefaults standardUserDefaults] setObject:nil forKey:AUTH_DATA];
            
            [[NSUserDefaults standardUserDefaults] setObject:nil forKey:SCRIPT71];
            
            [[NSUserDefaults standardUserDefaults] setObject:nil forKey:SCRIPT72];
            
            
            break;
            
        }
        case NSStreamEventOpenCompleted:{
            
            byteIndex = 0;
            NSLog(@"Stream has started");
            break;
        }
        case NSStreamEventHasSpaceAvailable:{
   
            [self sendMessage];
            
            NSLog(@"Data can be sent to stream");
            break;
        }
        case NSStreamEventHasBytesAvailable:{
            
            NSLog(@"Reading message from nibss");
            
//            BOOL da = [inputStream hasBytesAvailable];
            
            //uint8_t buffer[1024];
            
            int len;
            
            do{
                
                uint8_t buffer[1024];
                
                NSLog(@"Size of buffer : %lu",sizeof(buffer));
                
                len = (int)[inputStream read:buffer maxLength:sizeof(buffer)];
                
                NSLog(@"Length of data %d",len);
                
                if(!dataRead && dataRead == nil){
                    dataRead = [[NSMutableData data] retain];
                }
                
                if(len && len > 0){
                    
                    [dataRead appendBytes:(const void *)buffer length:len];
                    
                    [bytesRead setIntValue:[bytesRead intValue]+len];
                }
                
            } while ([inputStream hasBytesAvailable]);
            
            
            break;
        }
        case NSStreamEventEndEncountered:{
            
            isDone = true;
            
            NSLog(@"This is the end of stream reading");
            
            if(dataRead.length > 0){
                
                NSLog(@"Log your message read");
                
                [self readMessageFromNibss];
                
            }else{
                
                // This stores the response code in a temporary storage
                [[NSUserDefaults standardUserDefaults] setObject:@"XX" forKey:RESPONSE_CODE];
                
                [[NSUserDefaults standardUserDefaults] setObject:@"unauthenticated" forKey:AUTH_CODE];
                
                [[NSUserDefaults standardUserDefaults] setObject:nil forKey:AUTH_DATA];
                
                [[NSUserDefaults standardUserDefaults] setObject:nil forKey:SCRIPT71];
                
                [[NSUserDefaults standardUserDefaults] setObject:nil forKey:SCRIPT72];
                
            }
            
            [inputStream close];
            [outputStream close];
            
            [inputStream release];
            [outputStream release];
            
            [dataRead release];
            
            aStream = nil;
            
            break;
        }
            
    }
}

-(void)readMessageFromNibss{
    
//    NSLog(<#NSString * _Nonnull format, ...#>)
    NSLog(@" Read data : %@ ",[[NSString alloc] initWithBytes:[dataRead bytes] length:[dataRead length] encoding:NSUTF8StringEncoding]);
    NSLog(@" Read data : %@ ",[dataRead hexadecimalCharacters]);
    
    NSString *responseString = [dataRead hexadecimalCharacters];
    
    ISOMessage *response = [[ISOMessage alloc] initWithIsoMessage:responseString];
    
    if(response != NULL){
        
        NSString *responseCodeEName = @"DE39";
//        NSString *field53EName = @"DE53";
        
        ISODataElement *dataElement = [response.dataElements objectForKey:responseCodeEName];
        NSString *responseCode = dataElement.value;
        
        NSLog(@"%@:%@", responseCodeEName, dataElement.value);
        
        if(responseCode.length > 0){
            
            // This stores the response code in a temporary storage
            [[NSUserDefaults standardUserDefaults] setObject:responseCode forKey:RESPONSE_CODE];
            
            NSLog(@" Message was read successfully ");
            
            // This is the autorization response code
            dataElement = [response.dataElements objectForKey:@"DE38"];
            
            if(dataElement != nil){
                NSString *temp = dataElement.value;
            
                NSLog(@"Auth code :  %@",temp);
            
                if(temp.length > 0)
                    [[NSUserDefaults standardUserDefaults] setObject:temp forKey:AUTH_CODE];
                else
                    [[NSUserDefaults standardUserDefaults] setObject:@"Unanthenticated" forKey:AUTH_CODE];
            }
            // This get the new ICC data from the response
            dataElement = [response.dataElements objectForKey:@"DE55"];
            
            if(dataElement != nil && [responseCode isEqualToString:@"00"]){
                
                NSString *temp = dataElement.value;
            
                NSLog(@"ICC DATA %@",temp);
            
                getICCResponse(temp);
            }else{
                [[NSUserDefaults standardUserDefaults] setObject:nil forKey:AUTH_DATA];
                
                [[NSUserDefaults standardUserDefaults] setObject:nil forKey:SCRIPT71];
                
                [[NSUserDefaults standardUserDefaults] setObject:nil forKey:SCRIPT72];
            }
            
        }else{
            
            // This stores the response code in a temporary storage
            [[NSUserDefaults standardUserDefaults] setObject:@"XX" forKey:RESPONSE_CODE];
            
            [[NSUserDefaults standardUserDefaults] setObject:@"unauthenticated" forKey:AUTH_CODE];
            
            [[NSUserDefaults standardUserDefaults] setObject:nil forKey:AUTH_DATA];
            
            [[NSUserDefaults standardUserDefaults] setObject:nil forKey:SCRIPT71];
            
            [[NSUserDefaults standardUserDefaults] setObject:nil forKey:SCRIPT72];
            
            NSLog(@"Response message %@",responseCode);
            NSLog(@"No data received from nibss");
        }
    }
}


static void getICCResponse(NSString *icc){
    int index91 = 20;
    long index71 = 0;
    int tempIndex = 0;
    
    // This will remove the length of the main data
    icc = [icc substringFromIndex:3];
    
    NSString *temp ;
    
//    while( icc.length > 0){
    
    temp = [icc substringWithRange:NSMakeRange(0, 4)];
    
    if([temp isEqualToString:@"9F36"]){
        
        // This add the length of the tag
        tempIndex += 4;
        
        temp = [icc substringFromIndex:tempIndex];
        
        // This gets the Length fromn the TAG LEN VAL
        NSString *len = [icc substringWithRange:NSMakeRange(tempIndex, 2)];
        
        tempIndex += 2;
        
        // This converts the hex length to decimal
        long val = strtol([len UTF8String], NULL, 16) * 2;
        
        // This gets the value of the based on tag
        temp = [icc substringWithRange:NSMakeRange(tempIndex, val)];
        
        tempIndex +=  val;
        
    }
    
    if(tempIndex >= icc.length)
        return ;
    
    temp = [icc substringWithRange:NSMakeRange(tempIndex, 2)];
    
    if([temp isEqualToString:@"91"]){
       
            // This is the length of the tag
        tempIndex += 2;
        
        // This gets the Length fromn the TAG LEN VAL
        NSString *len = [icc substringWithRange:NSMakeRange(tempIndex, 2)];
        tempIndex += 2;
        
        long val = strtol([len UTF8String], NULL, 16) * 2;
        
        temp = [icc substringWithRange:NSMakeRange(tempIndex, val)];
        
        tempIndex += val;
        
        // This helps in storing the authentication data
        [[NSUserDefaults standardUserDefaults] setObject:temp forKey:AUTH_DATA];
            
    }
    
    if(tempIndex >= icc.length)
        return ;
    
    temp = [icc substringWithRange:NSMakeRange(tempIndex, 2)];
    
    if([temp isEqualToString:@"71"]){
        
        tempIndex += 2;
        
        NSString *len = [icc substringWithRange:NSMakeRange(tempIndex, 2)];
        tempIndex += 2;
        
        long val = strtol([len UTF8String], NULL, 16) * 2;
        
        temp = [icc substringWithRange:NSMakeRange(tempIndex, val)];
        
        tempIndex += val;
        
        [[NSUserDefaults standardUserDefaults] setObject:temp forKey:SCRIPT71];
    }
    
    if(tempIndex >= icc.length)
        return ;
    
    // This is where the issuer script template 2 is checked for
    temp = [icc substringWithRange:NSMakeRange(tempIndex, 2)];
    
    if([temp isEqualToString:@"72"]){
        
        tempIndex += 2;
        
        NSString *len = [icc substringWithRange:NSMakeRange(tempIndex, 2)];
        tempIndex += 2;
        
        long val = strtol([len UTF8String], NULL, 16) * 2;
        
        temp = [icc substringWithRange:NSMakeRange(tempIndex, val)];
        
        tempIndex += val;
        
        [[NSUserDefaults standardUserDefaults] setObject:temp forKey:SCRIPT72];
    }
    
        
//    }
}



@end
