
#import "PaypadFacade.h"
#import <Cordova/CDV.h>
#import "Global.h"
#import <Foundation/Foundation.h>
#import "EMVTransactionManager.h"
// #import "EMVTransactionManagerVas.h"
#import "EMVRequest.h"


@implementation PaypadFacade{
    NSString *commandId;
}

#define OP_NONE 0
#define OP_PIN 1
#define OP_SIGNATURE 2
#define OP_AMOUNT 3

#define POS_NORMAL 0
#define POS_FLIPPED 1

int operation;
int position=-1;
BOOL payPassPresent=FALSE;
BOOL scPresent=FALSE;
BOOL isDone;

int state;
int presentC;

NSOutputStream* outputStream;
NSInputStream* inputStream;
PinpadKeysRequest_Builder *pinpadRequestBuilder;

NSString* bdk;
NSString* pinkey;
NSString* dupktTr31;
NSString* tmkTr31;
NSString* dataTr31;
NSString* sessionKey;
NSString* parameter;
bool doVasM;
bool canPrint;
bool hasPaper = true;

- (void) initialization : (CDVInvokedUrlCommand*)command{

	// This is for initialization
	CDVPluginResult* pluginResult = nil;

	// This gets the terminal id
    NSString* terminalId = [command.arguments objectAtIndex:0];

    // This determines if the app needs vas for implementation
    NSString* doVas = [command.arguments objectAtIndex:1];

    //doVasM = doVas;

    if(terminalId.length <= 0){
    	pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Terminal Id is not provided"];
    	[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];

    	 return ;
    }    

    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    [dict setValue:@"initialization" forKey:@"operation"];

    // This is where we check if the initialization has been done before with PINPAD
    NSString *serialS = [[NSUserDefaults standardUserDefaults] objectForKey:PINPAD_SERIAL];

    if(serialS){

        NSString* serialDevice =  [PinpadHelper getDeviceSerial:dtdev];

        if([serialDevice isEqualToString:serialS]){

            [dict setValue:@"already_initialised" forKey:@"status"];

            pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dict];
            [pluginResult setKeepCallback:[NSNumber numberWithBool:NO]];
            [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];

            return ;
        }
    }


    [[NSUserDefaults standardUserDefaults] setObject:terminalId forKey:TERMINAL_ID];

    [[NSUserDefaults standardUserDefaults] setObject:command.callbackId forKey:@"COMMANDID"];

    // [

     // dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(void){

     [self.commandDelegate runInBackground:^{

        CDVPluginResult* pluginResult = nil;

        // This is used in storing the commandID which will be use in passing the response 
        // back to client
    

        // NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        // [dict setValue:@"initialization" forKey:@"operation"];
        [dict setValue:@"initialization" forKey:@"operation"];
        [dict setValue:@"downloading_keys" forKey:@"status"];
        pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dict];
        [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
        [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];

        [self connectToServer:@"178.62.57.125" port:55505];
    }];

}


-(void)connectToServer:(NSString *)ip port:(NSUInteger)port{
    
    if([ip isEqualToString:@""] || [ip isEqualToString:nil]){
        NSLog(@"Invalid target Id");
        return;
    }

    CFReadStreamRef _cfReadStreamRef;
    CFWriteStreamRef _cfWriteStreamRef;
    
    
    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:YES], kCFStreamSSLValidatesCertificateChain,
                              kCFStreamSocketSecurityLevelNegotiatedSSL,
                              kCFStreamSSLLevel,
                              nil ];
    
    CFReadStreamSetProperty(_cfReadStreamRef,
                            kCFStreamPropertySSLSettings, (CFTypeRef)settings);
    CFWriteStreamSetProperty(_cfWriteStreamRef,
                             kCFStreamPropertySSLSettings, (CFTypeRef)settings);
    
    inputStream =  ( NSInputStream *)(_cfReadStreamRef); // objc_unretainedObject(_cfReadStreamRef);
    outputStream = ( NSOutputStream *)(_cfWriteStreamRef); //objc_unretainedObject(_cfWriteStreamRef);
    
    [inputStream setDelegate:self];
    [outputStream setDelegate:self];
    //
    //
    [inputStream open];
    [outputStream open];
    //
    
    NSString *terminalId = [[NSUserDefaults standardUserDefaults] objectForKey:TERMINAL_ID];
    NSString *serialD = [[NSUserDefaults standardUserDefaults] objectForKey:PINPAD_CPU_SERIAL];
    
    // [[NSUserDefaults standardUserDefaults] setObject:terminalId forKey:TERMINAL_ID];

    NSLog(@"Serial IN connection %@",serial);
    pinpadRequestBuilder = [PinpadKeysRequest builder];
    [pinpadRequestBuilder setTerminalId:terminalId];
    [pinpadRequestBuilder setSerialNo:serialD];
    // [pinpadRequestBuilder setVas:false];
    self.pinkeyRequest = [pinpadRequestBuilder build];

    dispatch_async(dispatch_get_main_queue(),^{
        [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    });
    
    [serial release];
}


- (void) connection : (CDVInvokedUrlCommand*)command{


    // This is called to connect to pinpad

    if(dtdev.connstate == CONN_CONNECTED){
        CDVPluginResult* pluginResult = nil;

        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        [dict setValue:@"connection" forKey:@"operation"];
        [dict setValue:@"already_connected)" forKey:@"status"];
        

        pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dict];
        [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];

        [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
    }else{

        [self.commandDelegate runInBackground:^{
            CDVPluginResult* pluginResult = nil;

            NSMutableDictionary *dict = [NSMutableDictionary dictionary];
            [dict setValue:@"connection" forKey:@"operation"];
            [dict setValue:@"connecting" forKey:@"status"];

            pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dict];

            // This is used to make the thread wait for callback
            [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
            commandId = command.callbackId;

            [[NSUserDefaults standardUserDefaults] setObject:commandId forKey:@"COMMANDID"];

            [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];

            // This connects to the pinpad at this point
            [dtdev connect];
        }];
    }
}

