#import "AppDelegate.h"
#import "TestMainViewController.h"

#ifdef MPOS_XCFRAMEWORK
@import frameworkMPosSDK;

#else
#import "MPosControllerPrinter.h"
#import "MPosControllerDotPrinter.h"
#import "MPosControllerLabelPrinter.h"
#import "MPosControllerConfig.h"
#import "MPosControllerScanner.h"
#import "MPosControllerUSBSerial.h"
#import "MPosControllerBCD.h"
#import "MPosLibVersion.h"

#endif

@interface TestMainViewController ()
@property MPosControllerPrinter* posPrinter;
@property MPosControllerDotPrinter* dotPrinter;
@property MPosControllerLabelPrinter* labelPrinter;
@property MPosControllerConfig* mPosConfig;
@property MPosControllerScanner* barcodeScanner;
@property MPosControllerUSBSerial* usbToSerialDevice;
@property MPosControllerBCD* customerDisplay;
@property UITableView* tableView;
@property UITextView* textView;
@property NSArray<NSString*>* sections;
@property NSArray<NSArray<NSString*>*>* buttons;
@end

@implementation TestMainViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    NSLog(@"Bixolon SDK Version: %@", [MPosLibVersion getVersionInfo]);
    _posPrinter         = [MPosControllerPrinter new];
    _dotPrinter         = [MPosControllerDotPrinter new];
    _labelPrinter       = [MPosControllerLabelPrinter new];
    _barcodeScanner     = [MPosControllerScanner new];
    _usbToSerialDevice  = [MPosControllerUSBSerial new];
    _customerDisplay    = [MPosControllerBCD new];
    _mPosConfig         = [MPosControllerConfig new];
    _sections           = @[@"Device Connection",@"Pos Printer",@"Label Printer",@"Barcode Scanner",
                            @"USB to Serial (TTY-USB)",@"Customer Display (BCD)"];
    _buttons            = @[@[@"Device Selection", @"Device ID", @"Connection Method", @"Network Configure"],
                            @[@"Open", @"Close", @"Print (Line Mode)", @"Print (Page Mode)", @"Check Status"],
                            @[@"Open", @"Close", @"Print", @"Check Status"],
                            @[@"Open", @"Close"],
                            @[@"Open", @"Close"],
                            @[@"Open", @"Close", @"Display Text", @"Clear Screen"],
    ];
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceNotificationHandelr:) name: @"DataEvent" object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceNotificationHandelr:) name: @"StatusUpdateEvent" object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceNotificationHandelr:) name: @"OutputCompletedEvent" object:nil];
//    [MPosControllerPrinter setEnableLog:true saveFile:true saveToHex:true];
    [self initTextView];
    [self initTableView];
}

- (void) initTextView {
    _textView = [UITextView new];
    _textView.layer.borderColor     = UIColor.lightGrayColor.CGColor;
    _textView.layer.borderWidth     = 1;
    _textView.layer.cornerRadius    = 8;
    [_textView setEditable:NO];
    [self.view addSubview:_textView];
    _textView.translatesAutoresizingMaskIntoConstraints = false;
    [_textView.leftAnchor constraintEqualToAnchor: self.view.leftAnchor constant:10].active = YES;
    [_textView.rightAnchor constraintEqualToAnchor: self.view.rightAnchor constant:-10].active = YES;
    [_textView.topAnchor constraintEqualToAnchor: self.topLayoutGuide.bottomAnchor constant:10].active = YES;
    [_textView.heightAnchor constraintEqualToConstant: 100].active = YES;
}

- (void) initTableView {
    _tableView = [UITableView new];
    [_tableView registerClass:UITableViewCell.class forCellReuseIdentifier:@"TableViewCell"];
    _tableView.dataSource           = self;
    _tableView.delegate             = self;
    _tableView.tableFooterView      = [UIView new];
    _tableView.layer.borderColor    = UIColor.lightGrayColor.CGColor;
    _tableView.layer.borderWidth    = 1;
    _tableView.layer.cornerRadius   = 8;
    [self.view addSubview:_tableView];
    _tableView.translatesAutoresizingMaskIntoConstraints = false;
    [_tableView.leftAnchor constraintEqualToAnchor: self.view.leftAnchor constant:10].active = YES;
    [_tableView.rightAnchor constraintEqualToAnchor: self.view.rightAnchor constant:-10].active = YES;
    [_tableView.topAnchor constraintEqualToAnchor: self.textView.bottomAnchor constant:10].active = YES;
    [_tableView.bottomAnchor constraintEqualToAnchor: self.view.bottomAnchor constant:-10].active = YES;
}

- (void)viewDidAppear:(BOOL)animated{
    [super viewDidAppear:animated];
    [self clearHistory];
    [self updateConnectionInformation];
}

