import UIKit

class TestMainViewController: UIViewController {
    private let resuseIdentifier  = "TableViewCell"
    private let posPrinter = MPosControllerPrinter()
    private let labelPrinter = MPosControllerLabelPrinter()
    private let dotPrinter = MPosControllerDotPrinter()
    private let mPosConfig = MPosControllerConfig()
    private let barcodeScanner = MPosControllerScanner()
    private let usbToSerialDevice = MPosControllerUSBSerial()
    private let customerDisplay = MPosControllerBCD()
    private var tableView = UITableView()
    private var textView = UITextView()
    
    private let buttons:[[String]] = [
        ["Device Selection", "Device ID", "Connection Method", "Net Configure"],        // Connection
        ["Open", "Close", "Print (Line Mode)", "Print (Page Mode)", "Check Status"],    // Pos Printer
        ["Open", "Close", "Print", "Check Status"],                                     // Label Printer
        ["Open", "Close"],                                                              // Barcode Scanner
        ["Open", "Close"],                                                              // USB-Serial
        ["Open", "Close", "Display Text", "Clear Screen"],                              // BCD
    ]
    
    private let sections:[String] = [
        "Device Connection", "Pos Printer", "Label Printer", "Barcode Scanner",
        "USB to Serial (TTY-USB)", "Customer Display (BCD)"]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        print("SDK Version: \(posPrinter.getSDKVersion()!)")
//        MPosControllerPrinter.setEnableLog(true, saveFile: true, saveToHex: true)
        
        let notiCenter = NotificationCenter.default
        notiCenter.addObserver(self, selector: #selector(self.deviceNotificationHandler), name: NSNotification.Name(rawValue: "DataEvent"), object: nil)
        notiCenter.addObserver(self, selector: #selector(self.deviceNotificationHandler), name: NSNotification.Name(rawValue: "StatusUpdateEvent"), object: nil)
        notiCenter.addObserver(self, selector: #selector(self.deviceNotificationHandler), name: NSNotification.Name(rawValue: "OutputCompletedEvent"), object: nil)
        initTextView()
        initTableView()
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        self.clearHistory()
        self.updateConnectionInformation()
    }
    
    func initTextView() {
        textView = UITextView()
        textView.layer.borderColor = UIColor.lightGray.cgColor
        textView.layer.borderWidth = 1
        textView.layer.cornerRadius = 8
        view.addSubview(textView)
        textView.translatesAutoresizingMaskIntoConstraints = false
        textView.isEditable = false
        NSLayoutConstraint.activate([
            textView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 10),
            textView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -10),
            textView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor, constant: 10),
            //textView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
            textView.heightAnchor.constraint(equalToConstant: 100)
        ])
    }
    
    func initTableView() {
        tableView = UITableView()
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: resuseIdentifier)
        tableView.dataSource = self
        tableView.delegate = self
        tableView.backgroundColor = .white
        tableView.tableFooterView = UIView()
        tableView.layer.borderColor = UIColor.lightGray.cgColor
        tableView.layer.borderWidth = 1
        tableView.layer.cornerRadius = 8
        view.addSubview(tableView)
        tableView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            tableView.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 10),
            tableView.rightAnchor.constraint(equalTo: self.view.rightAnchor, constant: -10),
            tableView.topAnchor.constraint(equalTo: self.textView.bottomAnchor, constant: 10),
            tableView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor)
        ])
    }
    
    func updateConnectionInformation() {
        DispatchQueue.main.async { [weak self] in
            guard let strongSelf = self else { return }
            let ad = UIApplication.shared.delegate as! AppDelegate
            var cell = strongSelf.tableView.cellForRow(at: IndexPath(row: 0, section: 0))
            if cell != nil{
                let address = (ad.connectionString.count) > 0 ? String(ad.connectionString) : "Not Assigned"
                cell?.detailTextLabel?.text = " Address: \(address)"
                if (ad.deviceName.count) > 0 {
                    cell?.detailTextLabel?.text = " \(ad.deviceName), Address: \(address)"
                }
            }
            cell = strongSelf.tableView.cellForRow(at: IndexPath(row: 1, section: 0))
            if cell != nil{
                cell?.detailTextLabel?.text = " ID: Not Assigned"
                if ad.deviceId > 0 {
                    cell?.detailTextLabel?.text = " ID:\(String(describing: ad.deviceId))"
                }
            }
            cell = strongSelf.tableView.cellForRow(at: IndexPath(row: 2, section: 0))
            if cell != nil{
                cell?.detailTextLabel?.text = " Direct"
                if ad.connectionViaBgate {
                    cell?.detailTextLabel?.text = " Via B-gate"
                }
            }
            
            if !strongSelf.posPrinter.isOpen(){
                strongSelf.enableTableCell(enable: true, row: 0, section: 1)
            }
            if !strongSelf.labelPrinter.isOpen(){
                strongSelf.enableTableCell(enable: true, row: 0, section: 2)
            }
            if !strongSelf.barcodeScanner.isOpen(){
                strongSelf.enableTableCell(enable: true, row: 0, section: 3)
            }
            if !strongSelf.usbToSerialDevice.isOpen(){
                strongSelf.enableTableCell(enable: true, row: 0, section: 4)
            }
            if !strongSelf.customerDisplay.isOpen(){
                strongSelf.enableTableCell(enable: true, row: 0, section: 5)
            }
        }
    }
}


