#import "TestMainViewController.h"
#import "AppDelegate.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 (weak) IBOutlet NSScrollView *svHistory;
@property (weak) IBOutlet NSTextField *tfAddress;
@property (weak) IBOutlet NSTextField *tfDeviceId;
@property (weak) IBOutlet NSButton *radioBgate;
@property (weak) IBOutlet NSButton *radioDirect;
@property (weak) IBOutlet NSButton *btnNetConfig;
@end

@implementation TestMainViewController {
    NSTextView      *tvHistory;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    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];
    
    [self initTextView];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceNotificationHandler:) name: @"DataEvent" object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceNotificationHandler:) name: @"StatusUpdateEvent" object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceNotificationHandler:) name: @"OutputCompletedEvent" object:nil];
    
    [self onDeviceIdInit:nil];
    _tfAddress.stringValue = @"Not Assgined";
    _radioBgate.state = NSControlStateValueOn;
    [self toggleMethod:nil];
    [_btnNetConfig setHidden:YES];
    
    // whether create logs or not
//    [MPosControllerDevices setEnableLog:true saveFile:true saveToHex:true];
    NSApplication.sharedApplication.windows.firstObject.delegate = self;
    
    
    // Do any additional setup after loading the view.
}

- (IBAction)toggleMethod:(id)sender {
    AppDelegate* ad = (AppDelegate*)[[NSApplication sharedApplication] delegate];
    switch(_radioBgate.state) {
        case NSControlStateValueOn:
            ad.connectionViaBgate = YES;
            _radioDirect.state = NSControlStateValueOff;
            break;
        case NSControlStateValueOff:
            ad.connectionViaBgate = NO;
            _radioDirect.state = NSControlStateValueOn;
            break;
    }
}

- (void) initTextView {
    NSSize contentSize = [_svHistory contentSize];
    
    tvHistory = [[NSTextView alloc] initWithFrame:NSMakeRect(0, 0, contentSize.width, contentSize.height)];
    [tvHistory setMinSize:NSMakeSize(0.0, contentSize.height)];
    [tvHistory setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
    [tvHistory setVerticallyResizable:YES];
    [tvHistory setHorizontallyResizable:YES];
    [tvHistory setAutoresizingMask:NSViewWidthSizable];
    [tvHistory setEditable:NO];
    
    [[tvHistory textContainer]setContainerSize:NSMakeSize(contentSize.width, FLT_MAX)];
    [[tvHistory textContainer]setWidthTracksTextView:YES];
    [_svHistory setDocumentView:tvHistory];
}

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

-(void) clearHistory {
    tvHistory.string = @"";
}

-(void) updateUIInformation {
    AppDelegate* ad = (AppDelegate*)[[NSApplication sharedApplication] delegate];
    _tfAddress.stringValue = [ad.connectionString  isEqual: @""] ? @"Not Assgined" : ad.connectionString;
    _tfDeviceId.stringValue = [NSString stringWithFormat:@"%@", ad.deviceId == -1 ? @"Not Assigned" : [NSString stringWithFormat:@"%ld", ad.deviceId]];
    [_btnNetConfig setHidden:ad.networkDevice == nil];
}

-(void) updatePosPrinterStatusText:(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]];
    });
}

- (void) deviceNotificationHandler:(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: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"];
    }
}


- (void)setRepresentedObject:(id)representedObject {
    [super setRepresentedObject:representedObject];
    
    // Update the view, if already loaded.
}

- (IBAction)onDeviceIdInit:(id)sender {
    AppDelegate* ad = (AppDelegate*)[[NSApplication sharedApplication] delegate];
    ad.deviceId = -1;
    _tfDeviceId.stringValue = [NSString stringWithFormat:@"%@", ad.deviceId == -1 ? @"Not Assigned" : [NSString stringWithFormat:@"%ld", ad.deviceId]];
}

- (IBAction)onAddressLookup:(id)sender {
    NSViewController* vc = [self.storyboard instantiateControllerWithIdentifier:@"DevListTableViewController"];
    [self presentViewControllerAsSheet:vc];
}

- (IBAction)onDeviceIdLookup:(id)sender {
    NSViewController* vc = [self.storyboard instantiateControllerWithIdentifier:@"DeviceIdTableViewController"];
    [self presentViewControllerAsSheet:vc];
}

- (IBAction)onNetConfigure:(id)sender {
    NSViewController* vc = [self.storyboard instantiateControllerWithIdentifier:@"NetConfigurationViewController"];
    [self presentViewControllerAsSheet:vc];
}

- (void) showMessageBox:(NSString*)message style:(NSAlertStyle)style {
    NSAlert *alert = [NSAlert new];
    alert.alertStyle = style;
    alert.messageText = message;
    [alert runModal];
}