- (void) updateConnectionInformation{
    __weak TestMainViewController* weakSelf  = self;
    dispatch_async(dispatch_get_main_queue(),^{
        __strong TestMainViewController* strongSelf = weakSelf;
        AppDelegate* ad = (AppDelegate*)[[UIApplication sharedApplication] delegate];
        UITableViewCell *cell = (UITableViewCell*)[strongSelf.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
        if(cell){
            NSString* address = [ad.connectionString length] ? ad.connectionString : @"Not Assigned";
            [cell detailTextLabel].text = [NSString stringWithFormat:@" Address : %@", address];
            if([ad.deviceName length])
                [cell detailTextLabel].text = [NSString stringWithFormat:@" %@, Address: %@ ", ad.deviceName, address];
        }
        cell = (UITableViewCell*)[strongSelf.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]];
        if(cell){
            [cell detailTextLabel].text = [NSString stringWithFormat:@" ID: Not Assigned"];
            if(ad.deviceId > 0)
                [cell detailTextLabel].text = [NSString stringWithFormat:@" ID: %ld",(long)ad.deviceId];
        }
        cell = (UITableViewCell*)[strongSelf.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:2 inSection:0]];
        if(cell){
            [cell detailTextLabel].text = [NSString stringWithFormat:@" Direct"];
            if(ad.connectionViaBgate)
                [cell detailTextLabel].text = [NSString stringWithFormat:@" Via B-gate"];
        }

        if(![strongSelf.posPrinter isOpen]){
            [strongSelf enableTableCell:YES row:0 section:1];
        }
        if(![strongSelf.labelPrinter isOpen]){
            [strongSelf enableTableCell:YES row:0 section:2];
        }
        if(![strongSelf.barcodeScanner isOpen]){
            [strongSelf enableTableCell:YES row:0 section:3];
        }
        if(![strongSelf.usbToSerialDevice isOpen]){
            [strongSelf enableTableCell:YES row:0 section:4];
        }
        if(![strongSelf.customerDisplay isOpen]){
            [strongSelf enableTableCell:YES row:0 section:5];
        }
    });
}
- (void) deviceNotificationHandelr:(NSNotification*) notification{
    NSNumber* deviceId = (NSNumber*)[notification object];
    __weak TestMainViewController* weakSelf  = self;
    
    if ([[notification name] isEqualToString: @"StatusUpdateEvent"]){
        if([deviceId integerValue] != self.posPrinter.getDeviceId)
            return;
        NSMutableArray *allKeys = [[[notification userInfo] allKeys] mutableCopy];
        for (NSString *key in allKeys) {
            NSInteger status = [[[notification userInfo] objectForKey: key] integerValue];
            NSLog(@"%@, device id = %ld, status = %ld", [notification name], (long)[deviceId integerValue], (long)status);
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                __strong TestMainViewController* strongSelf = weakSelf;
                [strongSelf updatePosPrinterStatusText: [NSIndexPath indexPathForRow:4 inSection:1] status: status];
            });
        }
    }else if ([[notification name] isEqualToString: @"DataEvent"]){
        NSMutableArray *allKeys = [[[notification userInfo] allKeys] mutableCopy];
        for (NSString *key in allKeys) {
            NSData* data = [[notification userInfo] objectForKey: key];
            NSLog(@"%@, device id = %ld, data = %@", [notification name], (long)[deviceId integerValue], data);
            dispatch_async(dispatch_get_main_queue(),^{
                __strong TestMainViewController* strongSelf = weakSelf;
                [strongSelf addHistory:[NSString stringWithFormat:@"ID = %ld, %@", (long)[deviceId integerValue], data]];
            });
        }
    }else if ([[notification name] isEqualToString: @"OutputCompletedEvent"]){
        [self addHistory:@"OutputCompletedEvent"];
    }
}


