//
//  PrinterManager.swift
//  SIIMpaPrinterSample
//

import Foundation
import SIIMpaPrinterManager

class PrinterManager: NSObject {
    fileprivate static var _printer: SIIMpaPrinterManager = SIIMpaPrinterManager()
    fileprivate static var _resultString: String = "SUCCESS"
    fileprivate static var _gcd_printerManager: dispatch_queue_t = DispatchQueue(label: "com.sii-ps.PrinterManager")
    
    fileprivate static let RECEIPT_CONTENT: String =
    "--------------------------------\n" +
    "GRILLED CHICKEN BREAST   $ 18.50\n" +
    "SIRLOIN STEAK            $ 32.00\n" +
    "ROAST LAMB               $ 20.00\n" +
    "SALAD                    $ 10.00\n" +
    "COKE                     $  3.50\n" +
    "ICE CREAM                $  5.00\n" +
    "CHINESE NOODLE           $ 15.00\n" +
    "SUKIYAKI                 $ 30.00\n" +
    "SANDWICH                 $ 10.00\n" +
    "PIZZA                    $ 20.00\n" +
    "TEA                      $  3.50\n" +
    "COFFEE                   $  3.50\n" +
    "\n" +
    "--------------------------------\n" +
    "        SUBTOTAL        $ 174.50\n" +
    "        SALES TAX       $   8.73\n" +
    "        TOTAL           $ 183.23\n" +
    "\n" +
    "Thank you and see you again!\n"
    
    static func getResultString() -> String {
        return _resultString
    }
    
    static func getDispatchQueue() -> dispatch_queue_t {
        return _gcd_printerManager
    }
    
    static func startCallBack(status: StatusViewModel, sel: Selector) -> Bool {
        var openResult = false
        do {
            _resultString = "SUCCESS"
            try openResult = openPrinter()
            try _printer.startCallbackFunction(sel, target: status)
        } catch let error as NSError {
            _resultString = convertErrorCodeToString(error)
            if openResult {
                try! _printer.close()
            }
            return false
        }
        return true
    }
    
    static func stopCallBack() {
        do {
            _resultString = "SUCCESS"
            defer {
                try! _printer.close()
            }
            try _printer.stopCallbackFunction()
        } catch let error as NSError {
            _resultString = convertErrorCodeToString(error)
        }
    }
    