-(void) pluginInitialize{

    UIAccelerometer *accel = [UIAccelerometer sharedAccelerometer];
    accel.delegate = self;
    accel.updateInterval = 20.0f/60.0f;
    
    dtdev=[DTDevices sharedDevice];
    [dtdev addDelegate:self];

    // This is used to store a weak reference to a delegate
    commandD = self.commandDelegate;
}

-(void)connectionState:(int)state {
    switch (state) {
        case CONN_DISCONNECTED:
            // [_connectStatus setText:@"Pinpad not connected"];

            break;
        case CONN_CONNECTING:{
            [[UIApplication sharedApplication] setIdleTimerDisabled: YES];
            NSLog(@"CONNECTING PINPAD");
            // [_connectStatus setText:@"Pinpad not connected"];
            break;
        }
        case CONN_CONNECTED:
        {
            [[UIApplication sharedApplication] setIdleTimerDisabled:YES];
            scPresent=[dtdev scInit:SLOT_MAIN error:nil];
            
            NSLog(@"Pinpad is connected");
            
            NSLog(@"Serial %@",[dtdev serialNumber]);
            
            // [_connectStatus setText:@"Pinpad connected"];
            
            NSError *error = [[NSError alloc] init];
            
//            DTDeviceInfo* info = [dtdev getConnectedDeviceInfo:DEVICE_TYPE_PINPAD error:&error];
            
//            NSArray *array = [dtdev getConnectedDevicesInfo:&error];
            
            DTPinpadInfo *info = [dtdev ppadGetSystemInfo:&error];
        
//            NSArray *connArray = [dtdev btConnectedDevices];
            
//            NSLog(@"The Len %d",[connArray count]);
            
            if(![info isEqual: nil]){
                
                // This gets the CPU serial from the user
                NSData *data = [info cpuSerial];
                
                serial = [self dataToHexstring:data];

                // this stores the CPU serial in a temporary storage
                [[NSUserDefaults standardUserDefaults] setObject:serial forKey:PINPAD_CPU_SERIAL];
                
                NSLog(@"CPU Serial %@",serial);

                int stateP;
                
                

                NSString *action = [[NSUserDefaults standardUserDefaults] objectForKey:@"action"];

                if([action isEqualToString:@"printer"]){

                    bool status = [dtdev prnGetPrinterStatus:&stateP error:nil];

                    if(stateP == 0){
                        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
                        [dict setValue:@"connectprinter" forKey:@"operation"];
                        [dict setValue:@"connected" forKey:@"status"];  
                        [PaypadFacade sendNotification:dict wait:NO error:NO];
                    }else{
                        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
                        [dict setValue:@"connectprinter" forKey:@"operation"];
                        [dict setValue:@"cannot_connect" forKey:@"status"];  
                        [PaypadFacade sendNotification:dict wait:NO error:YES];
                    }
                }

                [serial retain];
                
            }
            
//            scPresent=[dtdev scInit:SLOT_MAIN error:nil];
            //since we work with AES encrypted or plain card data, make sure device is sending it
            [dtdev emsrSetEncryption:ALG_EH_AES256 params:nil error:nil];
            
            CDVPluginResult* pluginResult = nil;

            NSMutableDictionary *dict = [NSMutableDictionary dictionary];
            [dict setValue:@"connection" forKey:@"operation"];
            [dict setValue:@"connected" forKey:@"status"];

            pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dict];

            commandId =  [[NSUserDefaults standardUserDefaults] objectForKey:@"COMMANDID"];
            // This is used to make the thread wait for callback
            [pluginResult setKeepCallback:[NSNumber numberWithBool:NO]];

            [self.commandDelegate sendPluginResult:pluginResult callbackId:commandId];

            position = -1;
            //if we are connected to a device not supporting pin entry, but has bluetooth in, try to find something around to connect to
            //            if([dtdev getSupportedFeature:FEAT_PIN_ENTRY error:nil]!=FEAT_SUPPORTED && [dtdev getSupportedFeature:FEAT_BLUETOOTH error:nil]&BLUETOOTH_CLIENT)
            //                [self performSelectorOnMainThread:@selector(showBTController) withObject:nil waitUntilDone:false];
            break;
        }
    }
}


-(void)accelerometer:(UIAccelerometer *)acel didAccelerate:(UIAcceleration *)aceler
{
    if(position==-1)
    {
        if([aceler z]<0)
            [self positionChanged:POS_NORMAL];
        else
            [self positionChanged:POS_FLIPPED];
    }else
    {
        if(position==POS_NORMAL && [aceler z]>0.5)
            [self positionChanged:POS_FLIPPED];
        if(position==POS_FLIPPED && [aceler z]<-0.5)
            [self positionChanged:POS_NORMAL];
    }
}

-(void) network:(CDVInvokedUrlCommand*)command{

    // UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Network Status" message:@"Internet access not available" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
    // [alertView setMessage:@"No internet connection available"];
    // [alertView show];

    BOOL status = [self checkInternet];

    CDVPluginResult* pluginResult = nil;

    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    [dict setValue:@"network" forKey:@"operation"];

    [dict setValue:@(status) forKey:@"status"];
    pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dict];
    [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}