#pragma mark - UITableViewDelegate
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return self.sections.count;
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    return [self.sections objectAtIndex:section];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [[self.buttons objectAtIndex:section] count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"TableViewCell" forIndexPath:indexPath];
    
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"TableViewCell"];
    if(indexPath.section == 0){
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"TableViewCell"];
        switch (indexPath.row) {
            case 0: cell.detailTextLabel.text = @"Address";  break;
            case 1: cell.detailTextLabel.text = @"ID";       break;
            case 2: cell.detailTextLabel.text = @"Via";      break;
            default:
                break;
        }
        [self updateConnectionInformation];
    }
    
    NSArray<NSString*>* array = [self.buttons objectAtIndex:indexPath.section];
    cell.textLabel.text = [array objectAtIndex:indexPath.row];
    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    
    [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
    
    UIStoryboard* storyBoard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
    UIViewController* vc = nil;
    AppDelegate* ad = nil;
    
    // Connection
    if([indexPath section] == 0){
        switch([indexPath row]){
            case 0:
                vc = [storyBoard instantiateViewControllerWithIdentifier:@"DevListTableVC"];
                [self.navigationController pushViewController:vc animated:YES];
                break;
            case 1:
                vc = [storyBoard instantiateViewControllerWithIdentifier:@"DeviceIdTableVC"];
                [self.navigationController pushViewController:vc animated:YES];
                break;
            case 2:
                [self selectConnectionType];
                break;
            case 3:
                ad = (AppDelegate*)[[UIApplication sharedApplication] delegate];
                if (ad.networkDevice) {
                    vc = [storyBoard instantiateViewControllerWithIdentifier:@"NetConfigurationVC"];
                    [self.navigationController pushViewController:vc animated:YES];
                }else{
                    [self showMessageBox:@"Select a network device first through \"Device Selection\"" title:@"ERROR"];
                }
                break;
        }
    }
    // Pos Printer
    else if([indexPath section] == 1){
        switch([indexPath row]){
            case 0: [self openPosPrinter:indexPath];                break;
            case 1: [self closePosPrinter:indexPath];               break;
            case 2: [self printWithLineMode];                       break;
            case 3: [self printWithPageMode];                       break;
            case 4: [self getCurrentPosPrinterStatus:indexPath];    break;
        }
    }
    // Label Printer
    else if([indexPath section] == 2){
        switch([indexPath row]){
            case 0: [self openLabelPrinter:indexPath];              break;
            case 1: [self closeLabelPrinter:indexPath];             break;
            case 2: [self printLabel];                              break;
            case 3: [self getCurrentLabelPrinterStatus:indexPath];  break;
        }
    }
    // Barcode Scanner
    else if([indexPath section] == 3){
        switch([indexPath row]){
            case 0: [self openBarcodeScanner:indexPath];  break;
            case 1: [self closeBarcodeScanner:indexPath]; break;
        }
    }
    // USB-Serial
    else if([indexPath section] == 4){
        switch([indexPath row]){
            case 0: [self openTTYUSBDevice:indexPath];  break;
            case 1: [self closeTTYUSBDevice:indexPath]; break;
        }
    }
    // BCD
    else if([indexPath section] == 5){
        switch([indexPath row]){
            case 0: [self openCustomerDisplay:indexPath];       break;
            case 1: [self closeCustomerDisplay:indexPath];      break;
            case 2: [self textDisplay];                         break;
            case 3: [self clearDisplay];                        break;
        }
    }
}

-(void) addHistory:(NSString*) text {
    __weak TestMainViewController* weakSelf  = self;
    dispatch_async(dispatch_get_main_queue(),^{
        __strong TestMainViewController* strongSelf = weakSelf;
        strongSelf.textView.text = [strongSelf.textView.text stringByAppendingString: [text stringByAppendingString:@"\r\n"]];
        [strongSelf.textView scrollRangeToVisible:NSMakeRange(strongSelf.textView.text.length-1, 1)];
    });
}

-(void) clearHistory {
    __weak TestMainViewController* weakSelf  = self;
    dispatch_async(dispatch_get_main_queue(),^{
        __strong TestMainViewController* strongSelf = weakSelf;
        strongSelf.textView.text = @"";
        [strongSelf.textView scrollRangeToVisible:NSMakeRange(strongSelf.textView.text.length-1, 1)];
    });
}


-(void) enableTableCell:(BOOL)enable row:(NSInteger)row section:(NSInteger)section{
    dispatch_async(dispatch_get_main_queue(),^{
        NSIndexPath* index = [NSIndexPath indexPathForRow:row inSection:section];
        UITableViewCell* cell = (UITableViewCell*)[self.tableView cellForRowAtIndexPath:index];
        [cell setUserInteractionEnabled:enable];
    });
}

-(void)showMessageBox:(NSString*)message title:(NSString*)title {
    __weak TestMainViewController* weakSelf  = self;
    dispatch_async(dispatch_get_main_queue(),^{
        __strong TestMainViewController* strongSelf = weakSelf;
        UIAlertController* alert = [UIAlertController alertControllerWithTitle: title message:message preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler: nil];
        [alert addAction: defaultAction];
        [strongSelf presentViewController:alert animated:YES completion:nil];
    });
}