    static func getPrinterInformation(key: String) -> String? {
        var returnValue: String? = String()
        do {
            _resultString = "SUCCESS"
            var openResult = false
            try openResult = openPrinter()
            defer {
                if openResult {
                    try! _printer.close()
                }
            }
            
            switch key {
            case KEY_TYPE_NV_MEM_CAP:
                var value : UnsafeMutablePointer<Int>? = nil
                try _printer.getPrinterInformationNumber(.SII_MPM_GET_NV_MEM_CAP, printerInfoValue: &value)
                returnValue = String(format: "%d", value ?? 0)
            case KEY_TYPE_NV_MEM_REM_CAP:
                var value : UnsafeMutablePointer<Int>? = nil
                try _printer.getPrinterInformationNumber(.SII_MPM_GET_NV_MEM_REM_CAP, printerInfoValue: &value)
                returnValue = String(format: "%d", value ?? 0)
            case KEY_TYPE_NV_MEM_KEYCODE_LIST:
                var value: NSString? = NSString()
                try _printer.getPrinterInformationString(.SII_MPM_GET_NV_MEM_KEYCODE_LIST, printerInformationValue: &value)
                returnValue = value as String?
            case KEY_TYPE_REM_USER_MEM_CAP:
                var value : UnsafeMutablePointer<Int>? = nil
                try _printer.getPrinterInformationNumber(.SII_MPM_GET_REM_USER_MEM_CAP, printerInfoValue: &value)
                returnValue = String(format: "%d", value ?? 0)
            case KEY_TYPE_REM_USER_MEM_CAP_DEFRAG:
                var value : UnsafeMutablePointer<Int>? = nil
                try _printer.getPrinterInformationNumber(.SII_MPM_GET_REM_USER_MEM_CAP_DEFRAG, printerInfoValue: &value)
                returnValue = String(format: "%d", value ?? 0)
            case KEY_TYPE_FUNC_SET_RESP:
                var value: NSData? = NSData()
                try _printer.getPrinterInformation(.SII_MPM_GET_FUNC_SET_RESP, printerInformationValue: &value)
                returnValue = String(format: "%@", value ?? 0)
            case KEY_TYPE_PRN_ID_MODEL:
                var value : UnsafeMutablePointer<Int>? = nil
                try _printer.getPrinterInformationNumber(.SII_MPM_GET_PRN_ID_MODEL, printerInfoValue: &value)
                returnValue = String(format: "%d", value ?? 0)
            case KEY_TYPE_PRN_ID_TYPE:
                var value : UnsafeMutablePointer<Int>? = nil
                try _printer.getPrinterInformationNumber(.SII_MPM_GET_PRN_ID_TYPE, printerInfoValue: &value)
                returnValue = String(format: "%d", value ?? 0)
            case KEY_TYPE_PRN_ID_ROM_VER:
                var value : UnsafeMutablePointer<Int>? = nil
                try _printer.getPrinterInformationNumber(.SII_MPM_GET_PRN_ID_ROM_VER, printerInfoValue: &value)
                returnValue = String(format: "%d", value ?? 0)
            case KEY_TYPE_PRN_ID_FIRM_VER_MAIN:
                var value: NSString? = NSString()
                try _printer.getPrinterInformationString(.SII_MPM_GET_PRN_ID_FIRM_VER_MAIN, printerInformationValue: &value)
                returnValue = value as String?
            case KEY_TYPE_PRN_ID_MFR:
                var value: NSString? = NSString()
                try _printer.getPrinterInformationString(.SII_MPM_GET_PRN_ID_MFR, printerInformationValue: &value)
                returnValue = value as String?
            case KEY_TYPE_PRN_ID_MODEL_NAME:
                var value: NSString? = NSString()
                try _printer.getPrinterInformationString(.SII_MPM_GET_PRN_ID_MODEL_NAME, printerInformationValue: &value)
                returnValue = value as String?
            case KEY_TYPE_PRN_ID_FIRM_VER_BOOT:
                var value: NSString? = NSString()
                try _printer.getPrinterInformationString(.SII_MPM_GET_PRN_ID_FIRM_VER_BOOT, printerInformationValue: &value)
                returnValue = value as String?
            case KEY_TYPE_PRN_ID_FIRM_CHECKSUM_BOOT:
                var value : UnsafeMutablePointer<Int>? = nil
                try _printer.getPrinterInformationNumber(.SII_MPM_GET_PRN_ID_FIRM_CHECKSUM_BOOT, printerInfoValue: &value)
                returnValue = String(format: "%d", value ?? 0)
            case KEY_TYPE_PRN_ID_FIRM_CHECKSUM_MAIN:
                var value : UnsafeMutablePointer<Int>? = nil
                try _printer.getPrinterInformationNumber(.SII_MPM_GET_PRN_ID_FIRM_CHECKSUM_MAIN, printerInfoValue: &value)
                returnValue = String(format: "%d", value ?? 0)
            case KEY_TYPE_PRN_ID_FIRM_CHECKSUM:
                var value : UnsafeMutablePointer<Int>? = nil
                try _printer.getPrinterInformationNumber(.SII_MPM_GET_PRN_ID_FIRM_CHECKSUM, printerInfoValue: &value)
                returnValue = String(format: "%d", value ?? 0)
            case KEY_TYPE_MAINT_NUM_FEED_LINE:
                var value : UnsafeMutablePointer<Int>? = nil
                try _printer.getPrinterInformationNumber(.SII_MPM_GET_MAINT_NUM_FEED_LINE, printerInfoValue: &value)
                returnValue = String(format: "%d", value ?? 0)
            case KEY_TYPE_MAINT_NUM_HEAD_ACTIVE:
                var value : UnsafeMutablePointer<Int>? = nil
                try _printer.getPrinterInformationNumber(.SII_MPM_GET_MAINT_NUM_HEAD_ACTIVE, printerInfoValue: &value)
                returnValue = String(format: "%d", value ?? 0)
            case KEY_TYPE_MAINT_DRIVE_TIME:
                var value : UnsafeMutablePointer<Int>? = nil
                try _printer.getPrinterInformationNumber(.SII_MPM_GET_MAINT_DRIVE_TIME, printerInfoValue: &value)
                returnValue = String(format: "%d", value ?? 0)
            case KEY_TYPE_MAINT_NUM_FEED_LINE_INTEGRATION:
                var value : UnsafeMutablePointer<Int>? = nil
                try _printer.getPrinterInformationNumber(.SII_MPM_GET_MAINT_NUM_FEED_LINE_INTEGRATION, printerInfoValue: &value)
                returnValue = String(format: "%d", value ?? 0)
            case KEY_TYPE_MAINT_NUM_HEAD_ACTIVE_INTEGRATION:
                var value : UnsafeMutablePointer<Int>? = nil
                try _printer.getPrinterInformationNumber(.SII_MPM_GET_MAINT_NUM_HEAD_ACTIVE_INTEGRATION, printerInfoValue: &value)
                returnValue = String(format: "%d", value ?? 0)
            case KEY_TYPE_MAINT_DRIVE_TIME_INTEGRATION:
                var value : UnsafeMutablePointer<Int>? = nil
                try _printer.getPrinterInformationNumber(.SII_MPM_GET_MAINT_DRIVE_TIME_INTEGRATION, printerInfoValue: &value)
                returnValue = String(format: "%d", value ?? 0)
            case KEY_TYPE_HFONT_24_CHECKSUM:
                var value : UnsafeMutablePointer<Int>? = nil
                try _printer.getPrinterInformationNumber(.SII_MPM_GET_HFONT_24_CHECKSUM, printerInfoValue: &value)
                returnValue = String(format: "%d", value ?? 0)
            case KEY_TYPE_HFONT_24_ID:
                var value: NSString? = NSString()
                try _printer.getPrinterInformationString(.SII_MPM_GET_HFONT_24_ID, printerInformationValue: &value)
                returnValue = value as String?
            case KEY_TYPE_HFONT_24_INT_CHAR:
                var value: NSString? = NSString()
                try _printer.getPrinterInformationString(.SII_MPM_GET_HFONT_24_INT_CHAR, printerInformationValue: &value)
                returnValue = value as String?
            case KEY_TYPE_HFONT_16_CHECKSUM:
                var value : UnsafeMutablePointer<Int>? = nil
                try _printer.getPrinterInformationNumber(.SII_MPM_GET_HFONT_16_CHECKSUM, printerInfoValue: &value)
                returnValue = String(format: "%d", value ?? 0)
            case KEY_TYPE_HFONT_16_ID:
                var value: NSString? = NSString()
                try _printer.getPrinterInformationString(.SII_MPM_GET_HFONT_16_ID, printerInformationValue: &value)
                returnValue = value as String?
            case KEY_TYPE_HFONT_16_INT_CHAR:
                var value: NSString? = NSString()
                try _printer.getPrinterInformationString(.SII_MPM_GET_HFONT_16_INT_CHAR, printerInformationValue: &value)
                returnValue = value as String?
            case KEY_TYPE_FFONT_LANG:
                var value: NSString? = NSString()
                try _printer.getPrinterInformationString(.SII_MPM_GET_FFONT_LANG, printerInformationValue: &value)
                returnValue = value as String?
            case KEY_TYPE_FFONT_STANDARD:
                var value: NSString? = NSString()
                try _printer.getPrinterInformationString(.SII_MPM_GET_FFONT_STANDARD, printerInformationValue: &value)
                returnValue = value as String?
            case KEY_TYPE_FFONT_COMPANY:
                var value: NSString? = NSString()
                try _printer.getPrinterInformationString(.SII_MPM_GET_FFONT_COMPANY, printerInformationValue: &value)
                returnValue = value as String?
            case KEY_TYPE_FFONT_CHECKSUM:
                var value : UnsafeMutablePointer<Int>? = nil
                try _printer.getPrinterInformationNumber(.SII_MPM_GET_FFONT_CHECKSUM, printerInfoValue: &value)
                returnValue = String(format: "%d", value ?? 0)
            case KEY_TYPE_FFONT_DATA_SIZE:
                var value : UnsafeMutablePointer<Int>? = nil
                try _printer.getPrinterInformationNumber(.SII_MPM_GET_FFONT_DATA_SIZE, printerInfoValue: &value)
                returnValue = String(format: "%d", value ?? 0)
            case KEY_TYPE_FFONT_ROM_ID:
                var value : UnsafeMutablePointer<Int>? = nil
                try _printer.getPrinterInformationNumber(.SII_MPM_GET_FFONT_ROM_ID, printerInfoValue: &value)
                returnValue = String(format: "%d", value ?? 0)
            default:
                returnValue = ""
            }
        } catch let error as NSError {
            returnValue = convertErrorCodeToString(error)
        }
        return returnValue
    }
    