extension TestMainViewController: UITableViewDelegate, UITableViewDataSource {
    
    func numberOfSections(in tableView: UITableView) -> Int {
        return sections.count
    }
    
    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return sections[section]
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return buttons[section].count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        var cell: UITableViewCell? = self.tableView.dequeueReusableCell(withIdentifier: resuseIdentifier, for: indexPath)
        cell = UITableViewCell(style: .default, reuseIdentifier: resuseIdentifier)
        if indexPath.section == 0 {
            cell = UITableViewCell(style: .subtitle, reuseIdentifier: resuseIdentifier)
            switch indexPath.row {
            case 0: cell!.detailTextLabel?.text = "Address"
            case 1: cell!.detailTextLabel?.text = "ID"
            case 2: cell!.detailTextLabel?.text = "Via"
            default:
                break
            }
            self.updateConnectionInformation()
        }
        cell!.textLabel?.text = buttons[indexPath.section][indexPath.row]
        return cell!
    }
 
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("\(indexPath)")
        self.tableView.deselectRow(at: indexPath, animated: true)
        switch indexPath {
        // Connection
        case [0,0]:
            let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "DevListTableVC")
            self.navigationController?.pushViewController(vc, animated: true)
        case [0,1]:
            let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "DeviceIdTableVC")
            self.navigationController?.pushViewController(vc, animated: true)
        case [0,2]: self.selectConnectionType()
        case [0,3]:
            let ad = UIApplication.shared.delegate as! AppDelegate
            if let _ = ad.networkDevice {
                let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "NetConfigurationVC")
                self.navigationController?.pushViewController(vc, animated: true)
            }else{
                self.showMessageBox(message: "Select a network device first through \"Device Selection\"", title: "ERROR")
            }
        // Pos Printer
        case [1,0]: self.openPosPrinter(index: indexPath)
        case [1,1]: self.closePosPrinter(index: indexPath)
        case [1,2]: self.printWithLineMode(index: indexPath)
        case [1,3]: self.printWithPageMode(index: indexPath)
        case [1,4]: self.getCurrentPosPrinterStatus(index: indexPath)
        // Label Printer
        case [2,0]: self.openLabelPrinter(index: indexPath)
        case [2,1]: self.closeLabelPrinter(index: indexPath)
        case [2,2]: self.printLabel()
        case [2,3]: self.getCurrentLabelPrinterStatus(index: indexPath)
        // Barcode Scanner
        case [3,0]: self.openBarcodeScanner(index: indexPath)
        case [3,1]: self.closeBarcodeScanner(index: indexPath)
        // USB-Serial
        case [4,0]: self.openUSBSerialDevice(index: indexPath)
        case [4,1]: self.closeUSBSerialDevice(index: indexPath)
        // BCD
        case [5,0]: self.openCustomerDisplay(index: indexPath)
        case [5,1]: self.closeCustomerDisplay(index: indexPath)
        case [5,2]: self.textDisplay()
        case [5,3]: self.clearDisplay()
        default:
            return
        }
    }
}

extension TestMainViewController {

    func addHistory(text:String) {
        DispatchQueue.main.async { [weak self] in
            guard let strongSelf = self else { return }
            strongSelf.textView.text = strongSelf.textView.text.appending(text.appending("\r\n"))
            strongSelf.textView.scrollRangeToVisible(NSMakeRange(strongSelf.textView.text.count - 1, 1))
        }
    }
    
    func clearHistory() {
        DispatchQueue.main.async { [weak self] in
            guard let strongSelf = self else { return }
            strongSelf.textView.text = ""
            strongSelf.textView.scrollRangeToVisible(NSMakeRange(strongSelf.textView.text.count - 1, 1))
        }
    }
    
    func selectConnectionType(){
        let ad = UIApplication.shared.delegate as! AppDelegate
        let viaBgate = UIAlertAction(title: "Via B-gate", style: .default) { (UIAlertAction) in
            ad.connectionViaBgate = true
            if let cell = self.tableView.cellForRow(at: IndexPath(row: 2, section: 0)){
                cell.detailTextLabel?.text = "Via B-gate"
            }
        }
        let direct = UIAlertAction(title: "Direct", style: .default) { (UIAlertAction) in
            ad.connectionViaBgate = false
            if let cell = self.tableView.cellForRow(at: IndexPath(row: 2, section: 0)){
                cell.detailTextLabel?.text = "Direct"
            }
        }
        let alert = UIAlertController(title: "Connection Type", message: "Select a connection type", preferredStyle: .alert)
        alert.addAction(viaBgate)
        alert.addAction(direct)
        self.present(alert, animated: true, completion: nil)
    }
    