-(void) selectConnectionType{
    __weak TestMainViewController* weakSelf  = self;
    AppDelegate* ad = (AppDelegate*)[[UIApplication sharedApplication] delegate];
    UIAlertAction* viaBgate = [UIAlertAction actionWithTitle:@"Via B-gate" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
        __strong TestMainViewController* strongSelf = weakSelf;
        ad.connectionViaBgate = YES;
        UITableViewCell* cell = (UITableViewCell*)[strongSelf.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:2 inSection:0]];
        if(cell)
            [cell detailTextLabel].text = [NSString stringWithFormat:@" Via B-gate"];
    }];
    UIAlertAction* byPass = [UIAlertAction actionWithTitle:@"Direct" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
        __strong TestMainViewController* strongSelf = weakSelf;
        ad.connectionViaBgate = NO;
        UITableViewCell* cell = (UITableViewCell*)[strongSelf.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:2 inSection:0]];
        if(cell)
            [cell detailTextLabel].text = [NSString stringWithFormat:@" Direct"];
    }];
    UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Connection Type" message:@"select a connection type" preferredStyle:UIAlertControllerStyleAlert];
    [alert addAction:viaBgate];
    [alert addAction:byPass];
    [self presentViewController:alert animated:YES completion:nil];
}

@end


@implementation TestMainViewController (PosPrinter)

-(void) openPosPrinter:(NSIndexPath *)indexPath{
    if([self.posPrinter isOpen]){
        return;
    }
    __weak TestMainViewController* weakSelf  = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_async(dispatch_get_main_queue(),^{
            __strong TestMainViewController* strongSelf = weakSelf;
            AppDelegate* ad = (AppDelegate*)[[UIApplication sharedApplication] delegate];
            [strongSelf.posPrinter selectCommandMode: ad.connectionViaBgate ? MPOS_MODE_BGATE : MPOS_MODE_DIRECT];
            [strongSelf.posPrinter selectInterface: ad.conntectionType address: ad.connectionString];
            if([strongSelf.posPrinter openService: ad.deviceId timeout:10 /*seconds*/] != RES_SUCCESS){
                [strongSelf showMessageBox:@"openService failed" title: @"ERROR"];
                return;
            }
            [strongSelf.posPrinter getModelName:^(NSString* modelName) {
                dispatch_async(dispatch_get_main_queue(),^{
                    [strongSelf addHistory: [NSString stringWithFormat:@"Device Name: %@", modelName]];
                });
            }];
            [strongSelf.posPrinter asbEnable:YES];
            [strongSelf enableTableCell: NO row:indexPath.row section:indexPath.section];
            [strongSelf showMessageBox:@"OPEN SUCCESS" title: @"INFO"];
            [strongSelf addHistory:@"OPEN SUCCESS"];
        });
    });
}

-(void) closePosPrinter:(NSIndexPath *)indexPath{
    __weak TestMainViewController* weakSelf  = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        __strong TestMainViewController* strongSelf = weakSelf;
        [strongSelf.posPrinter closeService: 3 /*seconds*/];
        [strongSelf addHistory:@"CLOSED"];
        [strongSelf enableTableCell: YES row:indexPath.row-1 section:indexPath.section];
        dispatch_async(dispatch_get_main_queue(),^{
           UITableViewCell* cell = (UITableViewCell*)[strongSelf.tableView cellForRowAtIndexPath: [NSIndexPath indexPathForRow:4 inSection:1]];
            cell.detailTextLabel.text = @"";
            cell = (UITableViewCell*)[strongSelf.tableView cellForRowAtIndexPath: [NSIndexPath indexPathForRow:0 inSection:1]];
            cell.detailTextLabel.text = @"";
        });
    });
}

-(void) printWithLineMode{
    if(![self.posPrinter isOpen])
        return;
    __weak TestMainViewController* weakSelf  = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        __strong TestMainViewController* strongSelf = weakSelf;
        [strongSelf.posPrinter setTransaction:MPOS_TRANSACTION_IN];
        [strongSelf.posPrinter openDrawer:POS_DRAWER_PIN2];
        [strongSelf.posPrinter printText:@"Default\n" fontType:0 fontWidth:0 fontHeight:0 bold:0 underline:0 reverse:0 alignment:-1];
        [strongSelf.posPrinter printText:@"Bold+Double\n" fontType:0 fontWidth:1 fontHeight:1 bold:1 underline:0 reverse:0 alignment:-1];
        [strongSelf.posPrinter printText:@"Underline in 2 dots\n" fontType:0 fontWidth:0 fontHeight:0 bold:0 underline:2 reverse:0 alignment:-1];
        [strongSelf.posPrinter print1DBarcode:@"{C1234567890" symbology: POS_BARCODE_CODE128 width:2 height:50 alignment: -1 textPosition: 2];
        [strongSelf.posPrinter printImage:[UIImage imageNamed:@"bixolon.jpg"] width:384 alignment:1 threshold:128 ditheringType:1 compressType:1];
        [strongSelf.posPrinter cutPaper:POS_FEED_PARTIAL_CUT];
        [strongSelf.posPrinter setTransaction:MPOS_TRANSACTION_OUT];
    });
}