-(void) startscan : (CDVInvokedUrlCommand*)command{
    [[UIApplication sharedApplication] setIdleTimerDisabled: YES];


    if(dtdev.connstate != CONN_CONNECTED){

        CDVPluginResult* pluginResult = nil;
        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        [dict setValue:@"barcode" forKey:@"operation"];
        [dict setValue:@"failed" forKey:@"status"];
        [dict setValue:@"device not connected" forKey:@"message"];
        pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dict];

        [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];

        return;
    }
        
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
    int scanMode;

    [self.commandDelegate runInBackground:^{

        CDVPluginResult* pluginResult = nil;

        NSError *error = nil;

        if([dtdev barcodeGetScanMode:&scanMode error:&error]){
            
            NSMutableDictionary *dict = [NSMutableDictionary dictionary];
            
            if(error){
                
                [dict setValue:@"barcode" forKey:@"operation"];
                [dict setValue:@"failed" forKey:@"status"];
                pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dict];

                [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];

                [dtdev barcodeStopScan:&error];
                return;
            }

            [dtdev barcodeStartScan:&error];

            // NSMutableDictionary *dict = [NSMutableDictionary dictionary];
            [dict setValue:@"barcode" forKey:@"operation"];
            [dict setValue:@"started" forKey:@"status"];

            pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dict];

            // This is used to make the thread wait for callback
            [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
            commandId = command.callbackId;

            [[NSUserDefaults standardUserDefaults] setObject:commandId forKey:@"COMMANDID"];

            [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];

        }else
            [dtdev barcodeStartScan:&error];

    }];    
}

-(void)barcodeData:(NSString *)barcode type:(int)type
{    
    // [displayText setText:status];

    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    [dict setValue:@"barcode" forKey:@"operation"];
    [dict setValue:@"ended" forKey:@"status"];
    [dict setValue:barcode forKey:@"data"];


    [PaypadFacade sendNotification:dict wait:NO error:NO];

//  [self updateBattery];
}

-(void)barcodeData:(NSString *)barcode isotype:(NSString *)isotype
{    
    // [displayText setText:status];

    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    [dict setValue:@"barcode" forKey:@"operation"];
    [dict setValue:@"ended" forKey:@"status"];
    [dict setValue:barcode forKey:@"data"];


    [PaypadFacade sendNotification:dict wait:NO error:NO];

//  [self updateBattery];
}

-(void) stopscan : (CDVInvokedUrlCommand*)command{
    [[UIApplication sharedApplication] setIdleTimerDisabled: YES];

    if(dtdev.connstate != CONN_CONNECTED){

        CDVPluginResult* pluginResult = nil;
        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        [dict setValue:@"barcode" forKey:@"operation"];
        [dict setValue:@"failed" forKey:@"status"];
        [dict setValue:@"device not connected" forKey:@"message"];
        pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dict];

        [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];

        return;
    }

    [self.commandDelegate runInBackground:^{

        CDVPluginResult* pluginResult = nil;
        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        [dict setValue:@"barcode" forKey:@"operation"];
        [dict setValue:@"ended" forKey:@"status"];
        [dict setValue:@"" forKey:@"message"];
        pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dict];

        [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];

    }];
}

-(void)positionChanged:(int)newpos
{
    position=newpos;
    if(dtdev.connstate!=CONN_CONNECTED)
        return;
    
    [dtdev uiStopAnimation:-1 error:nil];
    [dtdev uiFillRectangle:0 topLeftY:0 width:0 height:0 color:[UIColor blackColor] error:nil];
    
    if(position==POS_FLIPPED)
    {
        if(operation==OP_SIGNATURE)
        {
//            [navigationController popViewControllerAnimated:FALSE];
//            [progressViewController updateImage:[UIImage imageNamed:@"card_ms.png"]];
//            [self enterPin];
        }
        if(operation==OP_AMOUNT)
        {
            [dtdev uiDrawText:@"\x01Please turn the\nunit and enter\namount" topLeftX:0 topLeftY:5 font:FONT_8X16 error:nil];
        }
        if(operation==OP_NONE)
        {
            if(dtdev.uiDisplayHeight<64)
            {
                // [dtdev uiDrawText:@"Insert smartcard\nor swipe magnetic\ncard" topLeftX:0 topLeftY:0 font:FONT_6X8 error:nil];
                [dtdev uiDrawText:@"     PINPAD\n   CONNECTED" topLeftX:0 topLeftY:0 font:FONT_8X16 error:nil];
            }else
            {
                [dtdev uiDrawText:@"\x01Use smart,\nmagnetic " topLeftX:25 topLeftY:3 font:FONT_6X8 error:nil];
                //magnetic card
                [dtdev uiStartAnimation:5 topLeftX:99 topLeftY:0 animated:TRUE error:nil];
                //smartcard
                if(scPresent)
                {
                    [dtdev uiStartAnimation:4 topLeftX:0 topLeftY:0 animated:TRUE error:nil];
                }
                if(payPassPresent)
                {
                    [dtdev uiDisplayImage:38 topLeftY:30 image:[UIImage imageNamed:@"paypass_logo.bmp"] error:nil];
                }
                [dtdev uiDisplayImage:38 topLeftY:30 image:[UIImage imageNamed:@"paypass_logo.bmp"] error:nil];
            }
        }
//        [progressViewController enableCancel:FALSE];
    }else
    {
        if(operation==OP_NONE && !dtdev.uiDisplayAtBottom)
        {
            if(dtdev.uiDisplayHeight<64)
            {
                // [dtdev uiDrawText:@"Insert smartcard\nor swipe magnetic\ncard" topLeftX:0 topLeftY:0 font:FONT_6X8 error:nil];
                [dtdev uiDrawText:@"     PINPAD\n   CONNECTED" topLeftX:0 topLeftY:0 font:FONT_8X16 error:nil];

            }else
            {
                [dtdev uiDrawText:@"\x01Use smart,\nmagnetic or\npaypass card" topLeftX:25 topLeftY:3 font:FONT_6X8 error:nil];
                //magnetic card
                [dtdev uiStartAnimation:5 topLeftX:99 topLeftY:0 animated:TRUE error:nil];
                //smartcard
                if(scPresent)
                {
                    [dtdev uiStartAnimation:4 topLeftX:0 topLeftY:0 animated:TRUE error:nil];
                }
                if(payPassPresent)
                {
                    [dtdev uiDisplayImage:38 topLeftY:30 image:[UIImage imageNamed:@"paypass_logo.bmp"] error:nil];
                }
                [dtdev uiDisplayImage:38 topLeftY:30 image:[UIImage imageNamed:@"paypass_logo.bmp"] error:nil];
            }
        }
//        [progressViewController enableCancel:TRUE];
    }
    
}