    func enableTableCell(enable: Bool, row: Int, section: Int){
        DispatchQueue.main.async {
            let indexPath = IndexPath(row: row, section: section)
            if let cell = self.tableView.cellForRow(at: indexPath){
                cell.isUserInteractionEnabled = enable
            }
        }
    }
    
    func showMessageBox(message: String, title:String){
        DispatchQueue.main.async {
            let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
            let defaultAction = UIAlertAction(title: "OK", style: .default, handler: nil)
            alert.addAction(defaultAction)
            self.present(alert, animated: true, completion: nil)
        }
    }
    
    @objc func deviceNotificationHandler(notification:NSNotification){
        DispatchQueue.main.async { [weak self] in
            guard let strongSelf = self else { return }
            if notification.name.rawValue.compare("StatusUpdateEvent").rawValue == 0 {
                let deviceId = notification.object as! Int
                if(deviceId != strongSelf.posPrinter.getDeviceId()){ return }
                for key in notification.userInfo!.keys {
                    let status = notification.userInfo![key] as! Int
                    print("notification.name = \(notification.name), id = \(deviceId), status = \(status)")
                    strongSelf.updatePosPrinterStatusText(index: IndexPath(row: 4, section: 1), printerStatus: status)
                }
            } else if notification.name.rawValue.compare("DataEvent").rawValue  == 0 {
                let deviceId = notification.object as! Int
                for key in notification.userInfo!.keys {
                    let devData = notification.userInfo![key] as! Data
                    let message = String(format: "ID = %ld, data = %@", deviceId, devData as CVarArg)
                    strongSelf.addHistory(text: message)
                }
            }else if notification.name.rawValue.compare("OutputCompletedEvent").rawValue == 0 {
                strongSelf.addHistory(text: "OutputCompletedEvent")
            }
        }
    }
}

extension TestMainViewController {
    
    func openPosPrinter(index:IndexPath){
        if(self.posPrinter.isOpen()){ return }
        DispatchQueue.global(qos: .background).async {
            DispatchQueue.main.async { [weak self] in
                guard let strongSelf = self else { return }
                let ad = UIApplication.shared.delegate as! AppDelegate
                strongSelf.posPrinter.selectCommand(ad.connectionViaBgate ? MPOS_COMMAND_MODE.MODE_BGATE : MPOS_COMMAND_MODE.MODE_DIRECT)
                strongSelf.posPrinter.selectInterface(MPOS_INTERFACE_TYPE(rawValue: ad.conntectionType)!, address: ad.connectionString)
                if strongSelf.posPrinter.openService(ad.deviceId, timeout: 10 /*seconds*/).rawValue != MPOS_RESULT.RES_SUCCESS.rawValue {
                    strongSelf.showMessageBox(message: "openService failed", title: "ERROR")
                    return
                }
                strongSelf.posPrinter.getModelName({ (modelName: String?) in
                    DispatchQueue.main.async {
                        strongSelf.addHistory(text: "Device Name: \(modelName!)")
                    }
                })
                strongSelf.posPrinter.asbEnable(true)
                strongSelf.enableTableCell(enable: false, row: index.row, section: index.section)
                strongSelf.showMessageBox(message: "OPEN SUCCESS", title: "INFO")
                strongSelf.addHistory(text: "OPEN SUCCESS")
            }
        }
    }
    
    func closePosPrinter(index:IndexPath){
        DispatchQueue.global(qos: .background).async { [weak self] in
            guard let strongSelf = self else { return }
            strongSelf.posPrinter.closeService(3 /*seconds*/)
            strongSelf.addHistory(text: "CLOSED")
            DispatchQueue.main.async {
                strongSelf.enableTableCell(enable: true, row: index.row-1, section: index.section)
                var indexPath = IndexPath(row: 0, section: 1)
                if let cell = strongSelf.tableView.cellForRow(at: indexPath){
                    cell.detailTextLabel?.text = ""
                }
                indexPath = IndexPath(row: 4, section: 1)
                if let cell = strongSelf.tableView.cellForRow(at: indexPath){
                    cell.detailTextLabel?.text = ""
                }
            }
        }
    }