- (IBAction)openPosPrinter:(id)sender {
    if([self.posPrinter isOpen]){
        [self addHistory:@"ALREADY OPENED"];
        return;
    }
    
    AppDelegate* ad = (AppDelegate*)[[NSApplication sharedApplication] delegate];
    [self.posPrinter selectCommandMode: ad.connectionViaBgate ? MPOS_MODE_BGATE : MPOS_MODE_DIRECT];
    [self.posPrinter selectInterface: ad.conntectionType address: ad.connectionString];
    if([self.posPrinter openService: ad.deviceId timeout:10 /*seconds*/] != RES_SUCCESS){
        [self showMessageBox:@"openService failed" style: NSAlertStyleCritical];
        return;
    }
    [self.posPrinter getModelName:^(NSString* modelName) {
        [self addHistory: [NSString stringWithFormat:@"Device Name: %@", modelName]];
    }];
    [self.posPrinter asbEnable:YES];
    [self addHistory:@"OPEN SUCCESS"];
    [self showMessageBox:@"OPEN SUCCESS" style:NSAlertStyleInformational];
}

- (IBAction)closePosPrinter:(id)sender {
    [self.posPrinter closeService: 3 /*seconds*/];
    [self addHistory:@"CLOSED"];
}

- (IBAction)printWithLineMode:(id)sender {
    if(![self.posPrinter isOpen])
        return;
    
    [self.posPrinter setTransaction:MPOS_TRANSACTION_IN];
    [self.posPrinter openDrawer:POS_DRAWER_PIN2];
    [self.posPrinter printText:@"Default\n" fontType:0 fontWidth:0 fontHeight:0 bold:0 underline:0 reverse:0 alignment:-1];
    [self.posPrinter printText:@"Bold+Double\n" fontType:0 fontWidth:1 fontHeight:1 bold:1 underline:0 reverse:0 alignment:-1];
    [self.posPrinter printText:@"Underline in 2 dots\n" fontType:0 fontWidth:0 fontHeight:0 bold:0 underline:2 reverse:0 alignment:-1];
    [self.posPrinter print1DBarcode:@"{C1234567890" symbology: POS_BARCODE_CODE128 width:2 height:50 alignment: -1 textPosition: 2];
    [self.posPrinter printImage:[NSImage imageNamed:@"bixolon.jpg"] width:384 alignment:1 threshold:128 ditheringType:1 compressType:1];
    [self.posPrinter cutPaper:POS_FEED_PARTIAL_CUT];
    [self.posPrinter setTransaction:MPOS_TRANSACTION_OUT];
}

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

- (IBAction)getCurrentPosPrinterStatus:(id)sender {
    __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:status];
        }];
    });
}

- (IBAction)openLabelPrinter:(id)sender {
    if([self.labelPrinter isOpen]) {
        [self addHistory:@"ALREADY OPENED"];
        return;
    }
    
    AppDelegate* ad = (AppDelegate*)[[NSApplication sharedApplication] delegate];
    [self.labelPrinter selectCommandMode: ad.connectionViaBgate ? MPOS_MODE_BGATE : MPOS_MODE_DIRECT];
    [self.labelPrinter selectInterface:ad.conntectionType address: ad.connectionString];
    if([self.labelPrinter openService: ad.deviceId timeout:10 /*seconds*/] != RES_SUCCESS){
        [self showMessageBox:@"openService failed" style: NSAlertStyleCritical];
        return;
    }
    [self.labelPrinter getModelName:^(NSString* modelName) {
        dispatch_async(dispatch_get_main_queue(),^{
            [self addHistory: [NSString stringWithFormat:@"Device Name: %@", modelName]];
        });
    }];
    [self showMessageBox:@"OPEN SUCCESS" style:NSAlertStyleInformational];
    [self addHistory:@"OPEN SUCCESS"];
}

- (IBAction)closeLabelPrinter:(id)sender {
    [self.labelPrinter closeService: 3 /*seconds*/];
    [self addHistory:@"CLOSED"];
}

- (IBAction)printLabel:(id)sender {
    if(![self.labelPrinter isOpen]) {
        return;
    }
    
    NSInteger dotsPerUnit = ([self.labelPrinter getPrinterDPI]) / 25.4;
    [self.labelPrinter setTransaction:MPOS_TRANSACTION_IN];
    NSArray<NSNumber*>* speeds = [self.labelPrinter getSupportedSpeeds];
    if([speeds count]){
        NSInteger speed = [[speeds lastObject /*Max Speed*/] integerValue];
        [self.labelPrinter setSpeed:speed];
    }
    [self.labelPrinter setDensity:10];
    [self.labelPrinter setWidth:dotsPerUnit * 52];
    [self.labelPrinter setLength:dotsPerUnit * 75 gapLength:dotsPerUnit * 3 mediaType: LABEL_MEDIA_TYPE_GAP offsetLength:0];
    [self.labelPrinter drawBlock:0 startPosY:0 endPosX:dotsPerUnit * 52 endPosY:dotsPerUnit * 73 option:'B' thickness:dotsPerUnit * 2];
    [self.labelPrinter setCharacterset: LABEL_CODEPAGE_CP437 internationalCharset:LABEL_ICS_USA];
    [self.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];
    [self.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];
    [self.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];
    [self.labelPrinter drawImage:[NSImage imageNamed:@"bixolon.jpg"] xPos:40 yPos:370 width:300 threshold:128 ditheringType:1 compressType:1];
    [self.labelPrinter printBuffer:1 /* Number of copies */];
    [self.labelPrinter setTransaction:MPOS_TRANSACTION_OUT];
}