-(BOOL)checkInternet{
    
        struct sockaddr_in zeroAddress;
        bzero(&zeroAddress, sizeof(zeroAddress));
        zeroAddress.sin_len = sizeof(zeroAddress);
        zeroAddress.sin_family = AF_INET;
    
        // UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Network Status" message:@"Internet access not available" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
    
        SCNetworkReachabilityRef reachabilityRef = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *) &zeroAddress);
        
        SCNetworkReachabilityFlags flags;
        if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
            if ((flags & kSCNetworkReachabilityFlagsReachable) == 0) {
                // if target host is not reachable
                
                // dispatch_async(dispatch_get_main_queue(), ^(void){
                //     [alertView setMessage:@"No internet connection available"];
                //     [alertView show];
                // });
                
                return NO;
            }
            
            if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0) {
                // if target host is reachable and no connection is required
                //  then we'll assume (for now) that your on Wi-Fi
                
                // dispatch_async(dispatch_get_main_queue(), ^(void){
                //     [alertView setMessage:@"Internet connection is available"];
                //     [alertView show];
                // });
                
                return YES; // This is a wifi connection.
            }
            
            
            if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0)
                 ||(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0)) {
                // ... and the connection is on-demand (or on-traffic) if the
                //     calling application is using the CFSocketStream or higher APIs
                
                if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0) {
                    // dispatch_async(dispatch_get_main_queue(), ^(void){
                    //     [alertView setMessage:@"Internet connection is available"];
                    //     [alertView show];
                    // });
                    // ... and no [user] intervention is needed
                    return YES; // This is a wifi connection.
                }
            }
            
            if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN) {
                // ... but WWAN connections are OK if the calling application
                //     is using the CFNetwork (CFSocketStream?) APIs.
                // dispatch_async(dispatch_get_main_queue(), ^(void){
                //     [alertView setMessage:@"Internet connection is available"];
                //     [alertView show];
                // });
                return YES; // This is a cellular connection.
            }
        }
    
    
    // [alertView setMessage:@"No internet connection available"];
    // [alertView show];
    return NO;
    
}

-(NSString *)dataToHexstring:(NSData *)data{
    
    unsigned const char* dbytes = [data bytes];
    
    NSMutableString *hexStr = [NSMutableString stringWithCapacity:[data length]*2];
    
    int i;
    
    for (i = 0; i < [data length]; i++) {
        [hexStr appendFormat:@"%02x", dbytes[i]];
    }
    
    NSString* temp = [NSString stringWithString:hexStr];
    
    return [temp uppercaseString];
}

-(NSData *)hexStringToData:(NSString *)hexString{
    
    const char *chars = [hexString UTF8String];
    long len = hexString.length;
    int i = 0;
    
    NSMutableData *data = [NSMutableData dataWithCapacity:len / 2];
    char byteChars[3] = {'\0','\0','\0'};
    unsigned long wholeByte;
    
    while (i < len) {
        byteChars[0] = chars[i++];
        byteChars[1] = chars[i++];
        wholeByte = strtoul(byteChars, NULL, 16);
        [data appendBytes:&wholeByte length:1];
    }
    
    return data;
}

/**
    This is used in passing the parameter received from NIBSS
 */
-(void)parseField62:(NSString*) msg{
    
    // This converts string to a mutable one
    NSMutableString *message = [msg mutableCopy];
    
    NSMutableArray *subMsg = [[NSMutableArray alloc] init];
    
    int i = 0 ;
    do{
        
        NSString *value = [message substringWithRange:NSMakeRange(2, 5-2)];
        int lengthValue = [value intValue];
        
        subMsg[i] = [message substringWithRange:NSMakeRange(5,lengthValue)];
        
        int switchVal = [[message substringWithRange:NSMakeRange(0, 2)] intValue];
        
        switch (switchVal) {
            case 2:
                // System.out.print("Time and date: ");
                // System.out.println(subMsg[i]);
                break;
            case 3:
                NSLog(@"AcceptorID: %@",subMsg[i]);
                
                [[NSUserDefaults standardUserDefaults] setObject:subMsg[i] forKey:ACCEPTOR_ID];
                break;
            case 4:
//                [[NSUserDefaults standardUserDefaults] setObject:subMsg[i] forKey:ACCEPTOR_ID];
                NSLog(@"Timeout: %@",subMsg[i]);
                break;
            case 5:
                NSLog(@"Currency Code: %@",subMsg[i]);
                break;
            case 6:
                NSLog(@"Currency Code: %@",subMsg[i]);
                break;
            case 7:
                NSLog(@"Call Timeout: %@",subMsg[i]);
                break;
            case 8:
                NSLog(@"merchant type %@", subMsg[i]);
                [[NSUserDefaults standardUserDefaults] setObject:subMsg[i] forKey:MERCHANT_TYPE];
//                Globals.merchantType = subMsg[i];
                break;
            case 52:
                NSLog(@"Acceptor name %@", subMsg[i]);
                [[NSUserDefaults standardUserDefaults] setObject:subMsg[i] forKey:ACCEPTOR_NAME];
//                Globals.acceptorName = subMsg[i];
                break;
        }
        
        message = [[message substringFromIndex:5 + lengthValue] mutableCopy];
        
    }while([message length] > 0);
}