-(void) printWithPageMode{
    if(![self.posPrinter isOpen])
        return;
    
    __weak TestMainViewController* weakSelf  = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        __strong TestMainViewController* strongSelf = weakSelf;
        NSInteger xPosition = 30;
        NSInteger yPosition = 30;
        [strongSelf.posPrinter setPagemode: POS_PAGEMODE_IN];
        [strongSelf.posPrinter setPagemodePrintArea:0 y:0 width:384 /* dot */ height:600 /* dot */];
        [strongSelf.posPrinter setPagemodeDirection: POS_DIRECTION_RIGHT90];
        [strongSelf.posPrinter printText: @"PAGE MODE #1"];
        yPosition += 30;
        [strongSelf.posPrinter setPagemodePosition: xPosition y: yPosition];
        [strongSelf.posPrinter printText: @"PAGE MODE #2"];
        yPosition += 60;
        [strongSelf.posPrinter setPagemodePosition: xPosition y: yPosition];
        [strongSelf.posPrinter print1DBarcode:@"{C1234567890" symbology: POS_BARCODE_CODE128 width:2 height:50 alignment: 1 textPosition: 0];
        [strongSelf.posPrinter setPagemode: POS_PAGEMODE_OUT];
        [strongSelf.posPrinter cutPaper:POS_FEED_PARTIAL_CUT];
    });
}

-(void) getCurrentPosPrinterStatus:(NSIndexPath *)indexPath{
    __weak TestMainViewController* weakSelf  = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        __strong TestMainViewController* strongSelf = weakSelf;
        [strongSelf.posPrinter checkPrinterStatus:^(NSInteger status){
            [strongSelf updatePosPrinterStatusText:indexPath status:status];
        }];
    });
}

-(void) updatePosPrinterStatusText:(NSIndexPath *)indexPath status:(NSInteger)status{
    __weak TestMainViewController* weakSelf  = self;
    dispatch_async(dispatch_get_main_queue(),^{
        __strong TestMainViewController* strongSelf = weakSelf;
        NSString* msg = @"";
        if(status == 0){
            msg = @"| NORMAL";
        }else{
            if(POS_STATUS_COVEROPEN & status)       msg = [msg stringByAppendingString:@" | COVER_OPEN"];
            if(POS_STATUS_PAPEREMPTY & status)      msg = [msg stringByAppendingString:@" | PAPER_EMPTY"];
            if(POS_STATUS_PAPER_NEAREND & status)   msg = [msg stringByAppendingString:@" | PAPER_NEAREND"];
            if(POS_STATUS_ERROR & status)           msg = [msg stringByAppendingString:@" | ERROR"];
            if(POS_STATUS_BATT_LOW & status)        msg = [msg stringByAppendingString:@" | BATTERY_LOW"];
            if(POS_STATUS_DRAWER_HIGH & status)     msg = [msg stringByAppendingString:@" | CD_HIGH"];
            if(POS_STATUS_DRAWER_LOW & status)      msg = [msg stringByAppendingString:@" | CD_LOW"];
            if(POS_STATUS_OFFLINE & status)         msg = [msg stringByAppendingString:@" | OFFLINE"];
        }
        msg = [msg stringByAppendingString:@" |"];
        [strongSelf addHistory: [NSString stringWithFormat:@"POS Printer Status: %@", msg]];
    });
}

@end

@implementation TestMainViewController (LabelPrinter)

-(void) openLabelPrinter:(NSIndexPath *)indexPath{
    if([self.labelPrinter isOpen])
        return;
    __weak TestMainViewController* weakSelf  = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_async(dispatch_get_main_queue(),^{
            __strong TestMainViewController* strongSelf = weakSelf;
            AppDelegate* ad = (AppDelegate*)[[UIApplication sharedApplication] delegate];
            [strongSelf.labelPrinter selectCommandMode: ad.connectionViaBgate ? MPOS_MODE_BGATE : MPOS_MODE_DIRECT];
            [strongSelf.labelPrinter selectInterface:ad.conntectionType address: ad.connectionString];
            if([strongSelf.labelPrinter openService: ad.deviceId timeout:10 /*seconds*/] != RES_SUCCESS){
                [strongSelf showMessageBox:@"openService failed" title: @"ERROR"];
                return;
            }
            [strongSelf.labelPrinter getModelName:^(NSString* modelName) {
                dispatch_async(dispatch_get_main_queue(),^{
                    [strongSelf addHistory: [NSString stringWithFormat:@"Device Name: %@", modelName]];
                });
            }];
            [strongSelf enableTableCell: NO row:indexPath.row section:indexPath.section];
            [strongSelf showMessageBox:@"OPEN SUCCESS" title: @"INFO"];
            [strongSelf addHistory:@"OPEN SUCCESS"];
        });
    });
}