    static func printStandardModeReceipt() -> Bool {
        do {
            _resultString = "SUCCESS"
            var openResult = false
            try openResult = openPrinter()
            defer {
                if openResult {
                    try! _printer.close()
                }
            }
            
            try _printer.selectStandardMode()
            try _printer.setStandardModeArea(0, printAreaWidth: 832)
            try _printer.setStandardModeAlignment(.SII_MPM_ALIGN_CENTER)
            
            //set line spacing and character spacing
            try _printer.setLineSpacing(34)
            try _printer.setCharacterRightSpace(0)
            
            //print logo
            let logoPath = Bundle.main.path(forResource: "ReceiptLogo", ofType: "jpg")
            try _printer.sendDataFile(logoPath, dithering: .SII_MPM_DITHERING_DISABLE)
            try _printer.feedLine(2)
            
            //print date
            try _printer.setCharacterFormatting(.SII_MPM_CHAR_TYPE_FONT_A, verticalScale: .SII_MPM_CHAR_SCALE_X1, horizontalScale: .SII_MPM_CHAR_SCALE_X1, underline: .SII_MPM_CHAR_UNDERLINE_NONE, bold: .SII_MPM_CHAR_BOLD_OFF, reverse: .SII_MPM_CHAR_REVERSE_OFF, rotate: .SII_MPM_ROTATE_NONE)
            let now = Date()
            let dateFormatter = DateFormatter()
            dateFormatter.dateFormat = "yyyy-MM-dd hh:mm"
            let time = dateFormatter.string(from: now)
            let receiptTime = String(format: "%@ %@\n", "No.123456789   ", time)
            try _printer.printText(receiptTime)
            
            //print receipt contents
            try _printer.printText(RECEIPT_CONTENT)
            try _printer.feedLine(2)
            
            //print barcode
            try _printer.print(.SII_MPM_TYPE_BARCODE_UPC_A, text: "12345678905", moduleWidth: .SII_MPM_MODULE_WIDTH_BARCODE_3, moduleHeight: 162, hri: .SII_MPM_HRI_BARCODE_BOTTOM_FONT_A, nwRatio: .SII_MPM_NWRATIO_BARCODE_1TO2)
            //print two dimension barcode
            try _printer.print2DCode(.SII_MPM_TYPE_2DCODE_PDF417, text: "ABC0123", mode: .SII_MPM_MODE_2DCODE_PDF417_STANDARD, moduleSize: .SII_MPM_MODULE_SIZE_2DCODE_3, moduleHeight: 10, column: 0, row: 0, errorCorrect: .SII_MPM_ERR_CORRECTION_2DCODE_PDF417_0)
            try _printer.feedCutPosition()
            
            return true
        } catch let error as NSError {
            _resultString = convertErrorCodeToString(error)
            return false
        }
    }
    