/**
    This is used in passing the parameter received from NIBSS
 */
-(void)parseField62Vas:(NSString*) msg{
    
    // This converts string to a mutable one
    NSMutableString *message = [msg mutableCopy];
    
    NSMutableArray *subMsg = [[NSMutableArray alloc] init];
    
    int i = 0 ;
    do{
        
        NSString *value = [message substringWithRange:NSMakeRange(2, 5-2)];
        int lengthValue = [value intValue];
        
        subMsg[i] = [message substringWithRange:NSMakeRange(5,lengthValue)];
        
        int switchVal = [[message substringWithRange:NSMakeRange(0, 2)] intValue];
        
        switch (switchVal) {
            case 2:
                // System.out.print("Time and date: ");
                // System.out.println(subMsg[i]);
                break;
            case 3:
                NSLog(@"AcceptorID: %@",subMsg[i]);
                
                [[NSUserDefaults standardUserDefaults] setObject:subMsg[i] forKey:ACCEPTOR_ID_VAS];
                break;
            case 4:
//                [[NSUserDefaults standardUserDefaults] setObject:subMsg[i] forKey:ACCEPTOR_ID];
                NSLog(@"Timeout: %@",subMsg[i]);
                break;
            case 5:
                NSLog(@"Currency Code: %@",subMsg[i]);
                break;
            case 6:
                NSLog(@"Currency Code: %@",subMsg[i]);
                break;
            case 7:
                NSLog(@"Call Timeout: %@",subMsg[i]);
                break;
            case 8:
                NSLog(@"merchant type %@", subMsg[i]);
                [[NSUserDefaults standardUserDefaults] setObject:subMsg[i] forKey:MERCHANT_TYPE_VAS];
//                Globals.merchantType = subMsg[i];
                break;
            case 52:
                NSLog(@"Acceptor name %@", subMsg[i]);
                [[NSUserDefaults standardUserDefaults] setObject:subMsg[i] forKey:ACCEPTOR_NAME_VAS];
//                Globals.acceptorName = subMsg[i];
                break;
        }
        
        message = [[message substringFromIndex:5 + lengthValue] mutableCopy];
        
    }while([message length] > 0);
}