-(void) closeLabelPrinter:(NSIndexPath *)indexPath{
    __weak TestMainViewController* weakSelf  = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        __strong TestMainViewController* strongSelf = weakSelf;
        [strongSelf.labelPrinter closeService: 3 /*seconds*/];
        [strongSelf addHistory:@"CLOSED"];
        dispatch_async(dispatch_get_main_queue(),^{
            [strongSelf enableTableCell: YES row: indexPath.row-1 section:indexPath.section];
            UITableViewCell* cell = (UITableViewCell*)[strongSelf.tableView cellForRowAtIndexPath: [NSIndexPath indexPathForRow:0 inSection:2]];
            cell.detailTextLabel.text = @"";
            cell = (UITableViewCell*)[strongSelf.tableView cellForRowAtIndexPath: [NSIndexPath indexPathForRow:3 inSection:2]];
            cell.detailTextLabel.text = @"";
        });
    });
}

-(void) printLabel{
    if(![self.labelPrinter isOpen])
        return;
    __weak TestMainViewController* weakSelf  = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        __strong TestMainViewController* strongSelf = weakSelf;
        NSInteger dotsPerUnit = ([strongSelf.labelPrinter getPrinterDPI]) / 25.4;
        [strongSelf.labelPrinter setTransaction:MPOS_TRANSACTION_IN];
        NSArray<NSNumber*>* speeds = [strongSelf.labelPrinter getSupportedSpeeds];
        if([speeds count]){
            NSInteger speed = [[speeds lastObject /*Max Speed*/] integerValue];
            [strongSelf.labelPrinter setSpeed:speed];
        }
        [strongSelf.labelPrinter setDensity:10];
        [strongSelf.labelPrinter setWidth:dotsPerUnit * 52];
        [strongSelf.labelPrinter setLength:dotsPerUnit * 75 gapLength:dotsPerUnit * 3 mediaType: LABEL_MEDIA_TYPE_GAP offsetLength:0];
        [strongSelf.labelPrinter drawBlock:0 startPosY:0 endPosX:dotsPerUnit * 52 endPosY:dotsPerUnit * 73 option:'B' thickness:dotsPerUnit * 2];
        [strongSelf.labelPrinter setCharacterset: LABEL_CODEPAGE_CP437 internationalCharset:LABEL_ICS_USA];
        [strongSelf.labelPrinter drawTextDeviceFont:@"Device Font" xPos:50 yPos:30 fontSelection: LABEL_DEVICE_FONT_10PT fontWidth:1 fontHeight:1 rightSpace:0 rotation:0 reverse:NO bold:NO rightToLeft:NO alignment:0];
        [strongSelf.labelPrinter drawTextVectorFont:@"Vector Font" xPos:50 yPos:100 fontSelection: LABEL_VECTOR_FONT_ASCII fontWidth:30 fontHeight:30 rightSpace:0 rotation:0 reverse:NO bold:NO italic:NO rightToLeft:NO alignment:0];
        [strongSelf.labelPrinter drawBarcode1D:@"0987654321" xPos:300 yPos:150 barcodeType: LABEL_BARCODE_CODE128 widthNarrow:2 widthWide:2 height:128 hri: LABEL_BARCODE_TEXT_BELOW3 quietZoneWidth:0 rotation:1];
        [strongSelf.labelPrinter drawImage:[UIImage imageNamed:@"bixolon.jpg"] xPos:40 yPos:370 width:300 threshold:128 ditheringType:1 compressType:1];
        [strongSelf.labelPrinter printBuffer:1 /* Number of copies */];
        [strongSelf.labelPrinter setTransaction:MPOS_TRANSACTION_OUT];
    });
}