    func printWithLineMode(index:IndexPath){
        if(!self.posPrinter.isOpen()){ return }
        DispatchQueue.global(qos: .background).async { [weak self] in
            guard let strongSelf = self else { return }
            strongSelf.posPrinter.setTransaction(MPOS_TRANSACTION.IN.rawValue)
            strongSelf.posPrinter.openDrawer(MPOS_CASHDRAWER_PIN.POS_DRAWER_PIN2.rawValue)
            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: 110 /*Code128*/, width: 2, height: 50, alignment: -1, textPosition: 2)
            strongSelf.posPrinter.printImage(UIImage(named: "bixolon.jpg"), width: 384, alignment: 1, threshold: 128, ditheringType: 1, compressType: 1)
            strongSelf.posPrinter.cutPaper(MPOS_PRINTER_CUTTYPE.POS_FEED_PARTIAL_CUT.rawValue)
            strongSelf.posPrinter.setTransaction(MPOS_TRANSACTION.OUT.rawValue)
            
            /*
            self.posPrinter.printPDF417("1234567890", symbol: 201, alignment: -1, columnNumber: 30, rowNumber: 30, moduleWidth: 2, moduleHeight: 4, eccLevel: 0)
            self.posPrinter.printQRCode("1231283123", model: 204, alignment: -1, moduleSize: 8, eccLevel: 48)
            self.posPrinter.printDataMatrix("123123dslkjf", alignment: -1, moduleSize: 3)

            self.posPrinter.printAztec("12345678", alignment: -1, moduleSize: 8, eccLevel: 48, mode: 0)
            self.posPrinter.printMaxicode("1234123", mode: 52, alignment: -1)
            self.posPrinter.printGS1DatabarMobile("1234567890", cData: "1234567890", symbol: 50, alignment: -1, moduleSize: 2, moduleHeight: 2, segmentHeight: 32, separatorHeight: 2)

            strongSelf.posPrinter.printGS1Databar("123457", symbol: 72, alignment: -1, moduleSize: 2)
            strongSelf.posPrinter.printGS1Databar("123457", symbol: 73, alignment: -1, moduleSize: 3)
            strongSelf.posPrinter.printCompositeSymbology("1258067", cData: "000", symbol: 65, cSymbol: 65, alignment: -1, size: 2)
            strongSelf.posPrinter.printBitmapFile("bixolon.jpg", width: 300, alignment: MPOS_ALIGNMENT.POS_ALIGNMENT_CENTER.rawValue, brightness: 80, isDithering: true, isCompress: true)
            strongSelf.posPrinter.cutPaper(Int(MPOS_PRINTER_CUTTYPE.POS_FEED_PARTIAL_CUT.rawValue))
            
            print("getFirmwareVersion: \(strongSelf.posPrinter.getFirmwareVersion())");
            
            var scrData:NSData? = nil
            strongSelf.posPrinter.powerUpSCR(&scrData)
            print("scrData = \(scrData)")
            var scrResponse:NSData? = nil
            var scrSendData:Data = Data(bytes: [0x00, 0xCA, 0x00, 0x00, 0x00] as [UInt8], count: 5)
            strongSelf.posPrinter.exchangeSCRData(scrSendData, response: &scrResponse)
            print("scrResponse = \(scrResponse)")

            var scrCardStatus:NSData? = nil
            strongSelf.posPrinter.getSCRCardStatus(&scrCardStatus)
            print("scrCardStatus = \(scrCardStatus)")
            strongSelf.posPrinter.powerDownSCR()
            
            var resultString = strongSelf.posPrinter.getStatisticsData(MPOS_POS_STATISTICS.POS_STATS_TPH1.rawValue)
            print("\(resultString)")
            resultString = strongSelf.posPrinter.getStatisticsData(MPOS_POS_STATISTICS.POS_STATS_TPH2.rawValue)
            print("\(resultString)")
            
            strongSelf.posPrinter.showCursor(0);
            strongSelf.posPrinter.displayString("ABCD", codePage: 0, internationalCharacterSet: 0, line: 1)
            strongSelf.posPrinter.msrReady()
            */
        }
    }

    func printWithPageMode(index:IndexPath){
        if(!self.posPrinter.isOpen()){ return }
        DispatchQueue.global(qos: .background).async { [weak self] in
            guard let strongSelf = self else { return }
//            self.posPrinter.setPagemode(MPOS_PRINTER_PAGEMODE(rawValue: 1 /* PAGEMODE IN */)!.rawValue)
//            self.posPrinter.setPagemodePrintArea(0, y: 0, width: 384, height: 400)
//            self.posPrinter.setPagemodeDirection(MPOS_PRINTER_PD(rawValue: 0)!.rawValue);
//            self.posPrinter.printText("LEFT TO RIGHT");
//            self.posPrinter.setPagemodeDirection(MPOS_PRINTER_PD(rawValue: 1)!.rawValue);
//            self.posPrinter.printText("BOTTOM TO TOP");
//            self.posPrinter.setPagemodeDirection(MPOS_PRINTER_PD(rawValue: 2)!.rawValue);
//            self.posPrinter.printText("RIGHT TO LEFT");
//            self.posPrinter.setPagemodeDirection(MPOS_PRINTER_PD(rawValue: 3)!.rawValue);
//            self.posPrinter.printText("TOP TO BOTTOM");
//            self.posPrinter.setPagemode(MPOS_PRINTER_PAGEMODE(rawValue: 0 /* PAGEMODE OUT*/)!.rawValue)
            var yPosition : Int = 30
            strongSelf.posPrinter.setPagemode(MPOS_PRINTER_PAGEMODE.POS_PAGEMODE_IN.rawValue)
            strongSelf.posPrinter.setPagemodePrintArea(0, y: 0, width: 384 /* dot */, height: 600 /* dot */)
            strongSelf.posPrinter.setPagemodeDirection(MPOS_PRINTER_PD.POS_DIRECTION_RIGHT90.rawValue);
            strongSelf.posPrinter.printText("PAGE MODE #1");
            yPosition += 30;
            strongSelf.posPrinter.setPagemodePosition(30, y: yPosition)
            strongSelf.posPrinter.printText("PAGE MODE #2");
            yPosition += 60;
            strongSelf.posPrinter.setPagemodePosition(30, y: yPosition)
            strongSelf.posPrinter.print1DBarcode("{C1234567890", symbology: 110 /*Code128*/, width: 2, height: 50, alignment: -1, textPosition: 0)
            strongSelf.posPrinter.setPagemode(MPOS_PRINTER_PAGEMODE.POS_PAGEMODE_OUT.rawValue)
            strongSelf.posPrinter.cutPaper(MPOS_PRINTER_CUTTYPE.POS_FEED_PARTIAL_CUT.rawValue)
        }
    }

    func updatePosPrinterStatusText(index:IndexPath, printerStatus:Int){
        DispatchQueue.global(qos: .background).async {
            DispatchQueue.main.async { [weak self] in
                guard let strongSelf = self else { return }
                var message = ""
                if(printerStatus == 0){
                    message = "| NORMAL"
                }else{
                    if(MPOS_STATUS.POS_STATUS_COVEROPEN.rawValue & printerStatus != 0) {message += " | COVER_OPEN"}
                    if(MPOS_STATUS.POS_STATUS_PAPEREMPTY.rawValue & printerStatus != 0) {message += " | PAPER_EMPTY"}
                    if(MPOS_STATUS.POS_STATUS_PAPER_NEAREND.rawValue & printerStatus != 0) {message += " | PAPER_NEAREND"}
                    if(MPOS_STATUS.POS_STATUS_ERROR.rawValue & printerStatus != 0) {message += " | ERROR"}
                    if(MPOS_STATUS.POS_STATUS_BATT_LOW.rawValue & printerStatus != 0) {message += " | BATTERY_LOW"}
                    if(MPOS_STATUS.POS_STATUS_DRAWER_HIGH.rawValue & printerStatus != 0) {message += " | CD_HIGH"}
                    if(MPOS_STATUS.POS_STATUS_DRAWER_LOW.rawValue & printerStatus != 0) {message += " | CD_LOW"}
                    if(MPOS_STATUS.POS_STATUS_OFFLINE.rawValue & printerStatus != 0)    {message += " | OFFLINE" }
                }
                message += " |"
                strongSelf.addHistory(text: "POS Printer Status: \(message)")
            }
        }
    }
    
    func getCurrentPosPrinterStatus(index:IndexPath){
        DispatchQueue.global(qos: .background).async { [weak self] in
            guard let strongSelf = self else { return }
            strongSelf.posPrinter.checkStatus({ (printerStatus:Int) in
                strongSelf.updatePosPrinterStatusText(index: index, printerStatus: printerStatus)
            })
        }
    }
    
    func openLabelPrinter(index:IndexPath){
        if(self.labelPrinter.isOpen()){ return }
        DispatchQueue.global(qos: .background).async {
            DispatchQueue.main.async { [weak self] in
                guard let strongSelf = self else { return }
                let ad = UIApplication.shared.delegate as! AppDelegate
                let commandMode = ad.connectionViaBgate ? MPOS_COMMAND_MODE.MODE_BGATE : MPOS_COMMAND_MODE.MODE_DIRECT
                strongSelf.labelPrinter.selectCommand(commandMode)
                strongSelf.labelPrinter.selectInterface(MPOS_INTERFACE_TYPE(rawValue: ad.conntectionType)!, address: ad.connectionString)
                if strongSelf.labelPrinter.openService(ad.deviceId, timeout: 10 /*seconds*/).rawValue != MPOS_RESULT.RES_SUCCESS.rawValue {
                    strongSelf.showMessageBox(message: "openService failed", title: "ERROR")
                    return
                }
                strongSelf.labelPrinter.getModelName({ (modelName: String?) in
                    DispatchQueue.main.async {
                        strongSelf.addHistory(text: "Device Name: \(modelName!)")
                    }
                })
                strongSelf.enableTableCell(enable: false, row: index.row, section: index.section)
                strongSelf.showMessageBox(message: "OPEN SUCCESS", title: "INFO")
                strongSelf.addHistory(text: "OPEN SUCCESS")
            }
        }
    }
    
    func closeLabelPrinter(index:IndexPath){
        DispatchQueue.global(qos: .background).async { [weak self] in
            guard let strongSelf = self else { return }
            strongSelf.labelPrinter.closeService(3/*seconds*/)
            strongSelf.addHistory(text: "CLOSED")
            DispatchQueue.main.async {
                strongSelf.enableTableCell(enable: true, row: index.row-1, section: index.section)
                var indexPath = IndexPath(row: 0, section: 2)
                if let cell = strongSelf.tableView.cellForRow(at: indexPath){
                    cell.detailTextLabel?.text = ""
                }
                indexPath = IndexPath(row: 3, section: 2)
                if let cell = strongSelf.tableView.cellForRow(at: indexPath){
                    cell.detailTextLabel?.text = ""
                }
            }
        }
    }

    func printLabel(){
        if(!self.labelPrinter.isOpen()){ return }
        DispatchQueue.global(qos: .background).async { [weak self] in
            guard let strongSelf = self else { return }
            let dotsPerUnit : Double = Double(strongSelf.labelPrinter.getPrinterDPI()) / 25.4
            strongSelf.labelPrinter.setTransaction(MPOS_TRANSACTION.IN.rawValue)
            if let speeds = strongSelf.labelPrinter.getSupportedSpeeds(), speeds.count > 0 {
                strongSelf.labelPrinter.setSpeed(speeds.first!.intValue /*Max Speed*/)
            }
            strongSelf.labelPrinter.setDensity(10)
            strongSelf.labelPrinter.setWidth(Int(dotsPerUnit * 52))
            strongSelf.labelPrinter.setLength(Int(dotsPerUnit * 75), gapLength: Int(dotsPerUnit * 3), mediaType: MPOS_LABEL_MEDIA_TYPE.LABEL_MEDIA_TYPE_GAP.rawValue, offsetLength: 0)
            strongSelf.labelPrinter.drawBlock(0, startPosY: 0, endPosX: Int(dotsPerUnit * 52), endPosY: Int(dotsPerUnit * 73), option: Int8(0x42/*B*/), thickness: Int(dotsPerUnit * 2))
            strongSelf.labelPrinter.setCharacterset(MPOS_LABEL_CONFIG_CODEPAGE.LABEL_CODEPAGE_CP437.rawValue, internationalCharset: MPOS_LABEL_CONFIG_ICS.LABEL_ICS_USA.rawValue)
            strongSelf.labelPrinter.drawTextDeviceFont("Device Font", xPos: 50, yPos: 30, fontSelection: MPOS_LABEL_DEVICE_FONT.LABEL_DEVICE_FONT_15PT.rawValue, fontWidth: 1, fontHeight: 1, rightSpace: 0, rotation: 0, reverse: false, bold: false, rightToLeft: false, alignment: 0)
            strongSelf.labelPrinter.drawTextVectorFont("Vector Font", xPos: 50, yPos: 100, fontSelection: MPOS_LABEL_VECTOR_FONT.LABEL_VECTOR_FONT_ASCII.rawValue, fontWidth: 30, fontHeight: 30, rightSpace: 0, rotation: 0, reverse: false, bold: false, italic: false, rightToLeft: false, alignment: 0)
            strongSelf.labelPrinter.drawBarcode1D("0987654321", xPos: 300, yPos: 150, barcodeType: MPOS_LABEL_BARCODE_TYPE.LABEL_BARCODE_CODE128.rawValue, widthNarrow: 2, widthWide: 2, height: 128, hri: MPOS_LABEL_BARCODE_HRI.LABEL_BARCODE_TEXT_BELOW3.rawValue, quietZoneWidth: 0, rotation: 1)
            strongSelf.labelPrinter.drawImage(UIImage(named: "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.rawValue)
        }
    }

    func getCurrentLabelPrinterStatus(index:IndexPath){
        DispatchQueue.global(qos: .background).async { [weak self] in
            guard let strongSelf = self else { return }
            var message = ""
            strongSelf.labelPrinter.checkStatus({ (printerStatus:Int) in
                DispatchQueue.main.async {
                    if(printerStatus == 0){
                        message = "NORMAL"
                    }else{
                        if(MPOS_LABEL_STATUS.LABEL_STATUS_COVEROPEN.rawValue & printerStatus != 0) {message += " COVER_OPEN"}
                        if(MPOS_LABEL_STATUS.LABEL_STATUS_PAPEREMPTY.rawValue & printerStatus != 0) {message += " PAPER_EMPTY"}
                        if(MPOS_LABEL_STATUS.LABEL_STATUS_CUTTER_JAMMED.rawValue & printerStatus != 0) {message += " CUTTER_JAM"}
                        if(MPOS_LABEL_STATUS.LABEL_STATUS_TPH_OVERHEAT.rawValue & printerStatus != 0) {message += " TPH_OVERHEAT"}
                        if(MPOS_LABEL_STATUS.LABEL_STATUS_GAP_ERROR.rawValue & printerStatus != 0) {message += " GAP_ERROR"}
                        if(MPOS_LABEL_STATUS.LABEL_STATUS_RIBBON_END.rawValue & printerStatus != 0) {message += " RIBBON END"}
                        if(MPOS_LABEL_STATUS.LABEL_STATUS_ON_BUILDING_LABEL.rawValue & printerStatus != 0) {message += " BUILDING LEBEL"}
                        if(MPOS_LABEL_STATUS.LABEL_STATUS_ON_PRINTING_LABEL.rawValue & printerStatus != 0) {message += " PRINTING LABEL"}
                        if(MPOS_LABEL_STATUS.LABEL_STATUS_ISSUED_LABEL_PAUSED.rawValue & printerStatus != 0) {message += " LABEL PAUSED"}
                        if(MPOS_LABEL_STATUS.LABEL_STATUS_MOTOR_OVERHEAT.rawValue & printerStatus != 0) {message += " MOTOR_OVERHEAT"}
                        if(MPOS_LABEL_STATUS.LABEL_STATUS_BOARD_OVERHEAT.rawValue & printerStatus != 0) {message += " BOARD_OVERHEAT"}
                        if(MPOS_LABEL_STATUS.LABEL_STATUS_WAIT_LABEL_TAKEN.rawValue & printerStatus != 0) {message += " WAIT_FOR_LABEL_TO_BE_TAKEN"}
                        if(MPOS_LABEL_STATUS.LABEL_STATUS_PRINTER_OFFLINE.rawValue & printerStatus != 0) {message += " LABEL_STATUS_PRINTER_OFFLINE"}
                    }
                    strongSelf.addHistory(text: "Label Printer Status: \(message)")
                }
            })
        }
    }

    func openBarcodeScanner(index:IndexPath){
        DispatchQueue.global(qos: .background).async { [weak self] in
            guard let strongSelf = self else { return }
            DispatchQueue.main.async {
                let ad = UIApplication.shared.delegate as! AppDelegate
                strongSelf.barcodeScanner.selectCommand(ad.connectionViaBgate ? MPOS_COMMAND_MODE.MODE_BGATE : MPOS_COMMAND_MODE.MODE_DIRECT)
                strongSelf.barcodeScanner.selectInterface(MPOS_INTERFACE_TYPE(rawValue: ad.conntectionType)!, address: ad.connectionString)
                if strongSelf.barcodeScanner.openService(ad.deviceId).rawValue != MPOS_RESULT.RES_SUCCESS.rawValue {
                    strongSelf.showMessageBox(message: "openService failed", title: "ERROR")
                    return
                }
                strongSelf.enableTableCell(enable: false, row: index.row, section: index.section)
                strongSelf.showMessageBox(message: "OPEN SUCCESS", title: "INFO")
            }
        }
    }
    
    func closeBarcodeScanner(index:IndexPath){
        DispatchQueue.global(qos: .background).async { [weak self] in
            guard let strongSelf = self else { return }
            strongSelf.barcodeScanner.closeService(0)
            strongSelf.addHistory(text: "CLOSED")
            strongSelf.enableTableCell(enable: true, row: index.row-1, section: index.section)
        }
    }

    func openUSBSerialDevice(index:IndexPath){
        if(self.usbToSerialDevice.isOpen()){ return }
        DispatchQueue.global(qos: .background).async { [weak self] in
            guard let strongSelf = self else { return }
            DispatchQueue.main.async {
                let ad = UIApplication.shared.delegate as! AppDelegate
                strongSelf.usbToSerialDevice.selectCommand(ad.connectionViaBgate ? MPOS_COMMAND_MODE.MODE_BGATE : MPOS_COMMAND_MODE.MODE_DIRECT)
                strongSelf.usbToSerialDevice.selectInterface(MPOS_INTERFACE_TYPE(rawValue: ad.conntectionType)!, address: ad.connectionString)
                if strongSelf.usbToSerialDevice.openService(ad.deviceId).rawValue != MPOS_RESULT.RES_SUCCESS.rawValue {
                    strongSelf.showMessageBox(message: "openService failed", title: "ERROR")
                    return
                }
                strongSelf.enableTableCell(enable: false, row: index.row, section: index.section)
                strongSelf.showMessageBox(message: "OPEN SUCCESS", title: "INFO")
            }
        }
    }

    func getSerialCommConfiguration(){
        if(!self.usbToSerialDevice.isOpen()){ return }
        DispatchQueue.global(qos: .background).async { [weak self] in
            guard let strongSelf = self else { return }
            DispatchQueue.main.async {
                let ad = UIApplication.shared.delegate as! AppDelegate
                let config = MPosControllerConfig()
                config.selectCommand(ad.connectionViaBgate ? MPOS_COMMAND_MODE.MODE_BGATE : MPOS_COMMAND_MODE.MODE_DIRECT)
                config.selectInterface(MPOS_INTERFACE_TYPE(rawValue: ad.conntectionType)!, address: ad.connectionString)
                if(config.openService().rawValue != MPOS_RESULT.RES_SUCCESS.rawValue){
                    strongSelf.showMessageBox(message: "getSerialCommConfiguration failed", title: "ERROR")
                    return
                }
                config.getSerialConfiguration(strongSelf.usbToSerialDevice.getDeviceId())
            }
        }
    }

    func setSerialCommConfiguration(){
        if(!self.usbToSerialDevice.isOpen()){ return }
        DispatchQueue.global(qos: .background).async { [weak self] in
            guard let strongSelf = self else { return }
            DispatchQueue.main.async {
                let ad = UIApplication.shared.delegate as! AppDelegate
                let config = MPosControllerConfig()
                config.selectCommand(ad.connectionViaBgate ? MPOS_COMMAND_MODE.MODE_BGATE : MPOS_COMMAND_MODE.MODE_DIRECT)
                config.selectInterface(MPOS_INTERFACE_TYPE(rawValue: ad.conntectionType)!, address: ad.connectionString)
                if(config.openService().rawValue != MPOS_RESULT.RES_SUCCESS.rawValue){
                    strongSelf.showMessageBox(message: "setSerialCommConfiguration failed", title: "ERROR")
                    return
                }
                strongSelf.addHistory(text: "OPEN SUCCESS")
                config.setSerial(strongSelf.usbToSerialDevice.getDeviceId(), baudRate: 6, dataBit: 1, stopBit: 0, parityBit: 0)
            }
        }
    }
    
    func closeUSBSerialDevice(index:IndexPath){
        DispatchQueue.global(qos: .background).async { [weak self] in
            guard let strongSelf = self else { return }
            strongSelf.usbToSerialDevice.closeService(0)
            strongSelf.addHistory(text: "CLOSED")
            strongSelf.enableTableCell(enable: true, row: index.row-1, section: index.section)
        }
    }

    func openCustomerDisplay(index:IndexPath){
        if(self.customerDisplay.isOpen()){ return }
        DispatchQueue.global(qos: .background).async { [weak self] in
            guard let strongSelf = self else { return }
            DispatchQueue.main.async {
                let ad = UIApplication.shared.delegate as! AppDelegate
                strongSelf.customerDisplay.selectCommand(ad.connectionViaBgate ? MPOS_COMMAND_MODE.MODE_BGATE : MPOS_COMMAND_MODE.MODE_DIRECT)
                strongSelf.customerDisplay.selectInterface(MPOS_INTERFACE_TYPE(rawValue: ad.conntectionType)!, address: ad.connectionString)
                if strongSelf.customerDisplay.openService(ad.deviceId).rawValue != MPOS_RESULT.RES_SUCCESS.rawValue {
                    strongSelf.showMessageBox(message: "openService failed", title: "ERROR")
                    return
                }
                strongSelf.customerDisplay.clearScreen()
                strongSelf.enableTableCell(enable: false, row: index.row, section: index.section)
                strongSelf.showMessageBox(message: "OPEN SUCCESS", title: "INFO")
                strongSelf.addHistory(text: "OPEN SUCCESS")
            }
        }
    }
    
    func closeCustomerDisplay(index:IndexPath){
        DispatchQueue.global(qos: .background).async { [weak self] in
            guard let strongSelf = self else { return }
            strongSelf.customerDisplay.closeService(0)
            strongSelf.addHistory(text: "CLOSED")
            strongSelf.enableTableCell(enable: true, row: index.row-1, section: index.section)
        }
    }

    func textDisplay(){
        if(!self.customerDisplay.isOpen()){ return }
        DispatchQueue.global(qos: .background).async { [weak self] in
        guard let strongSelf = self else { return }
            strongSelf.customerDisplay.displayString("1st Line: HELLO", codePage: 16, internationalCharacterSet: 0, line: 1)
            strongSelf.customerDisplay.displayString("2nd Line: HELLO", codePage: 16, internationalCharacterSet: 0, line: 2)
        }
    }

    func clearDisplay(){
        if(!self.customerDisplay.isOpen()){ return }
        DispatchQueue.global(qos: .background).async { [weak self] in
            guard let strongSelf = self else { return }
            strongSelf.customerDisplay.clearScreen()
        }
    }
    
    func storeAndDisplayImage(){
        if(!self.customerDisplay.isOpen()){ return }
        DispatchQueue.global(qos: .background).async { [weak self] in
            guard let strongSelf = self else { return }
            if strongSelf.customerDisplay.storeImageFile("bixolon.jpg", width: -1, imageNumber: 1) == MPOS_RESULT.RES_SUCCESS {
                strongSelf.customerDisplay.displayImage(1, xPos: 0, yPos: 0)
            }
        }
    }

}