    static func printPageModeReceipt() -> Bool {
        do {
            _resultString = "SUCCESS"
            var openResult = false
            try openResult = openPrinter()
            defer {
                if openResult {
                    try! _printer.close()
                }
            }
            
            let RECEIPT_WIDTH = 576
            let RECEIPT_HEIGHT = 1400
            let FONT_WIDTH = 12
            let FONT_HEIGHT = 24
            let LOGO_WIDTH = 384
            let LOGO_HEIGHT = 48
            let LINE_SPACE = 34
            
            // draw outline
            try _printer.selectPageMode(0, startY: 0, width: RECEIPT_WIDTH, height: RECEIPT_HEIGHT, direction: .SII_MPM_DIRECTION_LEFT_TO_RIGHT)
            try _printer.printPageModeRectangle(0, startY: 0, width: RECEIPT_WIDTH, height: RECEIPT_HEIGHT, thickness: 2)
            
            // set line spacing and character spacing
            try _printer.setLineSpacing(LINE_SPACE)
            try _printer.setCharacterRightSpace(0)
            
            // draw logo
            var startX = Int(RECEIPT_WIDTH - LOGO_WIDTH) / 2
            var startY = 80
            let width = RECEIPT_WIDTH - startX
            var height = LOGO_HEIGHT
            
            try _printer.selectPageMode(startX, startY: startY, width: width, height: height, direction: .SII_MPM_DIRECTION_LEFT_TO_RIGHT)
            try _printer.setPageModeVerticalPosition(0)
            
            let logoPath = Bundle.main.path(forResource: "ReceiptLogo", ofType: "jpg")
            try _printer.sendDataFile(logoPath, dithering: .SII_MPM_DITHERING_DISABLE)
            
            // draw date
            let now = Date()
            let dateFormatter = DateFormatter()
            dateFormatter.dateFormat = "yyyy-MM-dd hh:mm"
            let time = dateFormatter.string(from: now)
            let receiptTime = String(format: "%@ %@\n", "No.123456789   ", time)
            
            startX = Int(RECEIPT_WIDTH - ((FONT_WIDTH + 0 ) * receiptTime.utf16.count)) / 2
            startY = startY + height + 80
            height = FONT_HEIGHT
            try _printer.selectPageMode(startX, startY: startY, width: width, height: height, direction: .SII_MPM_DIRECTION_LEFT_TO_RIGHT)
            try _printer.setPageModeVerticalPosition(height)
            try _printer.setCharacterFormatting(.SII_MPM_CHAR_TYPE_FONT_A, verticalScale: .SII_MPM_CHAR_SCALE_X1, horizontalScale: .SII_MPM_CHAR_SCALE_X1, underline: .SII_MPM_CHAR_UNDERLINE_NONE, bold: .SII_MPM_CHAR_BOLD_OFF, reverse: .SII_MPM_CHAR_REVERSE_OFF, rotate: .SII_MPM_ROTATE_NONE)
            
            try _printer.printText(receiptTime)
            
            // draw receipt contents
            let dummy = "--------------------------------\n"
            startX = Int(RECEIPT_WIDTH - ((FONT_WIDTH + 0) * dummy.utf16.count)) / 2
            startY = startY + height + 40
            height = LINE_SPACE * 21
            try _printer.selectPageMode(startX, startY: startY, width: width, height: height, direction: .SII_MPM_DIRECTION_LEFT_TO_RIGHT)
            try _printer.setPageModeVerticalPosition(FONT_HEIGHT)
            try _printer.printText(RECEIPT_CONTENT)
            
            // draw barcode
            startX = 100
            startY = startY + height + 40
            height = 200
            try _printer.selectPageMode(startX, startY: startY, width: width, height: height, direction: .SII_MPM_DIRECTION_LEFT_TO_RIGHT)
            try _printer.setPageModeVerticalPosition(162)
            try _printer.print(.SII_MPM_TYPE_BARCODE_UPC_A, text: "12345678905", moduleWidth: .SII_MPM_MODULE_WIDTH_BARCODE_3, moduleHeight: 162, hri: .SII_MPM_HRI_BARCODE_BOTTOM_FONT_A, nwRatio: .SII_MPM_NWRATIO_BARCODE_1TO2)
            
            // draw two dimension barcode
            startX = 150
            startY = startY + height + 40
            height = 100
            try _printer.selectPageMode(startX, startY: startY, width: width, height: height, direction: .SII_MPM_DIRECTION_LEFT_TO_RIGHT)
            try _printer.print2DCode(.SII_MPM_TYPE_2DCODE_PDF417, text: "ABC0123", mode: .SII_MPM_MODE_2DCODE_PDF417_STANDARD, moduleSize: .SII_MPM_MODULE_SIZE_2DCODE_3, moduleHeight: 10, column: 0, row: 0, errorCorrect: .SII_MPM_ERR_CORRECTION_2DCODE_PDF417_0)
            
            // output to printer
            try _printer.printPageModeData()
            
            //exit pagemode
            try _printer.selectStandardMode()
            try _printer.feedCutPosition()
            
            return true
        } catch let error as NSError {
            _resultString = convertErrorCodeToString(error)
            return false
        }
    }
    