- (IBAction)getCurrentLabelPrinterStatus:(id)sender {
    __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]];
            });
        }];
    });
}

- (IBAction)openBarcodeScanner:(id)sender {
    if([self.barcodeScanner isOpen]) {
        [self addHistory:@"ALREADY OPENED"];
        return;
    }
    AppDelegate* ad = (AppDelegate*)[[NSApplication sharedApplication] delegate];
    [self.barcodeScanner selectCommandMode: ad.connectionViaBgate ? MPOS_MODE_BGATE : MPOS_MODE_DIRECT];
    [self.barcodeScanner selectInterface:ad.conntectionType address: ad.connectionString];
    if([self.barcodeScanner openService: ad.deviceId] != RES_SUCCESS){
        [self showMessageBox:@"openService failed" style: NSAlertStyleCritical];
        return;
    }
    [self showMessageBox:@"OPEN SUCCESS" style:NSAlertStyleInformational];
    [self addHistory:@"OPEN SUCCESS"];
}

- (IBAction)closeBarcodeScanner:(id)sender {
    [self.barcodeScanner closeService:1];
    [self addHistory:@"CLOSED"];
}

- (IBAction)openUSBSerialDevice:(id)sender {
    if([self.usbToSerialDevice isOpen]) {
        [self addHistory:@"ALREADY OPENED"];
        return;
    }
    
    AppDelegate* ad = (AppDelegate*)[[NSApplication sharedApplication] delegate];
    [self.usbToSerialDevice selectCommandMode: ad.connectionViaBgate ? MPOS_MODE_BGATE : MPOS_MODE_DIRECT];
    [self.usbToSerialDevice selectInterface:ad.conntectionType address: ad.connectionString];
    if([self.usbToSerialDevice openService: ad.deviceId] != RES_SUCCESS){
        [self showMessageBox:@"openService failed" style: NSAlertStyleCritical];
        return;
    }
    [self showMessageBox:@"OPEN SUCCESS" style: NSAlertStyleInformational];
    [self addHistory:@"OPEN SUCCESS"];
}

- (IBAction)closeUSBSerialDevice:(id)sender {
    [self.usbToSerialDevice closeService:3];
    [self addHistory:@"CLOSED"];
}

- (IBAction)openCustomerDisplay:(id)sender {
    if([self.customerDisplay isOpen]) {
        [self addHistory:@"ALREADY OPENED"];
        return;
    }
    
    AppDelegate* ad = (AppDelegate*)[[NSApplication sharedApplication] delegate];
    [self.customerDisplay selectCommandMode: ad.connectionViaBgate ? MPOS_MODE_BGATE : MPOS_MODE_DIRECT];
    [self.customerDisplay selectInterface:ad.conntectionType address: ad.connectionString];
    if([self.customerDisplay openService: ad.deviceId] != RES_SUCCESS){
        [self showMessageBox:@"openService failed" style: NSAlertStyleCritical];
        return;
    }
    [self.customerDisplay clearScreen];
    [self showMessageBox:@"OPEN SUCCESS" style:NSAlertStyleInformational];
    [self addHistory:@"OPEN SUCCESS"];
}

- (IBAction)closeCustomerDisplay:(id)sender {
    [self.customerDisplay closeService: 1];
    [self addHistory:@"CLOSED"];
}

- (IBAction)textDisplay:(id)sender {
    if(![_customerDisplay isOpen])
        return;
    
    [self.customerDisplay displayString:@"1st Line: HELLO" codePage:POS_CODEPAGE_WPC1252 internationalCharacterSet:POS_ICS_USA line:1];
    [self.customerDisplay displayString:@"2nd Line: HELLO" codePage:POS_CODEPAGE_WPC1252 internationalCharacterSet:POS_ICS_USA line:2];
}

- (IBAction)clearDisplay:(id)sender {
    if(![_customerDisplay isOpen])
        return;
    
    [self.customerDisplay clearScreen];
}

#pragma mark - NSWindowDelegate
- (void)windowDidEndSheet:(NSNotification *)notification {
    [self updateUIInformation];
}

@end