-(void)stream:(NSStream *)aStream
  handleEvent:(NSStreamEvent)eventCode{
    
    CDVPluginResult* pluginResult = nil;

    switch (eventCode) {
        case NSStreamEventErrorOccurred:{

            NSString *commandId =  [[NSUserDefaults standardUserDefaults] objectForKey:@"COMMANDID"];

            NSMutableDictionary *dict = [NSMutableDictionary dictionary];
            [dict setValue:@"initialization" forKey:@"operation"];
            [dict setValue:@"failed" forKey:@"status"];
            pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dict];
            [pluginResult setKeepCallback:[NSNumber numberWithBool:NO]];
            [self.commandDelegate sendPluginResult:pluginResult callbackId:commandId];

            NSLog(@"ERROR: %@",[[aStream streamError] localizedDescription]);

            NSLog(@"Error occured while trying to open connection");
            break;
        }
        case NSStreamEventOpenCompleted:
            
            NSLog(@"Stream has started");
            break;
        case NSStreamEventHasSpaceAvailable:
        {
            [self.pinkeyRequest writeDelimitedToOutputStream:outputStream];
            
            NSLog(@"Data can be sent to stream");
            break;
        }
        case NSStreamEventHasBytesAvailable:{
            NSLog(@"There is data to be read from the socket");
            
            self.pinkeyResponse = [PinpadKeysResponse parseDelimitedFromInputStream:inputStream];
            //
            //
            if([self.pinkeyResponse hasStatus]){
                
                BOOL status = [self.pinkeyResponse status];
                NSString *commandId =  [[NSUserDefaults standardUserDefaults] objectForKey:@"COMMANDID"];
                NSMutableDictionary *dict = [NSMutableDictionary dictionary];
                [dict setValue:@"initialization" forKey:@"operation"];

                // This checks if the keys were downloaded completely
                if(status == YES){
                    
                    NSLog(@"Pinkey: %@",self.pinkeyResponse.pinKey);
                    
                    tmkTr31 = self.pinkeyResponse.tmkTr31;
                    pinkey = self.pinkeyResponse.pinKey;
                    dupktTr31 = self.pinkeyResponse.dupktTr31;
                    bdk = self.pinkeyResponse.bdk;
                    dataTr31 = self.pinkeyResponse.dataTr31;
                    sessionKey = self.pinkeyResponse.tsk;
                    parameter = self.pinkeyResponse.parameter;


                    
                    // This stored the key that will be injected into the NSUserDefaults
                    [[NSUserDefaults standardUserDefaults] setObject:dupktTr31 forKey:DUKPT_TR31_LOCATION];
                    [[NSUserDefaults standardUserDefaults] setObject:tmkTr31 forKey:TMK_TR31_LOCATION];
                    [[NSUserDefaults standardUserDefaults] setObject:dataTr31 forKey:DATA_TR31_LOCATION];
                    [[NSUserDefaults standardUserDefaults] setObject:pinkey forKey:TPK_LOCATION];
                    [[NSUserDefaults standardUserDefaults] setObject:bdk forKey:BDK_LOCATION];
                    [[NSUserDefaults standardUserDefaults] setObject:sessionKey forKey:TSK_LOCATION];
                    [[NSUserDefaults standardUserDefaults] setObject:self.pinkeyResponse.dataKey forKey:DATA_KEY_LOCATION];
                    
                    [self parseField62:parameter];

                    // This is for getting the VAS paramaters
                    // if(self.pinkeyResponse.hasVasPresent == YES){
                        
                    //     [self parseField62Vas:self.pinkeyResponse.parameterOther];
                        
                    //     [[NSUserDefaults standardUserDefaults] setObject:self.pinkeyResponse.tmkTr31Other forKey:TMK_TR31_VAS_LOCATION];
                    //     [[NSUserDefaults standardUserDefaults] setObject:self.pinkeyResponse.pinKeyOther forKey:TPK_VAS_LOCATION];
                    //     [[NSUserDefaults standardUserDefaults] setObject:self.pinkeyResponse.tskOther forKey:TSK_VAS_LOCATION];

                    //     [[NSUserDefaults standardUserDefaults] setObject:self.pinkeyResponse.vasTid forKey:TERMINAL_ID_VAS];
                        
                    //     [[NSUserDefaults standardUserDefaults] setBool:YES forKey:VAS_PRESENT];
                    // }else{
                    //     [[NSUserDefaults standardUserDefaults] setBool:NO forKey:VAS_PRESENT];
                    // }
                    
                    NSError *error = nil;
                    
                    [PinpadHelper showWaiting:dtdev];
                    PaypadKeyManager *paypadKeyManager = [[PaypadKeyManager alloc] initWithDTDevices:dtdev];
                    [paypadKeyManager loadKeys];
                    
                    NSLog(@"Dukpt TR31 : %@",dupktTr31);
                    NSLog(@"Session key: %@",self.pinkeyResponse.tsk);

                    NSString *serialSD =  [PinpadHelper getDeviceSerial:dtdev];

                    [PinpadHelper initScreen:dtdev];

                    [[NSUserDefaults standardUserDefaults] setObject:serialSD forKey:PINPAD_SERIAL];

                    // NSString *commandId =  [[NSUserDefaults standardUserDefaults] objectForKey:@"COMMANDID"];

                    // NSMutableDictionary *dict = [NSMutableDictionary dictionary];
                    // [dict setValue:@"initialization" forKey:@"operation"];
                    [dict setValue:@"loading_keys_to_pinpad" forKey:@"status"];
                    pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dict];
                    [pluginResult setKeepCallback:[NSNumber numberWithBool:NO]];
                    [self.commandDelegate sendPluginResult:pluginResult callbackId:commandId];


                    
                    // UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:@"Key Download Status" message:@"Key Downloaded Successfully" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
                    
                    // This will load the keys to the PINPAD
//                    [self loadKeys];
                    
                    // [alertView show];
                    
                }else{
                    NSLog(@"Unable to download keys from server");
                    
                    tmkTr31 = self.pinkeyResponse.tmkTr31;
                    pinkey = self.pinkeyResponse.pinKey;
                    dupktTr31 = self.pinkeyResponse.dupktTr31;
                    bdk = self.pinkeyResponse.bdk;
                    dataTr31 = self.pinkeyResponse.dataTr31;
                    
                    NSString *commandId =  [[NSUserDefaults standardUserDefaults] objectForKey:@"COMMANDID"];

                    [dict setValue:@"failed" forKey:@"status"];
                    pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dict];
                    [pluginResult setKeepCallback:[NSNumber numberWithBool:NO]];
                    [self.commandDelegate sendPluginResult:pluginResult callbackId:commandId];

                    // UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:@"Key Download Status" message:@"Key Downloading Failed" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
                    
                    // [alertView show];
                }
                
            }else{

                NSString *commandId =  [[NSUserDefaults standardUserDefaults] objectForKey:@"COMMANDID"];

                NSMutableDictionary *dict = [NSMutableDictionary dictionary];
                [dict setValue:@"initialization" forKey:@"operation"];
                [dict setValue:@"failed" forKey:@"status"];
                pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dict];
                [pluginResult setKeepCallback:[NSNumber numberWithBool:NO]];
                [self.commandDelegate sendPluginResult:pluginResult callbackId:commandId];

            }
            
            [inputStream close];
            [outputStream close];
            
            break;
        }
            
        default:
            break;
    }
    NSLog(@"This is called after communicating with server");
}

-(void) payment : (CDVInvokedUrlCommand*)command{

    // This is called to do payment
    [[UIApplication sharedApplication] setIdleTimerDisabled: YES];
    
    CDVPluginResult* pluginResult = nil;

    // This gets the amount
    NSString* amount = [command.arguments objectAtIndex:0];

    // This gets the account type the customer selected
    NSString *accountType = [command.arguments objectAtIndex:1];

    if(amount.length <= 0 || accountType.length <= 0){

        // NSString *commandId =  [[NSUserDefaults standardUserDefaults] objectForKey:@"COMMANDID"];
        // enters here if if invalid parameter was passed
        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        [dict setValue:@"payment" forKey:@"operation"];
        [dict setValue:@"invalid_parameters" forKey:@"status"];
        pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dict];
        [pluginResult setKeepCallback:[NSNumber numberWithBool:NO]];
        [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];

        return ;
    }

    // This is used in saving the callback id
    [[NSUserDefaults standardUserDefaults] setObject:command.callbackId forKey:@"COMMANDID"];

    [self.commandDelegate runInBackground:^{

        // This is used in storing the commandID which will be use in passing the response 
        // back to client
        NSString *amnt = [NSString stringWithFormat:@"%0.2f",[amount doubleValue]];

        NSString *accType = @"";

        if([accountType caseInsensitiveCompare:@"current"] == NSOrderedSame){
            accType = @"20";
        }else if([accountType caseInsensitiveCompare:@"credit"] == NSOrderedSame){
            accType = @"30";
        }else{
            // enters here is saving was selected
            accType = @"10";
        }

        [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"T_DONE"];

        // dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(void){
            [self makePayment:amnt accountType:accType doVas:NO];
        // });
    }];
}