    static func printText(text: String, font: CharacterType, scale: CharacterScale, underline: Underline, bold: Bold, reverse: Reverse, rotate: Rotate) -> Bool {
        do {
            _resultString = "SUCCESS"
            var openResult = false
            try openResult = openPrinter()
            defer {
                if openResult {
                    try! _printer.close()
                }
            }
            
            try _printer.setStandardModeAlignment(.SII_MPM_ALIGN_LEFT)
            try _printer.setCharacterFormatting(font, verticalScale: scale, horizontalScale: scale, underline: underline, bold: bold, reverse: reverse, rotate: rotate)
            try _printer.printText(text)
            try _printer.feedDotLine(0)
            try _printer.feedCutPosition()
            return true
        } catch let error as NSError {
            _resultString = convertErrorCodeToString(error)
            return false
        }
    }
    
    static func sendDataFile(filePath: String, dithering: Dithering) -> Bool {
        do {
            _resultString = "SUCCESS"
            var openResult = false
            try openResult = openPrinter()
            defer {
                if openResult {
                    try! _printer.close()
                }
            }
            try _printer.setStandardModeAlignment(.SII_MPM_ALIGN_LEFT)
            try _printer.sendDataFile(filePath, dithering: dithering)
            try _printer.feedCutPosition()
            return true
        } catch let error as NSError {
            _resultString = convertErrorCodeToString(error)
            return false
        }
    }

    static func printPDF(filePath: String, startIndex: Int, endIndex: Int, rotate: Rotate, width: Int, bottomMargin: Int, dithering: Dithering) -> Bool {
        do {
            _resultString = "SUCCESS"
            var openResult = false
            try openResult = openPrinter()
            defer {
                if openResult {
                    try! _printer.close()
                }
            }
            try _printer.setStandardModeAlignment(.SII_MPM_ALIGN_LEFT)
            try _printer.printPDF(filePath, start: startIndex, end: endIndex, rotate: rotate, width: width, bottomMargin: bottomMargin, dithering: dithering)
            return true
        } catch let error as NSError {
            _resultString = convertErrorCodeToString(error)
            return false
        }
    }

    static func printBarcode(type: TypeBarcode, text: String, width: ModuleWidthBarcode, height: Int, hri: HriPositionBarcode, nwRatio: NwRatioBarcode) -> Bool {
        do {
            _resultString = "SUCCESS"
            var openResult = false
            try openResult = openPrinter()
            defer {
                if openResult {
                    try! _printer.close()
                }
            }
            let data: Data = text.data(using: .utf8)!
            try _printer.setStandardModeAlignment(.SII_MPM_ALIGN_LEFT)
            try _printer.print(type, binary: data, moduleWidth: width, moduleHeight: height, hri: hri, nwRatio: nwRatio)
            try _printer.feedCutPosition()
            return true
        } catch let error as NSError {
            _resultString = convertErrorCodeToString(error)
            return false
        }
    }
    
    static func print2DCode(type: Type2DCode, text: String, mode: Mode2Dcode, moduleSize: ModuleSize2Dcode, moduleHeight: Int, column: Int, row: Int, errorCorrect: ErrorCorrect2Dcode) -> Bool {
        do {
            _resultString = "SUCCESS"
            var openResult = false
            try openResult = openPrinter()
            defer {
                if openResult {
                    try! _printer.close()
                }
            }
            let data: Data = text.data(using: .utf8)!
            try _printer.setStandardModeAlignment(.SII_MPM_ALIGN_LEFT)
            try _printer.print2DCode(type, binary: data, mode: mode, moduleSize: moduleSize, moduleHeight: moduleHeight, column: column, row: row, errorCorrect: errorCorrect)
            try _printer.feedCutPosition()
            return true
        } catch let error as NSError {
            _resultString = convertErrorCodeToString(error)
            return false
        }
    }
    
    static func getVersion() -> String {
        return _printer.getVersion()
    }
    
    static func getWriteTimeout() -> String {
        let value = _printer.getWriteTimeout()
        return String(format: "%ld", value)
    }
    
    static func getResponseTimeout() -> String {
        let value = _printer.getResponseTimeout()
        return String(format: "%ld", value)
    }
    
    static func getCodePage() -> String {
        let value = _printer.getCharacterSet()
        let characterSet = CharacterSet(rawValue: value)!
        switch characterSet {
        case .SII_MPM_CODEPAGE_437:
            return SETTINGS_CODEPAGE_437
        case .SII_MPM_CODEPAGE_KATAKANA:
            return SETTINGS_CODEPAGE_KATAKANA
        case .SII_MPM_CODEPAGE_850:
            return SETTINGS_CODEPAGE_850
        case .SII_MPM_CODEPAGE_860:
            return SETTINGS_CODEPAGE_860
        case .SII_MPM_CODEPAGE_863:
            return SETTINGS_CODEPAGE_863
        case .SII_MPM_CODEPAGE_865:
            return SETTINGS_CODEPAGE_865
        case .SII_MPM_CODEPAGE_857:
            return SETTINGS_CODEPAGE_857
        case .SII_MPM_CODEPAGE_737:
            return SETTINGS_CODEPAGE_737
        case .SII_MPM_CODEPAGE_1252:
            return SETTINGS_CODEPAGE_1252
        case .SII_MPM_CODEPAGE_866:
            return SETTINGS_CODEPAGE_866
        case .SII_MPM_CODEPAGE_852:
            return SETTINGS_CODEPAGE_852
        case .SII_MPM_CODEPAGE_858:
            return SETTINGS_CODEPAGE_858
        case .SII_MPM_CODEPAGE_855:
            return SETTINGS_CODEPAGE_855
        case .SII_MPM_CODEPAGE_864:
            return SETTINGS_CODEPAGE_864
        case .SII_MPM_CODEPAGE_1250:
            return SETTINGS_CODEPAGE_1250
        case .SII_MPM_CODEPAGE_1251:
            return SETTINGS_CODEPAGE_1251
        case .SII_MPM_CODEPAGE_1253:
            return SETTINGS_CODEPAGE_1253
        case .SII_MPM_CODEPAGE_1254:
            return SETTINGS_CODEPAGE_1254
        @unknown default:
            return "Unknown"
        }
    }
    