-(void) getCurrentLabelPrinterStatus:(NSIndexPath *)indexPath{
    __weak TestMainViewController* weakSelf  = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        __strong TestMainViewController* strongSelf = weakSelf;
        [strongSelf.labelPrinter checkPrinterStatus:^(NSInteger status){
            dispatch_async(dispatch_get_main_queue(),^{
                NSString* msg = @"";
                if(status == 0){
                    msg = @"NORMAL";
                }else{
                    if(LABEL_STATUS_PAPEREMPTY & status)            msg = @"PAPER EMPTY";
                    if(LABEL_STATUS_COVEROPEN & status)             msg = @"COVER OPEN";
                    if(LABEL_STATUS_CUTTER_JAMMED & status)         msg = @"CUTTER JAM";
                    if(LABEL_STATUS_TPH_OVERHEAT & status)          msg = @"TPH OVERHEAT";
                    if(LABEL_STATUS_GAP_ERROR & status)             msg = @"GAP ERROR";
                    if(LABEL_STATUS_RIBBON_END & status)            msg = @"RIBBON END";
                    if(LABEL_STATUS_ON_BUILDING_LABEL & status)     msg = @"BUILDING LEBEL";
                    if(LABEL_STATUS_ON_PRINTING_LABEL & status)     msg = @"PRINTING LABEL";
                    if(LABEL_STATUS_ISSUED_LABEL_PAUSED & status)   msg = @"LABEL PAUSED";
                    if(LABEL_STATUS_MOTOR_OVERHEAT & status)        msg = @"MOTOR OVERHEAT";
                    if(LABEL_STATUS_BOARD_OVERHEAT & status)        msg = @"BOARD OVERHEAT";
                    if(LABEL_STATUS_WAIT_LABEL_TAKEN & status)      msg = @"WAIT FOR PAER TO BE TAKEN";
                    if(LABEL_STATUS_RFID_WRITING_ERROR & status)    msg = @"RFID WRITING ERROR";
                    if(LABEL_STATUS_PRINTER_OFFLINE & status)       msg = @" LABEL_STATUS_PRINTER_OFFLINE";
                }
                [strongSelf addHistory: [NSString stringWithFormat:@"Label Printer Status: %@", msg]];
            });
        }];
    });
}

@end

@implementation TestMainViewController (BarcodeScanner)

-(void) openBarcodeScanner:(NSIndexPath *)indexPath{
    if([self.barcodeScanner isOpen])
        return;
    __weak TestMainViewController* weakSelf  = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_async(dispatch_get_main_queue(),^{
            __strong TestMainViewController* strongSelf = weakSelf;
            AppDelegate* ad = (AppDelegate*)[[UIApplication sharedApplication] delegate];
            [strongSelf.barcodeScanner selectCommandMode: ad.connectionViaBgate ? MPOS_MODE_BGATE : MPOS_MODE_DIRECT];
            [strongSelf.barcodeScanner selectInterface:ad.conntectionType address: ad.connectionString];
            if([strongSelf.barcodeScanner openService: ad.deviceId] != RES_SUCCESS){
                [strongSelf showMessageBox:@"openService failed" title: @"ERROR"];
                return;
            }
            [strongSelf enableTableCell: NO row:indexPath.row section:indexPath.section];
            [strongSelf showMessageBox:@"OPEN SUCCESS" title: @"INFO"];
            [strongSelf addHistory:@"OPEN SUCCESS"];
        });
    });
}

-(void) closeBarcodeScanner:(NSIndexPath *)indexPath{
    __weak TestMainViewController* weakSelf  = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        __strong TestMainViewController* strongSelf = weakSelf;
        [strongSelf.barcodeScanner closeService:1];
        [strongSelf enableTableCell: YES row:indexPath.row-1 section:indexPath.section];
        [strongSelf addHistory:@"CLOSED"];
    });
}

@end

@implementation TestMainViewController (UsbSerial)

-(void) openTTYUSBDevice:(NSIndexPath *)indexPath{
    if([self.usbToSerialDevice isOpen])
        return;
    __weak TestMainViewController* weakSelf  = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_async(dispatch_get_main_queue(),^{
            __strong TestMainViewController* strongSelf = weakSelf;
            AppDelegate* ad = (AppDelegate*)[[UIApplication sharedApplication] delegate];
            [strongSelf.usbToSerialDevice selectCommandMode: ad.connectionViaBgate ? MPOS_MODE_BGATE : MPOS_MODE_DIRECT];
            [strongSelf.usbToSerialDevice selectInterface:ad.conntectionType address: ad.connectionString];
            if([strongSelf.usbToSerialDevice openService: ad.deviceId] != RES_SUCCESS){
                [strongSelf showMessageBox:@"openService failed" title: @"ERROR"];
                return;
            }
            [strongSelf enableTableCell: NO row:indexPath.row section:indexPath.section];
            [strongSelf showMessageBox:@"OPEN SUCCESS" title: @"INFO"];
            [strongSelf addHistory:@"OPEN SUCCESS"];
        });
    });
}

-(void) closeTTYUSBDevice:(NSIndexPath *)indexPath{
    __weak TestMainViewController* weakSelf  = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        __strong TestMainViewController* strongSelf = weakSelf;
        [strongSelf.usbToSerialDevice closeService:3];
        [strongSelf addHistory:@"CLOSED"];
        [strongSelf enableTableCell: YES row:indexPath.row-1 section:indexPath.section];
    });
}

@end

@implementation TestMainViewController (BgateConfig)