-(void) vas : (CDVInvokedUrlCommand*)command{

    // This is called to do payment

    CDVPluginResult* pluginResult = nil;

    // This gets the amount
    NSString* amount = [command.arguments objectAtIndex:0];

    // This gets the account type the customer selected
    NSString *accountType = [command.arguments objectAtIndex:1];

    // This gets the stan from the parameter 
    NSString *stan = [command.arguments objectAtIndex:2];

    // This gets the stan from the parameter 
    NSString *rrn = [command.arguments objectAtIndex:3];

    if(amount.length <= 0 || accountType.length <= 0){

        // NSString *commandId =  [[NSUserDefaults standardUserDefaults] objectForKey:@"COMMANDID"];
        // enters here if if invalid parameter was passed
        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        [dict setValue:@"payment" forKey:@"operation"];
        [dict setValue:@"invalid_parameters" forKey:@"status"];
        pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dict];
        [pluginResult setKeepCallback:[NSNumber numberWithBool:NO]];
        [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];

        return ;
    }

    if(rrn == nil){
        rrn = @"5";
    }

    [[NSUserDefaults standardUserDefaults] setObject:[NSString stringWithFormat:@"%012ld",rrn] forKey:RRN_VAS];

    if(stan == nil){
        stan = @"5";
    }

    [[NSUserDefaults standardUserDefaults] setObject:[NSString stringWithFormat:@"%012ld",stan] forKey:STAN_VAS];

    // This is used in saving the callback id
    [[NSUserDefaults standardUserDefaults] setObject:command.callbackId forKey:@"COMMANDID"];

    [self.commandDelegate runInBackground:^{

        // This is used in storing the commandID which will be use in passing the response 
        // back to client
        NSString *amnt = [NSString stringWithFormat:@"%0.2f",[amount doubleValue]];

        NSString *accType = @"";

        if([accountType caseInsensitiveCompare:@"current"] == NSOrderedSame){
            accType = @"20";
        }else if([accountType caseInsensitiveCompare:@"credit"] == NSOrderedSame){
            accType = @"30";
        }else{
            // enters here is saving was selected
            accType = @"10";
        }

        [self makePayment:amnt accountType:accType doVas:YES];

    }];

}

-(void)makePayment:(NSString *)amount accountType:(NSString*)accountType doVas:(BOOL) doVas{
    
    
    state = 22; // this is value that indicates present of card
    
    presentC = 1;
    
    int res = [PinpadHelper presentCard:dtdev quit:&state];

    NSString* commandId = [[NSUserDefaults standardUserDefaults] objectForKey:@"COMMANDID"];
    CDVPluginResult* pluginResult = nil;

    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    [dict setValue:@"payment" forKey:@"operation"];

    if(res == -1){

        [PinpadHelper showCanceled:dtdev];
        [dict setValue:@"cancelled" forKey:@"status"];  
        pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dict];
        [pluginResult setKeepCallback:[NSNumber numberWithBool:NO]];
        [self.commandDelegate sendPluginResult:pluginResult callbackId:commandId];

        presentC = 0;
        return ;
    }
    
    [dict setValue:@"processing" forKey:@"status"];
    pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dict];
    [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
    [self.commandDelegate sendPluginResult:pluginResult callbackId:commandId];

    NSData *atr=[dtdev scCardPowerOn:SLOT_MAIN error:nil];
    
    if(atr)
    {
        if([dtdev emvATRValidation:atr warmReset:false error:nil])
        {            
            EMVRequest *request = [[EMVRequest alloc] init];
            
            [request setCurrencyCode:@"566"];
            ////                [request setAccountType:]
            //
            // NSString *amount = @"1.00";

            [[NSUserDefaults standardUserDefaults] setObject:amount forKey:AMOUNT];
            
            [[NSUserDefaults standardUserDefaults] setObject:accountType forKey:ACCOUNT_TYPE_FROM];
            //
            amount = [amount stringByReplacingOccurrencesOfString:@"." withString:@""];
            //
            NSLog(@"Amount is %@",amount);
            //
            //
            NSString *amountOthers = @"000";
            [request setMinorAmount: [amount intValue]];
            [request setOtherAmount: [amountOthers intValue]];
            [request setTransactionCurrencyCode:@"566"];
            [request setTransactionCategoryCode:@"00"];
            
            [request setTransactionDate:[NSDate date]];
            [request setTransactionType:EMVGOOD];
            [request setTerminalDecision:EmvTerminalNoDecision];
            //
            [request setOnlinePinMode: MS];
            [request setAccountType: SAVINGS];
            

            // dispatch_async(dispatch_get_main_queue(), ^{
            if(doVas == NO){
                EMVTransactionManager *emvTransactionManager = [[EMVTransactionManager alloc] initWithDTDevices:dtdev];
                [emvTransactionManager doEMVTransaction:request];
            }else{
                // EMVTransactionManagerVas *emvTransactionManager = [[EMVTransactionManagerVas alloc] initWithDTDevices:dtdev];
                // [emvTransactionManager doEMVTransaction:request];
            }
            // });
            
            return;
        }
    }   
}

-(void) deviceButtonReleased: (int) which{
    
    if(which == 24 && presentC == 1)
        state = 10;
    
    NSLog(@"Button is release %i",which);
}

+(void)sendNotification:(NSDictionary *) dict
                   wait:(BOOL) wait error:(BOOL) error{
    
    // dispatch_async(dispatch_get_main_queue(),^{
        NSString* commandId = [[NSUserDefaults standardUserDefaults] objectForKey:@"COMMANDID"];
    
        CDVPluginResult* pluginResult = nil;
        
        if(error == YES){
            pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dict];
        }else{
            pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dict];
        }
        

        [pluginResult setKeepCallbackAsBool:wait];
        [commandD sendPluginResult:pluginResult callbackId:commandId];

        // return ;
    // });
}