    static func getInternationalCharacter() -> String {
        let value = _printer.getInternationalCharacterSet()
        let internationalSet = InternationalCharacterSet(rawValue: value)!
        switch internationalSet {
        case .SII_MPM_INT_CHAR_SET_USA:
            return SETTINGS_INTERNATIONAL_CHARACTER_USA
        case .SII_MPM_INT_CHAR_SET_FRANCE:
            return SETTINGS_INTERNATIONAL_CHARACTER_FRANCE
        case .SII_MPM_INT_CHAR_SET_GERMANY:
            return SETTINGS_INTERNATIONAL_CHARACTER_GERMANY
        case .SII_MPM_INT_CHAR_SET_UNITED_KINGDOM:
            return SETTINGS_INTERNATIONAL_CHARACTER_UNITED_KINGDOM
        case .SII_MPM_INT_CHAR_SET_DENMARK_1:
            return SETTINGS_INTERNATIONAL_CHARACTER_DENMARK_1
        case .SII_MPM_INT_CHAR_SET_SWEDEN:
            return SETTINGS_INTERNATIONAL_CHARACTER_SWEDEN
        case .SII_MPM_INT_CHAR_SET_ITALY:
            return SETTINGS_INTERNATIONAL_CHARACTER_ITALY
        case .SII_MPM_INT_CHAR_SET_SPAIN_1:
            return SETTINGS_INTERNATIONAL_CHARACTER_SPAIN_1
        case .SII_MPM_INT_CHAR_SET_JAPAN:
            return SETTINGS_INTERNATIONAL_CHARACTER_JAPAN
        case .SII_MPM_INT_CHAR_SET_NORWAY:
            return SETTINGS_INTERNATIONAL_CHARACTER_NORWAY
        case .SII_MPM_INT_CHAR_SET_DENMARK_2:
            return SETTINGS_INTERNATIONAL_CHARACTER_DENMARK_2
        case .SII_MPM_INT_CHAR_SET_SPAIN_2:
            return SETTINGS_INTERNATIONAL_CHARACTER_SPAIN_2
        case .SII_MPM_INT_CHAR_SET_LATIN_AMERICA:
            return SETTINGS_INTERNATIONAL_CHARACTER_LATIN_AMERICA
        case .SII_MPM_INT_CHAR_SET_ARABIA:
            return SETTINGS_INTERNATIONAL_CHARACTER_ARABIA
        @unknown default:
            return "Unknown"
        }
    }
    
    static func setWriteTimeout(value: String) {
        _printer.setWriteTimeout(Int(value)!)
    }
    
    static func setResponseTimeout(value: String) {
        _printer.setResponseTimeout(Int(value)!)
    }
    
    static func setCodePage(value: String) {
        do {
            _resultString = "SUCCESS"
            switch value {
            case SETTINGS_CODEPAGE_437:
                try _printer.select(.SII_MPM_CODEPAGE_437)
            case SETTINGS_CODEPAGE_KATAKANA:
                try _printer.select(.SII_MPM_CODEPAGE_KATAKANA)
            case SETTINGS_CODEPAGE_850:
                try _printer.select(.SII_MPM_CODEPAGE_850)
            case SETTINGS_CODEPAGE_860:
                try _printer.select(.SII_MPM_CODEPAGE_860)
            case SETTINGS_CODEPAGE_863:
                try _printer.select(.SII_MPM_CODEPAGE_863)
            case SETTINGS_CODEPAGE_865:
                try _printer.select(.SII_MPM_CODEPAGE_865)
            case SETTINGS_CODEPAGE_857:
                try _printer.select(.SII_MPM_CODEPAGE_857)
            case SETTINGS_CODEPAGE_737:
                try _printer.select(.SII_MPM_CODEPAGE_737)
            case SETTINGS_CODEPAGE_1252:
                try _printer.select(.SII_MPM_CODEPAGE_1252)
            case SETTINGS_CODEPAGE_866:
                try _printer.select(.SII_MPM_CODEPAGE_866)
            case SETTINGS_CODEPAGE_852:
                try _printer.select(.SII_MPM_CODEPAGE_852)
            case SETTINGS_CODEPAGE_858:
                try _printer.select(.SII_MPM_CODEPAGE_858)
            case SETTINGS_CODEPAGE_855:
                try _printer.select(.SII_MPM_CODEPAGE_855)
            case SETTINGS_CODEPAGE_864:
                try _printer.select(.SII_MPM_CODEPAGE_864)
            case SETTINGS_CODEPAGE_1250:
                try _printer.select(.SII_MPM_CODEPAGE_1250)
            case SETTINGS_CODEPAGE_1251:
                try _printer.select(.SII_MPM_CODEPAGE_1251)
            case SETTINGS_CODEPAGE_1253:
                try _printer.select(.SII_MPM_CODEPAGE_1253)
            case SETTINGS_CODEPAGE_1254:
                try _printer.select(.SII_MPM_CODEPAGE_1254)
            default:
                return
            }
        } catch let error as NSError {
            _resultString = convertErrorCodeToString(error)
        }
    }
    