-(void) getSerialCommConfiguration{
    if(![self.usbToSerialDevice isOpen])
        return;
    __weak TestMainViewController* weakSelf  = self;
    MPosControllerConfig* config = [MPosControllerConfig new];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_async(dispatch_get_main_queue(),^{
            __strong TestMainViewController* strongSelf = weakSelf;
            AppDelegate* ad = (AppDelegate*)[[UIApplication sharedApplication] delegate];
            [config selectCommandMode: ad.connectionViaBgate ? MPOS_MODE_BGATE : MPOS_MODE_DIRECT];
            [config selectInterface:ad.conntectionType address: ad.connectionString];
            if([config openService] != RES_SUCCESS){
                [strongSelf showMessageBox:@"getSerialCommConfiguration failed" title: @"ERROR"];
                return;
            }
            [config getSerialConfiguration:[strongSelf.usbToSerialDevice getDeviceId]];
            /*
            [config getSerialConfiguration: [strongSelf.usbToSerialDevice getDeviceId] serialConfigBlock:^(NSArray<NSNumber*>* serialConfig){
                NSLog(@"Serial Communication: %@", serialConfig);
            }];
             */
            [config closeService:0];
        });
    });
}

-(void) setSerialCommConfiguration{
    if(![self.usbToSerialDevice isOpen])
        return;
    __weak TestMainViewController* weakSelf  = self;
    MPosControllerConfig* config = [MPosControllerConfig new];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_async(dispatch_get_main_queue(),^{
            __strong TestMainViewController* strongSelf = weakSelf;
            AppDelegate* ad = (AppDelegate*)[[UIApplication sharedApplication] delegate];
            [config selectCommandMode: ad.connectionViaBgate ? MPOS_MODE_BGATE : MPOS_MODE_DIRECT];
            [config selectInterface:ad.conntectionType address: ad.connectionString];
            if([config openService] != RES_SUCCESS){
                [strongSelf showMessageBox:@"setSerialCommConfiguration failed" title: @"ERROR"];
                return;
            }
            [config setSerialConfig:[strongSelf.usbToSerialDevice getDeviceId] baudRate:6 dataBit:1 stopBit:0 parityBit:0];
            [config closeService:0];
        });
    });
}

@end

@implementation TestMainViewController (CustomerDisplay)

-(void) openCustomerDisplay:(NSIndexPath *)indexPath{
    if([self.customerDisplay isOpen])
        return;
    __weak TestMainViewController* weakSelf  = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_async(dispatch_get_main_queue(),^{
            __strong TestMainViewController* strongSelf = weakSelf;
            AppDelegate* ad = (AppDelegate*)[[UIApplication sharedApplication] delegate];
            [strongSelf.customerDisplay selectCommandMode: ad.connectionViaBgate ? MPOS_MODE_BGATE : MPOS_MODE_DIRECT];
            [strongSelf.customerDisplay selectInterface:ad.conntectionType address: ad.connectionString];
            if([self.customerDisplay openService: ad.deviceId] != RES_SUCCESS){
                [strongSelf showMessageBox:@"openService failed" title: @"ERROR"];
                return;
            }
            [strongSelf.customerDisplay clearScreen];
            [strongSelf enableTableCell: NO row:indexPath.row section:indexPath.section];
            [strongSelf showMessageBox:@"OPEN SUCCESS" title: @"INFO"];
            [strongSelf addHistory:@"OPEN SUCCESS"];
        });
    });
}

-(void) closeCustomerDisplay:(NSIndexPath *)indexPath{
    __weak TestMainViewController* weakSelf  = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        __strong TestMainViewController* strongSelf = weakSelf;
        [strongSelf.customerDisplay closeService: 1];
        [strongSelf addHistory:@"CLOSED"];
        [strongSelf enableTableCell: YES row:indexPath.row-1 section:indexPath.section];
    });
}

-(void) textDisplay{
    if(![_customerDisplay isOpen])
        return;
    __weak TestMainViewController* weakSelf  = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        __strong TestMainViewController* strongSelf = weakSelf;
        [strongSelf.customerDisplay displayString:@"1st Line: HELLO" codePage:POS_CODEPAGE_WPC1252 internationalCharacterSet:POS_ICS_USA line:1];
        [strongSelf.customerDisplay displayString:@"2nd Line: HELLO" codePage:POS_CODEPAGE_WPC1252 internationalCharacterSet:POS_ICS_USA line:2];
    });
}

-(void) clearDisplay{
    if(![_customerDisplay isOpen])
        return;
    __weak TestMainViewController* weakSelf  = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        __strong TestMainViewController* strongSelf = weakSelf;
        [strongSelf.customerDisplay clearScreen];
    });
}

-(void) storeAndDisplayImage{
    if(![_customerDisplay isOpen])
        return;
    __weak TestMainViewController* weakSelf  = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        __strong TestMainViewController* strongSelf = weakSelf;
        [strongSelf.customerDisplay storeImageFile:@"bixolon.jpg" width:-1 imageNumber:1];
        [strongSelf.customerDisplay displayImage:1 xPos:0 yPos:0];
    });
}

@end
