using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WinRT.BxlComponent.Plugin.BxlMpXamarinSDK.Abstractions;
using WinRT.BxlComponent.Plugin.BxlMpXamarinSDK;
using System.Threading;
using Windows.Foundation;
using Windows.Storage;
using Windows.Storage.Streams;
using System.IO;
using System.Collections.ObjectModel;
using System.Xml;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Core;
using Windows.Graphics.Imaging;
using Windows.ApplicationModel.Core;
using System.Net.Http;

namespace WinRT.BxlComponent
{
    internal partial class BxlReactNativeSDKHelper
    {
        public static string CodePage { get; private set; } = "WPC1252";
        private static SemaphoreSlim _printSemaphore = new SemaphoreSlim(1, 1);
        private static ObservableCollection<BxlDeviceInfoEntry> _deviceEntryCollection = new ObservableCollection<BxlDeviceInfoEntry>();
        private static readonly object _locker = new object();
        private static bool _intialized = false;
        public static BxlReactNativeSDKHelper MposUwpApiWrapper { get; private set; } = null;
        public static MPosControllerDevices MposDeviceObj { get; private set; } = null;
        public static MPosDeviceType MposDeviceType { get; private set; } = MPosDeviceType.MPOS_DEVICE_PRINTER;
        public static string XmlFileName { get; private set; } = "DeviceEntry.xml";
        public bool DeviceEnable { get; private set; } = false;
        public bool DeviceClaimed { get; private set; } = false;
        public static BxlReactNativeSDKHelper Instance
        {
            get
            {
                lock (_locker)
                {
                    if (!_intialized)
                    {
                        InitDevInfoCollection();
                        MposDeviceObj = new MPosDeviceFactoryImplementation().createDevice(MposDeviceType);
                        MposUwpApiWrapper = new BxlReactNativeSDKHelper();
                        _intialized = true;
                    }
                }

                return MposUwpApiWrapper;
            }
        }
        private BxlReactNativeSDKHelper() { }
        private static void InitDevInfoCollection()
        {
            if (!File.Exists(ApplicationData.Current.LocalFolder.Path + "\\" + XmlFileName))
            {
                MPosDebug.WriteLine("InitDevInfoCollection : xml file not found");
                return;
            }

            _deviceEntryCollection.Clear();

            try
            {
                using (XmlReader reader = XmlReader.Create(ApplicationData.Current.LocalFolder.Path + "\\" + XmlFileName))
                {
                    var xmlDataArray = new string[3];
                    reader.MoveToContent();

                    while (reader.Read())
                    {
                        if (!reader.IsStartElement())
                            continue;

                        switch (reader.Name.Trim())
                        {
                            case "deviceName": reader.Read(); xmlDataArray[0] = reader.Value.Trim(); break;
                            case "interfaceType": reader.Read(); xmlDataArray[1] = reader.Value.Trim(); break;
                            case "address":
                                reader.Read();
                                xmlDataArray[2] = reader.Value.Trim();
                                MPosDebug.WriteLine("InitDevInfoCollection : XML DATA = " + xmlDataArray[0] + " " + xmlDataArray[1] + " " + xmlDataArray[2]);
                                if (!(_deviceEntryCollection.Any(x => x.Name == xmlDataArray[0])))
                                    _deviceEntryCollection.Add(new BxlDeviceInfoEntry() { Name = xmlDataArray[0], InterfaceType = xmlDataArray[1], Address = xmlDataArray[2] });
                                break;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MPosDebug.WriteLine("InitDevInfoCollection : ex = " + ex);
            }

            MPosDebug.WriteLine("InitDevInfoCollection : Count = " + _deviceEntryCollection.Count);
        }
        public int Open(string deviceName)
        {
            MPosDebug.WriteLine("Open : deviceName = " + deviceName);
            if (_deviceEntryCollection.Count <= 0)
                InitDevInfoCollection();
            if (_deviceEntryCollection.Any(x => x.Name == deviceName.Trim()))
                return (int)MPosResult.MPOS_SUCCESS;
            return (int)MPosResult.MPOS_FAIL;
        }
        public async Task<int> Claim(string deviceName, uint timeout = 3000)
        {
            var result = (int)MPosResult.MPOS_FAIL_NOT_CONNECT;

            MPosDebug.WriteLine("Claim : deviceName = " + deviceName + ", timeout =" + timeout);

            if (!(_deviceEntryCollection.Any(x => x.Name == deviceName)))
            {
                MPosDebug.WriteLine("Claim : MPOS_FAIL_NO_DEVICE_FOUND");
                return (int)MPosResult.MPOS_FAIL_NO_DEVICE_FOUND;
            }

            var devEntry = _deviceEntryCollection.Where(x => x.Name == deviceName).Single();

            MPosDebug.WriteLine("Claim : Address = " + devEntry.Address.Trim());
            MPosDebug.WriteLine("Claim : InterfaceType = " + devEntry.InterfaceType.Trim());

            var interfaceType = (int)MPosInterfaceType.MPOS_INTERFACE_BLUETOOTH;

            switch (devEntry.InterfaceType.Trim())
            {
                case "0": interfaceType = (int)MPosInterfaceType.MPOS_INTERFACE_BLUETOOTH; break;   // Bluetooth
                case "1": interfaceType = (int)MPosInterfaceType.MPOS_INTERFACE_ETHERNET; break;   // Ethernet
                case "3": interfaceType = (int)MPosInterfaceType.MPOS_INTERFACE_WIFI; break;   // Wifi
                //case "2":   // USB
                //case "4":   // Wi-Fi Direct
                //case "5":   // BLE (Bluetooth Low Energy)
                default:
                    MPosDebug.WriteLine("Claim : MPOS_FAIL_INVALID_INTERFACE");
                    return (int)MPosResult.MPOS_FAIL_INVALID_INTERFACE;
            }

            try{
                await _printSemaphore.WaitAsync();
                MposDeviceObj.selectInterface(interfaceType, devEntry.Address.Trim());
                MposDeviceObj.selectCommandMode((int)MPosCommandMode.MPOS_COMMAND_MODE_DIRECT);
                result = await MposDeviceObj.openService(timeout);
                if (result == (int)MPosResult.MPOS_SUCCESS) {
                    await ((MPosControllerPrinter)MposDeviceObj).getCodePageName((name) => SetTextEncoding(name));
                    DeviceClaimed = true;
                }
            }
            finally{
                _printSemaphore.Release();
            }

            return result;
        }
        public async Task<int> Release()
        {
            var result = (int)MPosResult.MPOS_FAIL_NOT_CONNECT;
            if (MposDeviceObj != null)
            {
                result = await MposDeviceObj.closeService();
                DeviceEnable = false;
                DeviceClaimed = false;
                _deviceEntryCollection.Clear();
            }
            return result;
        }
        public async Task<int> Close()
        {
            return await Release();
        }
        public async Task<int> AddEntry(string deviceName, string interfaceType, string address)
        {
            // Already the device name exist in the list, remove it and then add a new item.
            if (_deviceEntryCollection.Any(x => x.Name == deviceName))
                _deviceEntryCollection.Remove(_deviceEntryCollection.Where(x => x.Name == deviceName).Single());
            _deviceEntryCollection.Add(new BxlDeviceInfoEntry() { Name = deviceName, InterfaceType = interfaceType, Address = address });

            try
            {
                MPosDebug.WriteLine("AddEntry : LocalFolder.Path = " + ApplicationData.Current.LocalFolder.Path);

                StorageFolder localFolder = ApplicationData.Current.LocalFolder;
                //StorageFile xmlFile = await localFolder.CreateFileAsync(_xmlFileName, CreationCollisionOption.OpenIfExists);
                StorageFile xmlFile = await localFolder.CreateFileAsync(XmlFileName, CreationCollisionOption.ReplaceExisting);

                using (IRandomAccessStream writeStream = await xmlFile.OpenAsync(FileAccessMode.ReadWrite))
                {
                    System.IO.Stream s = writeStream.AsStreamForWrite();
                    System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings() { Async = true, Indent = true };

                    MPosDebug.WriteLine("AddEntry : _deviceEntryCollection.Count = " + _deviceEntryCollection.Count);

                    using (System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(s, settings))
                    {
                        writer.WriteStartDocument();
                        writer.WriteStartElement("devices");
                        foreach (BxlDeviceInfoEntry entry in _deviceEntryCollection)
                        {
                            MPosDebug.WriteLine("AddEntry : DATA = " + entry.Name + " " + entry.InterfaceType + " " + entry.Address);
                            writer.WriteStartElement(entry.Name);
                            writer.WriteElementString("deviceName", entry.Name);
                            writer.WriteElementString("interfaceType", entry.InterfaceType);
                            writer.WriteElementString("address", entry.Address);
                            writer.WriteEndElement();
                        }
                        writer.WriteEndElement();
                        writer.WriteEndDocument();
                        writer.Flush();
                        await writer.FlushAsync();
                    }
                }
            }
            catch (Exception ex){
                MPosDebug.WriteLine("AddEntry : ex = " + ex.Message);
                return (int)MPosResult.MPOS_FAIL;
            }

            return (int)MPosResult.MPOS_SUCCESS;
        }
        public async Task<int> TransactionPrint(int mode)
        {
            var result = (int)MPosResult.MPOS_FAIL_NOT_CONNECT;
            if (!DeviceEnable){
                MPosDebug.WriteLine("TransactionPrint : MPOS_FAIL_DEVICE_DISABLE");
                return (int)cordovaResult.MPOS_FAIL_DEVICE_DISABLE;
            }

            if (MposDeviceObj != null){
                if (MposDeviceObj is MPosControllerPrinter){
                    if(mode == 11)
                        result = await ((MPosControllerPrinter)MposDeviceObj).setTransaction((int)MPosTransactionMode.MPOS_PRINTER_TRANSACTION_IN);
                    else
                        result = await ((MPosControllerPrinter)MposDeviceObj).setTransaction((int)MPosTransactionMode.MPOS_PRINTER_TRANSACTION_OUT);
                }
            }
            return result;
        }
    }
    internal partial class BxlReactNativeSDKHelper
    {
        public async Task<int> DirectIO(byte[] data)
        {
            var result = (int)MPosResult.MPOS_FAIL_NOT_CONNECT;
            if (!DeviceEnable){
                MPosDebug.WriteLine("directIO : MPOS_FAIL_DEVICE_DISABLE");
                return (int)cordovaResult.MPOS_FAIL_DEVICE_DISABLE;
            }

            if (MposDeviceObj != null)
            {
                if (MposDeviceObj is MPosControllerPrinter){
                    result = await ((MPosControllerPrinter)MposDeviceObj).directIO(data);
                }
            }

            return result;
        }
        public async Task<int> PrintNormal(string data)
        {
            var result = (int)MPosResult.MPOS_FAIL_NOT_CONNECT;

            if (!DeviceEnable)
            {
                MPosDebug.WriteLine("PrintNormal : MPOS_FAIL_DEVICE_DISABLE");
                return (int)cordovaResult.MPOS_FAIL_DEVICE_DISABLE;
            }

            if (MposDeviceObj != null)
            {
                
                if (MposDeviceObj is MPosControllerPrinter) {
                    result = await ((MPosControllerPrinter)MposDeviceObj).printText(data);
                }
            }

            return result;
        }
        public async Task<int> Print2dCode(string data, int symbology, int height, int width, int alignment, int hriPosition)
        {
            var result = (int)MPosResult.MPOS_FAIL_NOT_CONNECT;

            if (!DeviceEnable)
            {
                MPosDebug.WriteLine("Print2dCode : MPOS_FAIL_DEVICE_DISABLE");
                return (int)cordovaResult.MPOS_FAIL_DEVICE_DISABLE;
            }

            result = (int)MPosResult.MPOS_FAIL_INVALID_PARAMETER;

            MPosDebug.WriteLine("Print2dCode : symbology = " + symbology + " alignment = " + alignment + " hriPosition = " + hriPosition);

            alignment = (alignment * (-1) - 1);
            hriPosition = (hriPosition * (-1)) - 11;

            switch ((UposCodeType)symbology)
            {
                /*
                case UposCodeType.PTR_BCS_GS1DATABAR:        // GS1 Databar omnidirectional
                case UposCodeType.PTR_BCS_GS1DATABAR_E:      // GS1 Databar Stacked omnidirectional
                case UposCodeType.PTR_BCS_GS1DATABAR_S:      // GS1 Databar Expanded ??
                case UposCodeType.PTR_BCS_GS1DATABAR_E_S:    // GS1 Databar Expanded Stacked ??
                    if (MposDeviceObj is MPosControllerPrinter)
                        result = await ((MPosControllerPrinter)MposDeviceObj).printGS1Databar(data, (int)MPosGS1DatabarSymbol.MPOS_BARCODE_GS1_RSS14STACKED, alignment, 0x02);
                    break;
                case UposCodeType.PTR_BCS_MAXICODE:          // MAXI CODE
                    if (MposDeviceObj is MPosControllerPrinter)
                        result = await ((MPosControllerPrinter)MposDeviceObj).printMaxiCode(data, alignment, (int)MPosMaxiCodeMode.MPOS_LABEL_MAXICODE_MODE_4);
                    break;
                case UposCodeType.PTR_BCS_AZTEC:             // Aztec
                    if (MposDeviceObj is MPosControllerPrinter)
                        result = await ((MPosControllerPrinter)MposDeviceObj).printAztec(data, alignment, 0x02, (int)MPosAztecECCLevel.MPOS_AZTEC_ECC_LEVEL_M, (int)MPosAztecMode.MPOS_AZTEC_DATA);
                    break;
                case UposCodeType.PTR_BCS_DATAMATRIX:        // Data Matrix
                    if (MposDeviceObj is MPosControllerPrinter)
                        result = await ((MPosControllerPrinter)MposDeviceObj).printDataMatrix(data, alignment, 3);
                    break;
                */
                case UposCodeType.PTR_BCS_PDF417:            // PDF417
                case UposCodeType.PTR_BCS_UPDF417:           // Micro PDF417
                    if (MposDeviceObj is MPosControllerPrinter)
                        result = await ((MPosControllerPrinter)MposDeviceObj).printPDF417(data, (int)MPos2dCodeType.MPOS_BARCODE_PDF417, alignment, 0x00, 0x00, 0x03, 0x03, (int)MPosPDF417ECCLevel.MPOS_PDF417_ECC_LEVEL_0);
                    break;
                case UposCodeType.PTR_BCS_QRCODE:            // QR Code 
                case UposCodeType.PTR_BCS_UQRCODE:           // Micro QR Code
                    if (MposDeviceObj is MPosControllerPrinter)
                        result = await ((MPosControllerPrinter)MposDeviceObj).printQRCode(data, (int)MPos2dCodeType.MPOS_BARCODE_QRCODE_MODEL2, alignment, 0x03, (int)MPosQRCodeECCLevel.MPOS_QRCODE_ECC_LEVEL_H);
                    break;
                default:
                    MPosDebug.WriteLine("Print2dCode : NOT SUPPORTED CODE");
                    return (int)MPosResult.MPOS_FAIL_INVALID_PARAMETER;
            }

            return result;
        }
        public async Task<int> PrintBarCode(string data, int symbology, int height, int width, int alignment, int hriPosition)
        {
            var result = (int)MPosResult.MPOS_FAIL_NOT_CONNECT;

            if (!DeviceEnable)
            {
                MPosDebug.WriteLine("PrintBarCode : MPOS_FAIL_DEVICE_DISABLE");
                return (int)cordovaResult.MPOS_FAIL_DEVICE_DISABLE;
            }

            if (symbology >= (int)UposCodeType.PTR_BCS_GS1DATABAR)
            {
                return await Print2dCode(data, symbology, height, width, alignment, hriPosition);
            }

            result = (int)MPosResult.MPOS_FAIL_INVALID_PARAMETER;

            MPosDebug.WriteLine("PrintBarCode : symbology = " + symbology + " alignment = " + alignment + " hriPosition = " + hriPosition);

            alignment = (alignment * (-1) - 1);
            hriPosition = (hriPosition * (-1)) - 11;

            switch ((UposCodeType)symbology)
            {
                case UposCodeType.PTR_BCS_UPCA:              // UPC-A
                case UposCodeType.PTR_BCS_UPCE:              // UPC-E
                case UposCodeType.PTR_BCS_JAN8:              // JAN8
                //case UposCodeType.PTR_BCS_EAN8:            // EAN8
                case UposCodeType.PTR_BCS_JAN13:             // JAN13
                //case UposCodeType.PTR_BCS_EAN13:           // EAN13
                case UposCodeType.PTR_BCS_ITF:               // Interleaved 2 of 5
                case UposCodeType.PTR_BCS_CODABAR:           // Codabar
                case UposCodeType.PTR_BCS_CODE39:            // Code39
                case UposCodeType.PTR_BCS_CODE93:            // Code93
                case UposCodeType.PTR_BCS_CODE128:           // Code128
                    break;
                case UposCodeType.PTR_BCS_CODE128_PARSED:    // CODE128 with parsing
                    symbology = (int)UposCodeType.PTR_BCS_CODE128;
                    //int numericData = 0;
                    //if (int.TryParse(data, out numericData) && (data.Length % 2) == 0)
                    if ((data.Length % 2) == 0)
                        data = "{C" + data;
                    break;
                default:
                    MPosDebug.WriteLine("PrintBarCode : NOT SUPPORTED CODE");
                    return (int)MPosResult.MPOS_FAIL_INVALID_PARAMETER;
            }

            if (MposDeviceObj is MPosControllerPrinter)
                result = await ((MPosControllerPrinter)MposDeviceObj).print1DBarcode(data, symbology, width, height, alignment, hriPosition);

            return result;
        }
        public async Task<int> PrintBitmapWithURL(string uriString, int width, int alignment)
        {
            var result = (int)cordovaResult.MPOS_FAIL_DEVICE_DISABLE;

            if (!DeviceEnable)
            {
                MPosDebug.WriteLine("PrintBitmapWithURL : MPOS_FAIL_DEVICE_DISABLE");
                return (int)cordovaResult.MPOS_FAIL_DEVICE_DISABLE;
            }

            result = (int)cordovaResult.MPOS_FAIL_IMAGE_CREATION;

            MPosDebug.WriteLine("PrintBitmapWithURL : uriString = " + uriString);
            string filePath = await MPosImagePrintCommand.createImageFileFromURL(uriString);

            if (!String.IsNullOrEmpty(filePath))
            {
                if (MposDeviceObj is MPosControllerPrinter)
                {
                    if (width <= 0)
                        result = await ((MPosControllerPrinter)MposDeviceObj).printBitmapFile(filePath, (int)MPosImageWidth.MPOS_IMAGE_WIDTH_ASIS, (alignment * (-1)), 50, true, true);
                    else
                        result = await ((MPosControllerPrinter)MposDeviceObj).printBitmapFile(filePath, width, (alignment * (-1) - 1), 50, true, true);
                }
            }

            return result;
        }
        public async Task<int> PrintBitmapWithBase64(string base64String, int width, int alignment)
        {
            var result = (int)MPosResult.MPOS_SUCCESS;

            if (!DeviceEnable)
            {
                MPosDebug.WriteLine("PrintBitmapWithBase64 : MPOS_FAIL_DEVICE_DISABLE");
                return (int)cordovaResult.MPOS_FAIL_DEVICE_DISABLE;
            }

            try
            {
                var randomAccessStream = new InMemoryRandomAccessStream();

                using (var dataWriter = new DataWriter(randomAccessStream))
                {
                    // read stream
                    dataWriter.WriteBytes(Convert.FromBase64String(base64String));
                    await dataWriter.StoreAsync();

                    // decode image
                    var decoder = await BitmapDecoder.CreateAsync(randomAccessStream);
                    randomAccessStream.Seek(0);

                    // Get the SoftwareBitmap representation of the file
                    SoftwareBitmap softwareBitmap = await decoder.GetSoftwareBitmapAsync();
                    MPosDebug.WriteLine("printBitmapWithBase64 : softwareBitmap.PixelHeight = " + softwareBitmap.PixelHeight);
                    MPosDebug.WriteLine("printBitmapWithBase64 : softwareBitmap.PixelWidth = " + softwareBitmap.PixelWidth);

                    // Scale image to appropriate size 
                    BitmapTransform transform = null;

                    if (width <= 0)
                    {
                        transform = new BitmapTransform()
                        {
                            ScaledWidth = Convert.ToUInt32(softwareBitmap.PixelWidth),
                            ScaledHeight = Convert.ToUInt32(softwareBitmap.PixelHeight)
                        };
                    }
                    else
                    {
                        transform = new BitmapTransform()
                        {
                            ScaledWidth = (uint)width,
                            ScaledHeight = Convert.ToUInt32(softwareBitmap.PixelHeight)
                        };
                    }

                    PixelDataProvider pixelData = await decoder.GetPixelDataAsync(
                        BitmapPixelFormat.Bgra8,
                        BitmapAlphaMode.Straight,
                        transform,
                        ExifOrientationMode.IgnoreExifOrientation,
                        ColorManagementMode.DoNotColorManage
                    );

                    var imgData = MPosImagePrintCommand.getRleCmd(pixelData.DetachPixelData(),
                                                                    transform.ScaledWidth,
                                                                    transform.ScaledHeight,
                                                                    50,
                                                                    (alignment * (-1) - 1),
                                                                    true);

                    if (MposDeviceObj is MPosControllerPrinter)
                    {
                        result = await ((MPosControllerPrinter)MposDeviceObj).directIO(imgData);
                    }
                }

            }
            catch (Exception ex)
            {
                MPosDebug.WriteLine("printBitmapWithBase64 : ex = " + ex.ToString());
                result = (int)cordovaResult.MPOS_FAIL_IMAGE_DECODE;
            }

            return result;
        }
    }
    internal partial class BxlReactNativeSDKHelper
    {
        public IList<BxlDeviceInfoEntry> GetEntry()
        {
            var list = new List<BxlDeviceInfoEntry>();
            if (_deviceEntryCollection.Count > 0)
                foreach (var item in _deviceEntryCollection)
                    list.Add(item);
            MPosDebug.WriteLine("GetEntry : Count = " + list.Count);
            return list;
        }
        public bool GetDeviceEnable()
        {
            MPosDebug.WriteLine("GetDeviceEnable : DeviceEnable = " + DeviceEnable);
            return DeviceEnable;
        }
        public async Task<string> GetNetworkDevice(bool wireless, int searchTime /* second */)
        {
            MPosDebug.WriteLine("GetNetworkDevice : wireless = " + wireless + ", searchTime = " + searchTime);
            MposLookup mPosLookup = MPosLookupUtil.Current;

            var interfaceType = MPosInterfaceType.MPOS_INTERFACE_WIFI;
            if (!wireless){
                interfaceType = MPosInterfaceType.MPOS_INTERFACE_ETHERNET;
            }

            var result = await mPosLookup.refreshDeivcesList((int)interfaceType, searchTime /*second*/);
            if (result != (int)MPosResult.MPOS_SUCCESS)
                return "";

            var deviceList = mPosLookup.getDeviceList((int)interfaceType);

            MPosDebug.WriteLine("GetNetworkDevice : deviceList.Count = " + deviceList.Count);

            if (deviceList.Count == 0)
                return "";

            string jsonData = "";
            jsonData += "[";

            foreach (Plugin.BxlMpXamarinSDK.Abstractions.MposConnectionInformation networkDevInfo in deviceList)
            {
                MPosDebug.WriteLine("GetNetworkDevice : networkDevInfo.Name = " + networkDevInfo.Name);

                // InterfaceType
                jsonData += "{\"interfacetype\": ";
                //jsonData += "\"";
                if (networkDevInfo.IntefaceType == MPosInterfaceType.MPOS_INTERFACE_WIFI)
                    jsonData += "\"1\"";
                else if (networkDevInfo.IntefaceType == MPosInterfaceType.MPOS_INTERFACE_ETHERNET)
                    jsonData += "\"2\"";
                else if (networkDevInfo.IntefaceType == MPosInterfaceType.MPOS_INTERFACE_BLUETOOTH)
                    jsonData += "\"4\"";

                jsonData += ",";

                // IP Address
                jsonData += "\"address\": ";
                jsonData += "\"";
                jsonData += networkDevInfo.IpAddress + ":" + networkDevInfo.PortNumber;
                jsonData += "\",";

                // name
                jsonData += "\"devicename\": ";
                jsonData += "\"";
                jsonData += networkDevInfo.Name.TrimEnd();
                jsonData += "\"";
                jsonData += "},";
            }

            // Remove ',' at the last index.
            jsonData = jsonData.Substring(0, jsonData.Length - 1);
            jsonData += "]";
            MPosDebug.WriteLine("GetNetworkDevice : jsonData = " + jsonData);
            return jsonData;
        }
        public async Task<string> GetPairedDevice()
        {
            MposLookup mPosLookup = MPosLookupUtil.Current;
            //var interfaceType = MPosInterfaceType.MPOS_INTERFACE_BLUETOOTH;
            //var interfaceType = MPosInterfaceType.MPOS_INTERFACE_WIFI;
            var interfaceType = MPosInterfaceType.MPOS_INTERFACE_BLUETOOTH;

            var result = await mPosLookup.refreshDeivcesList((int)interfaceType, 1 /*second*/);

            if (result != (int)MPosResult.MPOS_SUCCESS)
                return "";

            var deviceList = mPosLookup.getDeviceList((int)interfaceType);

            MPosDebug.WriteLine("GetPairedDevice : deviceList.Count = " + deviceList.Count);

            if (deviceList.Count == 0)
                return "";

            string jsonData = "";
            jsonData += "[";

            foreach (MposConnectionInformation btInfo in deviceList)
            {
                jsonData += "{\"interfacetype\": 4";
                jsonData += ",";
                // Address
                jsonData += "\"address\": ";
                jsonData += "\"";
                jsonData += btInfo.Address;
                jsonData += "\",";
                // ModelName
                jsonData += "\"devicename\": ";
                jsonData += "\"";
                jsonData += btInfo.Name;
                jsonData += "\"},";
            }

            // Remove ',' at the last index.
            jsonData = jsonData.Substring(0, jsonData.Length - 1);
            jsonData += "]";
            MPosDebug.WriteLine("GetPairedDevice : jsonData = " + jsonData);
            return jsonData;
        }
        public async Task<int> GetPrinterStatus()
        {
            MPosDebug.WriteLine("GetPrinterStatus : START");
            int result = (int)MPosResult.MPOS_FAIL_NOT_CONNECT;
            if (!DeviceEnable){
                MPosDebug.WriteLine("GetPrinterStatus : MPOS_FAIL_DEVICE_DISABLE");
                return (int)cordovaResult.MPOS_FAIL_DEVICE_DISABLE;
            }

            if (MposDeviceObj != null)
            {
                if (MposDeviceObj is MPosControllerPrinter)
                {
                    int status = (int)await((MPosControllerPrinter)MposDeviceObj).checkPrinterStatus();
                    MPosDebug.WriteLine("GetPrinterStatus : status = 0x" + status.ToString("X2"));
                    if ((status & (int)MPosPrinterStatus.MPOS_STATUS_PRINTER_ERROR) != 0){
                        MPosDebug.WriteLine("GetPrinterStatus : MPOS_STATUS_PRINTER_ERROR");
                        status &= ~(int)MPosPrinterStatus.MPOS_STATUS_PRINTER_ERROR;
                        status |= 32;   // Offline (cutter jam, TPH overheat, disconnected with HOST)
                    }
                    if ((status & (int)MPosPrinterStatus.MPOS_STATUS_DRAWER_LOW) != 0){
                        MPosDebug.WriteLine("GetPrinterStatus : MPOS_STATUS_DRAWER_LOW");
                        status &= ~(int)MPosPrinterStatus.MPOS_STATUS_DRAWER_LOW;
                        // cash drawer 지원 시, 아래 주석 코드 제거
                        //status |= 16;   // cash drawer low
                    }
                    if ((status & (int)MPosPrinterStatus.MPOS_STATUS_DRAWER_HIGH) != 0){
                        MPosDebug.WriteLine("GetPrinterStatus : MPOS_STATUS_DRAWER_HIGH");
                        status &= ~(int)MPosPrinterStatus.MPOS_STATUS_DRAWER_HIGH;
                        // cash drawer 지원 시, 아래 주석 코드 제거
                        //status |= 8;    // cash drawer high
                    }
                    result = status;
                }
            }
            MPosDebug.WriteLine("GetPrinterStatus : result = " + result);
            MPosDebug.WriteLine("GetPrinterStatus : END");
            return result;
        }
        public async Task<int> CheckHealth(int level)
        {
            var result = (int)MPosResult.MPOS_FAIL_NOT_CONNECT;
            if (!DeviceEnable)
            {
                MPosDebug.WriteLine("CheckHealth : MPOS_FAIL_DEVICE_DISABLE");
                return (int)cordovaResult.MPOS_FAIL_DEVICE_DISABLE;
            }
            /*
                internal 
                    CheckHealth: Successful
                    CheckHealth: Failed

                external
                    CheckHealth: Cover Open (114/201)
                    CheckHealth: Successful
                    CheckHealth: Paper Empty (114/203)
                    CheckHealth: Nohardware (107/0)
            */

            if (MposDeviceObj != null)
            {
                if (MposDeviceObj is MPosControllerPrinter)
                {
                    switch (level)
                    {
                        case 1: // Internal
                            result = (int)MPosResult.MPOS_FAIL;
                            break;
                        case 2: // External
                            //string message = "==========================\r\nCheckHealth External\r\n==========================\r\n";
                            string message = "CheckHealth: ";
                            var status = await ((MPosControllerPrinter)MposDeviceObj).checkPrinterStatus();
                            if ((status & (uint)MPosPrinterStatus.MPOS_STATUS_PRINTER_COVEROPEN) != 0) message += "Cover Open";
                            else if ((status & (uint)MPosPrinterStatus.MPOS_STATUS_PRINTER_PAPEREMPTY) != 0) message += "Paper Empty";
                            else if ((status & (uint)MPosPrinterStatus.MPOS_STATUS_PRINTER_PAPER_NEAREND) != 0) message += "Near End";
                            else if ((status & (uint)MPosPrinterStatus.MPOS_STATUS_PRINTER_ERROR) != 0) message += "Error";
                            else
                            {
                                message += "Successful";
                            }
                            message += "\r\n";
                            result = await PrintNormal(message);
                            break;
                        case 3: // Interactive (not supported)
                            result = (int)MPosResult.MPOS_FAIL;
                            break;
                    }
                }
            }

            return result;
        }
    }
    internal partial class BxlReactNativeSDKHelper
    {
        public int SetCharacterSet(int characterSet)
        {
            MPosDebug.WriteLine("SetCharacterSet : START");
            MPosDebug.WriteLine("SetCharacterSet : characterSet = " + characterSet);
            var result = (int)MPosResult.MPOS_FAIL_NOT_CONNECT;
            if (!DeviceEnable){
                MPosDebug.WriteLine("SetCharacterSet : MPOS_FAIL_DEVICE_DISABLE");
                return (int)cordovaResult.MPOS_FAIL_DEVICE_DISABLE;
            }

            switch (characterSet)
            {
                case 437: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_CP437;             break;
                case 850: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_CP850;             break;
                case 860: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_CP860;             break;
                case 863: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_CP863;             break;
                case 865: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_CP865;             break;
                case 1252: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_WPC1252;          break;
                case 866: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_CP866;             break;
                case 852: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_CP852;             break;
                case 858: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_CP858;             break;
                case 862: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_CP862;             break;
                case 8411: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_THAI11;           break;
                case 8414: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_THAI14;           break;
                case 8416: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_THAI16;           break;
                case 8418: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_THAI18;           break;
                case 8442: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_THAI42;           break;
                case 1253: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_WPC1253;          break;
                case 1254: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_WPC1254;          break;
                case 1257: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_WPC1257;          break;
                case 1251: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_WPC1251;          break;
                case 7065: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_FARSI_II;         break;
                case 737: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_CP737;             break;
                case 775: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_CP775;             break;
                case 1255: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_WPC1255;          break;
                case 855: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_CP855;             break;
                case 857: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_CP857;             break;
                case 928: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_CP928;             break;
                case 1258: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_WPC1258;          break;
                case 1250: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_WPC1250;          break;
                case 3031: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_TCVN;             break;
                case 3032: characterSet = (int)MPosCodePage.MPOS_CODEPAGE_TCVN_CAPTIAL;     break;
                case 5601: characterSet = (int)MPosEastAsiaCodePage.MPOS_CODEPAGE_KSC5601;  break;
                case 2312: characterSet = (int)MPosEastAsiaCodePage.MPOS_CODEPAGE_GB2312;   break;
                case 6605: characterSet = (int)MPosEastAsiaCodePage.MPOS_CODEPAGE_BIG5;     break;
                case 8374: characterSet = (int)MPosEastAsiaCodePage.MPOS_CODEPAGE_SHIFTJIS; break;
                default:
                    break;
            }
            if (MposDeviceObj != null){
                if (MposDeviceObj is MPosControllerPrinter)
                    result = ((MPosControllerPrinter)MposDeviceObj).setTextEncoding((int)characterSet);
            }

            MPosDebug.WriteLine("SetCharacterSet : END");
            return result;
        }
        private void SetTextEncoding(string codepage)
        {
            MPosDebug.WriteLine("SetTextEncoding : START");
            MPosDebug.WriteLine("SetTextEncoding : codepage = " + codepage);

            int cp = (int)MPosCodePage.MPOS_CODEPAGE_WPC1252;

            if (codepage.IndexOf("PC437") >= 0)             cp = (int)MPosCodePage.MPOS_CODEPAGE_CP437;
            else if (codepage.IndexOf("PC850") >= 0)        cp = (int)MPosCodePage.MPOS_CODEPAGE_CP850;
            else if (codepage.IndexOf("PC852") >= 0)        cp = (int)MPosCodePage.MPOS_CODEPAGE_CP852;
            else if (codepage.IndexOf("PC855") >= 0)        cp = (int)MPosCodePage.MPOS_CODEPAGE_CP855;
            else if (codepage.IndexOf("PC857") >= 0)        cp = (int)MPosCodePage.MPOS_CODEPAGE_CP857;
            else if (codepage.IndexOf("PC858") >= 0)        cp = (int)MPosCodePage.MPOS_CODEPAGE_CP858;
            else if (codepage.IndexOf("PC860") >= 0)        cp = (int)MPosCodePage.MPOS_CODEPAGE_CP860;
            else if (codepage.IndexOf("PC862") >= 0)        cp = (int)MPosCodePage.MPOS_CODEPAGE_CP862;
            else if (codepage.IndexOf("PC863") >= 0)        cp = (int)MPosCodePage.MPOS_CODEPAGE_CP863;
            else if (codepage.IndexOf("PC864") >= 0)        cp = (int)MPosCodePage.MPOS_CODEPAGE_CP864;
            else if (codepage.IndexOf("PC865") >= 0)        cp = (int)MPosCodePage.MPOS_CODEPAGE_CP865;
            else if (codepage.IndexOf("PC866") >= 0)        cp = (int)MPosCodePage.MPOS_CODEPAGE_CP866;
            else if (codepage.IndexOf("PC737") >= 0)        cp = (int)MPosCodePage.MPOS_CODEPAGE_CP737;
            else if (codepage.IndexOf("PC775") >= 0)        cp = (int)MPosCodePage.MPOS_CODEPAGE_CP775;
            else if (codepage.IndexOf("PC928") >= 0)        cp = (int)MPosCodePage.MPOS_CODEPAGE_CP928;
            else if (codepage.IndexOf("WPC1250") >= 0)      cp = (int)MPosCodePage.MPOS_CODEPAGE_WPC1250;
            else if (codepage.IndexOf("WPC1251") >= 0)      cp = (int)MPosCodePage.MPOS_CODEPAGE_WPC1251;
            else if (codepage.IndexOf("WPC1252") >= 0)      cp = (int)MPosCodePage.MPOS_CODEPAGE_WPC1252;
            else if (codepage.IndexOf("WPC1253") >= 0)      cp = (int)MPosCodePage.MPOS_CODEPAGE_WPC1253;
            else if (codepage.IndexOf("WPC1254") >= 0)      cp = (int)MPosCodePage.MPOS_CODEPAGE_WPC1254;
            else if (codepage.IndexOf("WPC1255") >= 0)      cp = (int)MPosCodePage.MPOS_CODEPAGE_WPC1255;
            else if (codepage.IndexOf("WPC1256") >= 0)      cp = (int)MPosCodePage.MPOS_CODEPAGE_WPC1256;
            else if (codepage.IndexOf("WPC1257") >= 0)      cp = (int)MPosCodePage.MPOS_CODEPAGE_WPC1257;
            else if (codepage.IndexOf("WPC1258") >= 0)      cp = (int)MPosCodePage.MPOS_CODEPAGE_WPC1258;
            else if (codepage.IndexOf("FARSI") >= 0)        cp = (int)MPosCodePage.MPOS_CODEPAGE_FARSI_II;
            else if (codepage.IndexOf("KHMER") >= 0)        cp = (int)MPosCodePage.MPOS_CODEPAGE_KHMER;
            else if (codepage.IndexOf("THAI11") >= 0)       cp = (int)MPosCodePage.MPOS_CODEPAGE_THAI11;
            else if (codepage.IndexOf("THAI14") >= 0)       cp = (int)MPosCodePage.MPOS_CODEPAGE_THAI14;
            else if (codepage.IndexOf("THAI16") >= 0)       cp = (int)MPosCodePage.MPOS_CODEPAGE_THAI16;
            else if (codepage.IndexOf("THAI18") >= 0)       cp = (int)MPosCodePage.MPOS_CODEPAGE_THAI18;
            else if (codepage.IndexOf("THAI42") >= 0)       cp = (int)MPosCodePage.MPOS_CODEPAGE_THAI42;
            else if (codepage.IndexOf("TCVN-3(1)") >= 0)    cp = (int)MPosCodePage.MPOS_CODEPAGE_TCVN;
            else if (codepage.IndexOf("TCVN-3(2)") >= 0)    cp = (int)MPosCodePage.MPOS_CODEPAGE_TCVN_CAPTIAL;
            else if (codepage.IndexOf("VISCII") >= 0)       cp = (int)MPosCodePage.MPOS_CODEPAGE_VISCII;
            else if (codepage.IndexOf("KATAKANA") >= 0)     cp = (int)MPosEastAsiaCodePage.MPOS_CODEPAGE_SHIFTJIS;
            else if (codepage.IndexOf("KS5601") >= 0)       cp = (int)MPosEastAsiaCodePage.MPOS_CODEPAGE_KSC5601;
            else if (codepage.IndexOf("BIG5") >= 0)         cp = (int)MPosEastAsiaCodePage.MPOS_CODEPAGE_BIG5;
            else if (codepage.IndexOf("GB2312") >= 0)       cp = (int)MPosEastAsiaCodePage.MPOS_CODEPAGE_GB2312;
            else if (codepage.IndexOf("SHIFT-JIS") >= 0)    cp = (int)MPosEastAsiaCodePage.MPOS_CODEPAGE_SHIFTJIS;

            if (MposDeviceObj != null){
                if (MposDeviceObj is MPosControllerPrinter)
                    ((MPosControllerPrinter)MposDeviceObj).setTextEncoding((int)cp);
            }

            MPosDebug.WriteLine("SetTextEncoding : END");
        }
        public async Task<int> PageModePrint(int mode)
        {
            var result = (int)MPosResult.MPOS_FAIL_NOT_CONNECT;

            if (!DeviceEnable)
            {
                MPosDebug.WriteLine("PageModePrint : MPOS_FAIL_DEVICE_DISABLE");
                return (int)cordovaResult.MPOS_FAIL_DEVICE_DISABLE;
            }

            if (MposDeviceObj != null)
            {
                if (MposDeviceObj is MPosControllerPrinter)
                    result = await ((MPosControllerPrinter)MposDeviceObj).setPagemode(mode);
            }

            return result;
        }
        public int SetDeviceEnable(bool enable)
        {
            var result = (int)MPosResult.MPOS_FAIL_NOT_CONNECT;

            if (!DeviceClaimed)
            {
                result = (int)cordovaResult.MPOS_FAIL_NOT_CLAIMED;
                MPosDebug.WriteLine("SetDeviceEnable : MPOS_FAIL_NOT_CLAIMED");
                return result;
            }

            if (MposDeviceObj != null)
            {
                DeviceEnable = enable;
                result = (int)MPosResult.MPOS_SUCCESS;
            }

            MPosDebug.WriteLine("SetDeviceEnable : DeviceEnable = " + DeviceEnable);
            return result;
        }
        public async Task<int> SetPageModePrintArea(int x, int y, int width, int height)
        {
            var result = (int)MPosResult.MPOS_FAIL_NOT_CONNECT;

            if (!DeviceEnable)
            {
                MPosDebug.WriteLine("SetPageModePrintArea : MPOS_FAIL_DEVICE_DISABLE");
                return (int)cordovaResult.MPOS_FAIL_DEVICE_DISABLE;
            }

            if (MposDeviceObj != null)
            {
                if (MposDeviceObj is MPosControllerPrinter)
                    result = ((MPosControllerPrinter)MposDeviceObj).setPagemodePrintArea(x, y, width, height);
            }

            return result;
        }
        public async Task<int> SetPageModePrintDirection(int direction)
        {
            var result = (int)MPosResult.MPOS_FAIL_NOT_CONNECT;

            if (!DeviceEnable)
            {
                MPosDebug.WriteLine("SetPageModePrintDirection : MPOS_FAIL_DEVICE_DISABLE");
                return (int)cordovaResult.MPOS_FAIL_DEVICE_DISABLE;
            }

            if (MposDeviceObj != null)
            {
                if (MposDeviceObj is MPosControllerPrinter)
                    result = ((MPosControllerPrinter)MposDeviceObj).setPagemodeDirection((int)direction);
            }

            return result;
        }
        public async Task<int> SetPageModeVerticalPosition(int y)
        {
            var result = (int)MPosResult.MPOS_FAIL_NOT_CONNECT;

            if (!DeviceEnable)
            {
                MPosDebug.WriteLine("SetPageModeVerticalPosition : MPOS_FAIL_DEVICE_DISABLE");
                return (int)cordovaResult.MPOS_FAIL_DEVICE_DISABLE;
            }

            if (MposDeviceObj != null)
            {
                if (MposDeviceObj is MPosControllerPrinter)
                    result = ((MPosControllerPrinter)MposDeviceObj).setPagemodePosition(-1, y);
            }

            return result;
        }
        public async Task<int> SetPageModeHorizontalPosition(int x)
        {
            var result = (int)MPosResult.MPOS_FAIL_NOT_CONNECT;

            if (!DeviceEnable)
            {
                MPosDebug.WriteLine("SetPageModeHorizontalPosition : MPOS_FAIL_DEVICE_DISABLE");
                return (int)cordovaResult.MPOS_FAIL_DEVICE_DISABLE;
            }

            if (MposDeviceObj != null)
            {
                if (MposDeviceObj is MPosControllerPrinter)
                    result = ((MPosControllerPrinter)MposDeviceObj).setPagemodePosition(x, -1);
            }

            return result;
        }
    }
}