-(void)deviceFeatureSupported:(int)feature value:(int)value{

    // This is used in checking if printer is connected
    if(feature==FEAT_PRINTING){

        if(value&PRINT_PROTOCOL_ESCPOS){
            canPrint = true;

            NSMutableDictionary *dict = [NSMutableDictionary dictionary];
            [dict setValue:@"connectprinter" forKey:@"operation"];
            [dict setValue:@"connected" forKey:@"status"];  
            [PaypadFacade sendNotification:dict wait:NO error:NO];
            return ;

        }else{

            if(value&PRINT_PROTOCOL_ZPL){
                canPrint = true;
                NSMutableDictionary *dict = [NSMutableDictionary dictionary];
                [dict setValue:@"connectprinter" forKey:@"operation"];
                [dict setValue:@"connected" forKey:@"status"];  
                [PaypadFacade sendNotification:dict wait:NO error:NO];

            }else{

                int stateP;
                bool status = [dtdev prnGetPrinterStatus:&stateP error:nil];
                    
                if(stateP == 0){
                    canPrint = true;
                    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
                    [dict setValue:@"connectprinter" forKey:@"operation"];
                    [dict setValue:@"connected" forKey:@"status"];  
                    [PaypadFacade sendNotification:dict wait:NO error:YES];
                }else{
                    canPrint = false;
                    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
                     [dict setValue:@"connectprinter" forKey:@"operation"];
                     [dict setValue:@"connecting" forKey:@"status"];
                    NSString* commandId = [[NSUserDefaults standardUserDefaults] objectForKey:@"COMMANDID"];
                    
                    CDVPluginResult* pluginResult = nil;

                    pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_NO_RESULT messageAsDictionary:dict];
                    
                    [pluginResult setKeepCallbackAsBool:YES];
                    [commandD sendPluginResult:pluginResult callbackId:commandId];
                }
                
            }

            return;
        }
        
        if(value==FEAT_UNSUPPORTED){
            canPrint = false;
            NSMutableDictionary *dict = [NSMutableDictionary dictionary];
            [dict setValue:@"connectprinter" forKey:@"operation"];
            [dict setValue:@"cannot_connect" forKey:@"status"];  
            [PaypadFacade sendNotification:dict wait:NO error:YES];
            return ;
        }
    }
}

-(void) connectprinter : (CDVInvokedUrlCommand*)command {

    CDVPluginResult* pluginResult = nil;

    [[NSUserDefaults standardUserDefaults] setObject:command.callbackId forKey:@"COMMANDID"];

    [[NSUserDefaults standardUserDefaults] setObject:@"printer" forKey:@"action"];

    if(canPrint == true){
        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        [dict setValue:@"connectprinter" forKey:@"operation"];
        [dict setValue:@"already_connected" forKey:@"status"];  
        [PaypadFacade sendNotification:dict wait:NO error:NO];
        // return ;
    }else{

        [self.commandDelegate runInBackground:^{

            [dtdev connect];

            NSMutableDictionary *dict = [NSMutableDictionary dictionary];
            [dict setValue:@"connectprinter" forKey:@"operation"];
            [dict setValue:@"connecting" forKey:@"status"];  
            [PaypadFacade sendNotification:dict wait:YES error:NO];
        }];
    }
    return ;
}

-(void) print : (CDVInvokedUrlCommand*)command {

    CDVPluginResult* pluginResult = nil;

    if(canPrint == false){
        pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Printer is not connected"];
        [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
        return ;
    }

    if(hasPaper == false){
        pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Printer has no paper"];
        [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
        return ;
    }

    NSString *header = [command.arguments objectAtIndex:0];
    NSDictionary *body = [command.arguments objectAtIndex:1];
    NSString *footer = [command.arguments objectAtIndex:2];
    NSString *poweredby = [command.arguments objectAtIndex:3];

    NSMutableString *stringToPrint = [[NSMutableString alloc] init];
    
    [stringToPrint appendString:[NSString stringWithFormat:@"{=C}{+B}{+DW}{+DH}%@\n",header]];
    [stringToPrint appendString:[NSString stringWithFormat:@"{=C}{+B}{+DW}{-DH}%@\n",@"Receipt"]];

    [stringToPrint appendString:@"\n"];
    for(NSString* key in body.allKeys){
        NSString* obj = [body objectForKey:key];
        
        [stringToPrint appendString:[NSString stringWithFormat:@"{=L}{-DW}{-DH}{-B}%@ : {-B}%@\n",[self formatString:key size:15],obj]];
    }

    [stringToPrint appendString:[NSString stringWithFormat:@"\n{=C}{-B}%@\n",footer]];
    [stringToPrint appendString:[NSString stringWithFormat:@"{=L}{-B}%@",@"================================"]];
    [stringToPrint appendString:[NSString stringWithFormat:@"{=C}{=F0}{+B}%@{=F1}\n",poweredby]];
    // [stringToPrint appendString:];
    [stringToPrint appendString:[NSString stringWithFormat:@"{=L}{-B}{=F1}%@",@"================================\n"]];

    [stringToPrint appendString:@"\n\n\n\n"];
            
    [dtdev prnPrintText:stringToPrint error:nil];

    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    [dict setValue:@"printing" forKey:@"operation"];
    [dict setValue:@"done" forKey:@"status"];  
    pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dict];

    [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}

-(void)paperStatus:(BOOL)present{

    hasPaper = present;
}

-(NSString *) formatString:(NSString*) data size:(int) size{
    
    if(data.length > size)
        return data;
    
    NSMutableString *str = [[NSMutableString alloc] init];
    
    [str appendString:data];
    
    for(int i = 0 ; i < size - data.length ; i++ ){
        [str appendString:@" "];
    }
    
    return str;
}


@end