    static func setInternationalCharacter(value: String) {
        do {
            _resultString = "SUCCESS"
            switch value {
            case SETTINGS_INTERNATIONAL_CHARACTER_USA:
                try _printer.select(.SII_MPM_INT_CHAR_SET_USA)
            case SETTINGS_INTERNATIONAL_CHARACTER_FRANCE:
                try _printer.select(.SII_MPM_INT_CHAR_SET_FRANCE)
            case SETTINGS_INTERNATIONAL_CHARACTER_GERMANY:
                try _printer.select(.SII_MPM_INT_CHAR_SET_GERMANY)
            case SETTINGS_INTERNATIONAL_CHARACTER_UNITED_KINGDOM:
                try _printer.select(.SII_MPM_INT_CHAR_SET_UNITED_KINGDOM)
            case SETTINGS_INTERNATIONAL_CHARACTER_DENMARK_1:
                try _printer.select(.SII_MPM_INT_CHAR_SET_DENMARK_1)
            case SETTINGS_INTERNATIONAL_CHARACTER_SWEDEN:
                try _printer.select(.SII_MPM_INT_CHAR_SET_SWEDEN)
            case SETTINGS_INTERNATIONAL_CHARACTER_ITALY:
                try _printer.select(.SII_MPM_INT_CHAR_SET_ITALY)
            case SETTINGS_INTERNATIONAL_CHARACTER_SPAIN_1:
                try _printer.select(.SII_MPM_INT_CHAR_SET_SPAIN_1)
            case SETTINGS_INTERNATIONAL_CHARACTER_JAPAN:
                try _printer.select(.SII_MPM_INT_CHAR_SET_JAPAN)
            case SETTINGS_INTERNATIONAL_CHARACTER_NORWAY:
                try _printer.select(.SII_MPM_INT_CHAR_SET_NORWAY)
            case SETTINGS_INTERNATIONAL_CHARACTER_DENMARK_2:
                try _printer.select(.SII_MPM_INT_CHAR_SET_DENMARK_2)
            case SETTINGS_INTERNATIONAL_CHARACTER_SPAIN_2:
                try _printer.select(.SII_MPM_INT_CHAR_SET_SPAIN_2)
            case SETTINGS_INTERNATIONAL_CHARACTER_LATIN_AMERICA:
                try _printer.select(.SII_MPM_INT_CHAR_SET_LATIN_AMERICA)
            case SETTINGS_INTERNATIONAL_CHARACTER_ARABIA:
                try _printer.select(.SII_MPM_INT_CHAR_SET_ARABIA)
            default:
                return
            }
        } catch let error as NSError {
            _resultString = convertErrorCodeToString(error)
        }
    }
    
    static func setLogFileSize(value: String) {
        do {
            _resultString = "SUCCESS"
            switch value {
            case SETTINGS_LOG_FILE_SIZE_1M:
                try _printer.setLog(0, logFileSize:.SII_MPM_LOG_FILE_SIZE_1MB)
            case SETTINGS_LOG_FILE_SIZE_5M:
                try _printer.setLog(0, logFileSize:.SII_MPM_LOG_FILE_SIZE_5MB)
            case SETTINGS_LOG_FILE_SIZE_10M:
                try _printer.setLog(0, logFileSize:.SII_MPM_LOG_FILE_SIZE_10MB)
            case SETTINGS_LOG_FILE_SIZE_50M:
                try _printer.setLog(0, logFileSize:.SII_MPM_LOG_FILE_SIZE_50MB)
            default:
                return
            }
        } catch let error as NSError {
            _resultString = convertErrorCodeToString(error)
        }
    }
    
    static func isMPA40Printer(name: String) -> Bool {
        if name.contains("MP-A40") {
            return true
        } else {
            return false
        }
    }
    
    static func openPrinter() throws -> Bool {
        do {
            let portType = getPortType()
            let printerModel = getPrinterModel()
            let address = PrinterViewModel().address
            let socketKeepingTime = Int(PrinterViewModel().socketKeepingTime)!
            try _printer.open(portType, printerModel: printerModel, address: address, socketKeepingTime: socketKeepingTime)
            return true
        } catch let error as NSError {
            throw(error)
        }
    }
    
    static func getPortType() -> PrinterInterface {
        let value = PrinterViewModel().portType
        switch value {
        case PORTTYPE_TCP_IP:
            return .SII_MPM_PRN_IF_TCP
        case PORTTYPE_BLUETOOTH:
            return .SII_MPM_PRN_IF_BT
        default:
            return PrinterInterface(rawValue: -1)!
        }
    }
    
    static func getPrinterModel() -> PrinterModel {
        let value = PrinterViewModel().modelName
        if value.contains("MP-A40") {
            return .SII_MPM_PRN_MODEL_MP_A40
        } else {
            return PrinterModel(rawValue: -1)!
        }
    }
}

class DiscoverManager: NSObject {
    static var _discover: SIIMpaPrinterDiscovery = SIIMpaPrinterDiscovery()
    static var _threadCompletion: Bool = false
    fileprivate static var _resultString: String = ""
    fileprivate static var _gcd_discoverManager: dispatch_queue_t = DispatchQueue(label: "com.sii-ps.DiscoverManager")
    
    static func getDispatchQueue() -> dispatch_queue_t {
        return _gcd_discoverManager
    }
    
    static func startDiscoveryBluetoothPrinter() {
        do {
            _resultString = "SUCCESS"
            try _discover.startPrinter(nil, target: nil, prnIf: .SII_MPM_PRN_IF_BT, retry: 1, timeout: 3)
        } catch let error as NSError {
            _resultString = convertErrorCodeToString(error)
        }
    }
    
    static func startDiscoveryTcpPrinter() {
        do {
            _resultString = "SUCCESS"
            _threadCompletion = false
            let target: DiscoverManager = DiscoverManager()
            try _discover.startPrinter(#selector(onDiscoveryFinished(event:)), target: target, prnIf: .SII_MPM_PRN_IF_TCP, retry: 1, timeout: 3)
        } catch let error as NSError {
            _resultString = convertErrorCodeToString(error)
        }
    }
    
    static func cancelDiscoveryTcpPrinter() {
        do {
            _resultString = "SUCCESS"
            try _discover.cancelPrinter()
        } catch let error as NSError {
            _resultString = convertErrorCodeToString(error)
        }
    }
    
    static func getFoundPrinter() -> [SIIMpaDiscoveredPrinter] {
        var returnList: [SIIMpaDiscoveredPrinter] = []
        do {
            var foundPrinterList: NSMutableArray? = NSMutableArray()
            _resultString = "SUCCESS"
            try _discover.getFoundPrinter(&foundPrinterList)
            if foundPrinterList != nil && foundPrinterList!.count > 0 {
                for i in 0..<foundPrinterList!.count {
                    let obj = foundPrinterList![i]
                    let foundPrinter = obj as! SIIMpaDiscoveredPrinter
                    if isMPA40Printer(name: foundPrinter.printerModel) {
                        returnList.append(foundPrinter)
                    }
                }
            }
        } catch let error as NSError {
            _resultString = convertErrorCodeToString(error)
        }
        return returnList
    }
    
    static func discoverFinished() -> Bool {
        return _threadCompletion
    }
    
    @objc func onDiscoveryFinished(event: NSNumber) {
        DiscoverManager._threadCompletion = true
    }
    
    static func isMPA40Printer(name: String) -> Bool {
        if name.contains("MP-A40") {
            return true
        } else {
            return false
        }
    }
}

func convertErrorCodeToString(_ error:NSError) -> String {
    let errorCode: ErrorCode = ErrorCode(rawValue: error.code)!
    var errorCodeText = ""
    switch errorCode {
    case .SII_MPM_SUCCESS:
        errorCodeText = "SUCCESS"
        break
    case .SII_MPM_ERR_PARAM:
        errorCodeText = "ERR_PARAM"
        break
    case .SII_MPM_ERR_OPENED:
        errorCodeText = "ERR_OPENED"
        break
    case .SII_MPM_ERR_TIMEOUT:
        errorCodeText = "ERR_TIMEOUT"
        break
    case .SII_MPM_ERR_NOT_OPENED:
        errorCodeText = "ERR_NOT_OPENED"
        break
    case .SII_MPM_ERR_OFFLINE:
        errorCodeText = "ERR_OFFLINE"
        break
    case .SII_MPM_ERR_CLOSE_FAIL:
        errorCodeText = "ERR_CLOSE_FAIL"
        break
    case .SII_MPM_ERR_NOT_MONITORING:
        errorCodeText = "ERR_NOT_MONITORING"
        break
    case .SII_MPM_ERR_INIT_FAILED:
        errorCodeText = "ERR_INIT_FAILED"
        break
    case .SII_MPM_ERR_DATA_SIZE_ZERO:
        errorCodeText = "ERR_DATA_SIZE_ZERO"
        break
    case .SII_MPM_ERR_OVER_MAX_DATA_SIZE:
        errorCodeText = "ERR_OVER_MAX_DATA_SIZE"
        break
    case .SII_MPM_ERR_INVALID_DATA:
        errorCodeText = "ERR_INVALID_DATA"
        break
    case .SII_MPM_ERR_INVALID_STATE:
        errorCodeText = "ERR_INVALID_STATE"
        break
    case .SII_MPM_ERR_ACCESS:
        errorCodeText = "ERR_ACCESS"
        break
    case .SII_MPM_ERR_CANCELED:
        errorCodeText = "ERR_CANCELED"
        break
    case .SII_MPM_ERR_WRITE_FAULT:
        errorCodeText = "ERR_WRITE_FAULT"
        break
    case .SII_MPM_ERR_FILE_INVALID:
        errorCodeText = "ERR_FILE_INVALID"
        break
    case .SII_MPM_ERR_ENCODE_FAILED:
        errorCodeText = "ERR_ENCODE_FAILED"
        break
    case .SII_MPM_ERR_NOT_FOUND:
        errorCodeText = "ERR_NOT_FOUND"
        break
    case .SII_MPM_ERR_TRANSACTION_STOPPED:
        errorCodeText = "ERR_TRANSACTION_STOPPED"
        break
    case .SII_MPM_ERR_PRINTER_STATUS_ERROR:
        errorCodeText = "ERR_PRINTER_STATUS_ERROR"
        break
    @unknown default:
        errorCodeText = "unexpected error"
        break
    }
    
    return errorCodeText
}
