using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SII.SDK.Maui.Printer;
using DeviceInfo = SII.SDK.Maui.Printer.DeviceInfo;
using DeviceType = SII.SDK.Maui.Printer.DeviceType;

namespace Sample
{
    partial class Function
    {
        // Define completion delegate of StartDiscoveryDevice
        public event Action<DeviceInfo[]> DeviceSearchCompletedEvent;

        // PrinterManager class
        private PrinterManager _printerManager;

        // Offline status(0x80000000) definition
        private const int STATUS_OFFLINE = -2147483648;

        // Sample print data definition
        private const string RECEIPT_SAMPLE_EN =
        "--------------------------------\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" +
        "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\n";

        // Sample print data definition for Japanese
        private const string RECEIPT_SAMPLE_JA =
        "--------------------------------\n" +
        "ｸﾞﾘﾙﾁｷﾝﾌﾞﾚｽﾄ              ¥1,850\n" +
        "ｻｰﾛｲﾝｽﾃｰｷ                 ¥3,200\n" +
        "ﾛｰｽﾄﾗﾑ                    ¥2,000\n" +
        "ｻﾗﾀﾞ                      ¥1,000\n" +
        "ｸｯｷｰ                        ¥350\n" +
        "ｸｯｷｰ                        ¥350\n" +
        "ｱｲｽｸﾘｰﾑ                     ¥500\n" +
        "ﾁｭｳｶｿﾊﾞ                   ¥1,500\n" +
        "ｽｷﾔｷ                      ¥3,000\n" +
        "ｻﾝﾄﾞｲｯﾁ                   ¥1,000\n" +
        "ﾋﾟｻﾞ                      ¥2,000\n" +
        "ｺｳﾁｬ                        ¥350\n" +
        "ｺｰﾋｰ                        ¥350\n\n" +
        "--------------------------------\n" +
        "       小計　            ¥17,450\n" +
        "       消費税               ¥873\n" +
        "       合計　            ¥18,323\n\n" +
        "ご利用ありがとうございます\n" +
        "またのご利用をお待ちしております\n\n";

        public Function()
        {
            object context = null;
#if ANDROID
            context = Platform.AppContext;
#endif
            // For iOS, no context is needed, so pass null
            _printerManager = new PrinterManager(context);
        }

        public void Dispose()
        {
            if (_printerManager != null)
            {
                if (_printerManager.IsConnect)
                {
                    _printerManager.Disconnect();
                }
                _printerManager = null;
            }
        }

        public partial String GetCurrentLanguage();
        public partial Task CheckStoragePermissions();
        private partial Task CheckBluetoothPermissions(PortType portType);
        private partial object GetPlatformImageData(string filePath);
        private partial bool DisposePlatformImageData(object imageObject);

        // Sample of getting SDK version
        public string GetVersion()
        {
            return _printerManager.Version;
        }

        // Sample of Connect
        public Task<string> ConnectSampleAsync(DeviceModel deviceModel, DeviceInfo deviceInfo)
        {
            return Task.Run(() =>
            {
                string result = "";
                try
                {
                    _printerManager.Connect(deviceModel, deviceInfo);
                }
                catch (PrinterException ex)
                {
                    result = $"Connect Error : {ex.HResult}";
                }

                return result;
            });
        }

        // Sample of Disconnect
        public Task<string> DisonnectSampleAsync()
        {
            return Task.Run(() =>
            {
                string result = "";
                try
                {
                    _printerManager.Disconnect();
                }
                catch (PrinterException ex)
                {
                    result = $"Disconnect Error : {ex.HResult}";
                }

                return result;
            });
        }

        // Sample of printing in standard mode
        public Task<string> StandardModePrintSampleAsync()
        {
            return Task.Run(() =>
            {
                string result = "";
                try
                {
                    // Check offline
                    _printerManager.GetStatus(out int[] status);
                    if (status[0] == STATUS_OFFLINE)
                    {
                        return result = $"StandardModePrintSample Error : {PrinterException.ERROR_OFFLINE}";
                    }

                    DateTime dateTime = DateTime.Now;

                    // Print according to the language of the terminal.
                    if (GetCurrentLanguage().Contains("en"))
                    {
                        // Language used: Other than Japanese
                        // Character set for English
                        _printerManager.CodePage = CodePage.CODE_PAGE_1252;
                        _printerManager.InternationalCharacter = InternationalCharacter.COUNTRY_USA;

                        // Print Image
                        _printerManager.SendDataFile(GetSampleFilePath("SampleLogo.jpg"), PrintAlignment.ALIGNMENT_CENTER, Dithering.DITHERING_ERRORDIFFUSION);

                        // Print Text
                        _printerManager.SendTextEx($"\nNo.00001    {dateTime.ToString("yyyy-MM-dd HH:mm:ss")}\n", CharacterBold.BOLD_CANCEL, CharacterUnderline.UNDERLINE_CANCEL, CharacterReverse.REVERSE_CANCEL, CharacterFont.FONT_A, CharacterScale.VERTICAL_1_HORIZONTAL_1, PrintAlignment.ALIGNMENT_CENTER);

                        // Print Text
                        _printerManager.SendTextEx(RECEIPT_SAMPLE_EN, CharacterBold.BOLD_CANCEL, CharacterUnderline.UNDERLINE_CANCEL, CharacterReverse.REVERSE_CANCEL, CharacterFont.FONT_A, CharacterScale.VERTICAL_1_HORIZONTAL_1, PrintAlignment.ALIGNMENT_CENTER);

                        // Print QR
                        string qrData = "QR Sample";      // 1-Byte Character Set example
                        _printerManager.PrintQRcode(qrData, ErrorCorrection.QR_ERROR_CORRECTION_M, ModuleSize.QR_MODULE_SIZE_4, PrintAlignment.ALIGNMENT_CENTER, QrModel.QR_MODEL_2);

                        // Specify the barcode for EAN13
                        _printerManager.PrintBarcode(BarcodeSymbol.BARCODE_EAN13, "0123456789012", ModuleSize.BARCODE_MODULE_WIDTH_3, 80, HriPosition.HRI_POSITION_BELOW, CharacterFont.FONT_A, PrintAlignment.ALIGNMENT_CENTER);
                        //// Specify the barcode for CODE93 (Data:12345)
                        //// How to binary input.
                        //// 1. Input any data from 00H to 2EH. Multiple data can be input
                        //// 2. Input 2FH or more lastly as the stop code
                        //byte[] data = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x2F };
                        //_printerManager.PrintBarcode(BarcodeSymbol.BARCODE_CODE93, data, ModuleSize.BARCODE_MODULE_WIDTH_3, 80, HriPosition.HRI_POSITION_BELOW, CharacterFont.FONT_A, PrintAlignment.ALIGNMENT_CENTER);
                    }
                    else
                    {
                        // Language used: Japanese
                        // Character set for Japanese
                        _printerManager.CodePage = CodePage.CODE_PAGE_KATAKANA;
                        _printerManager.InternationalCharacter = InternationalCharacter.COUNTRY_JAPAN;

                        // Print Image
                        _printerManager.SendDataFile(GetSampleFilePath("SampleLogo.jpg"), PrintAlignment.ALIGNMENT_CENTER, Dithering.DITHERING_ERRORDIFFUSION);

                        // Print Text
                        _printerManager.SendTextEx($"\nNo.00001    {dateTime.ToString("yyyy-MM-dd HH:mm:ss")}\n", CharacterBold.BOLD_CANCEL, CharacterUnderline.UNDERLINE_CANCEL, CharacterReverse.REVERSE_CANCEL, CharacterFont.FONT_A, CharacterScale.VERTICAL_1_HORIZONTAL_1, PrintAlignment.ALIGNMENT_CENTER);

                        // Print Text
                        _printerManager.SendTextEx(RECEIPT_SAMPLE_JA, CharacterBold.BOLD_CANCEL, CharacterUnderline.UNDERLINE_CANCEL, CharacterReverse.REVERSE_CANCEL, CharacterFont.FONT_A, CharacterScale.VERTICAL_1_HORIZONTAL_1, PrintAlignment.ALIGNMENT_CENTER);

                        // Print QR
                        string qrData = "QR サンプル"; // 2-Byte Character Set example
                        _printerManager.PrintQRcode(qrData, ErrorCorrection.QR_ERROR_CORRECTION_M, ModuleSize.QR_MODULE_SIZE_4, PrintAlignment.ALIGNMENT_CENTER, QrModel.QR_MODEL_2);

                        // Specify the barcode for EAN13
                        _printerManager.PrintBarcode(BarcodeSymbol.BARCODE_EAN13, "0123456789012", ModuleSize.BARCODE_MODULE_WIDTH_3, 80, HriPosition.HRI_POSITION_BELOW, CharacterFont.FONT_A, PrintAlignment.ALIGNMENT_CENTER);
                    }

                    // Partial cut with pre-feed
                    // If using printer does not have cutter, it will only feed paper
                    _printerManager.CutPaper(CuttingMethod.CUT_PARTIAL);

                    // Confirm print finished
                    _printerManager.GetPrinterResponse(PrinterResponseId.PRINTER_RESPONSE_REQUEST, 0, out int[] response);
                    if (response != null && response.Length != 0)
                    {
                        if (response[0] != (int)0x80)
                        {
                            return result = "StandardModePrintSample Error";
                        }
                    }
                }
                catch (PrinterException ex)
                {
                    result = $"StandardModePrintSample Error : {ex.HResult}";
                }

                return result;
            });
        }

        // Sample of printing in page mode
        public Task<string> PageModePrintSampleAsync()
        {
            return Task.Run(() =>
            {
                string result = "";
                try
                {
                    // Check offline
                    _printerManager.GetStatus(out int[] status);
                    if (status[0] == STATUS_OFFLINE)
                    {
                        return result = $"PageModePrintSample Error : {PrinterException.ERROR_OFFLINE}";
                    }

                    // Character set for English
                    _printerManager.CodePage = CodePage.CODE_PAGE_1252;
                    _printerManager.InternationalCharacter = InternationalCharacter.COUNTRY_USA;

                    //// Character set for Japanese
                    //_printerManager.CodePage = CodePage.CODE_PAGE_KATAKANA;
                    //_printerManager.InternationalCharacter = InternationalCharacter.COUNTRY_JAPAN;

                    // Start page mode
                    _printerManager.EnterPageMode();

                    // Specify the print area in page mode
                    // The number of printable dots in one dot line has to be set to 355 dots for this sample code.
                    _printerManager.SetPageModeArea(0, 0, 355, 576);

                    // Specify the rectangle and the rule
                    _printerManager.PrintPageModeRectangle(0, 0, 344, 575, LineStyle.LINESTYLE_THIN);
                    _printerManager.PrintPageModeRectangle(7, 7, 336, 567, LineStyle.LINESTYLE_THIN);
                    _printerManager.PrintPageModeLine(11, 404, 334, 404, LineStyle.LINESTYLE_THIN);

                    // Specify the print direction in page mode
                    _printerManager.SetPageModeDirection(Direction.DIRECTION_TOP_TO_BOTTOM);

                    // Specify the text
                    _printerManager.PrintPageModeText(21, 47, "No.123456789");
                    _printerManager.PrintPageModeText(212, 340, "Date 2023-01-01");

                    // Specify the image file
                    string imagePath = GetSampleFilePath("TicketImage.jpg");
                    _printerManager.PrintPageModeImageFile(10, 222, imagePath, Dithering.DITHERING_DISABLE);

                    // Specify the print area in page mode
                    _printerManager.SetPageModeArea(0, 404, 345, 163);

                    // Specify the direction of the print
                    _printerManager.SetPageModeDirection(Direction.DIRECTION_LEFT_TO_RIGHT);

                    // Specify the barcode for CODE128
                    _printerManager.PrintPageModeBarcode(20, 132, BarcodeSymbol.BARCODE_CODE128, new byte[] { 0x67, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x68 }, ModuleSize.BARCODE_MODULE_WIDTH_2, 80, HriPosition.HRI_POSITION_ABOVE, CharacterFont.FONT_A);

                    //// Specify the barcode for CODE128 (Data:123456789)
                    //// How to input using the CODE128 Code Set table
                    //// 1. Input the start code of 67H(Code Set A), 68H(Code Set B), or 69H(Code Set C) shown in the table of CODE128 Code Set
                    //// 2. Input any data from 00H to 66H. Multiple data can be input
                    //// 3. Input 67H or more lastly as the stop code
                    ////byte[] data = new byte[] { 0x68, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x67 };

                    //// How to input using the CODE128 Special Code Set table
                    //// 1. Input the start code (START A, START B, or START C) of the code set to be selected shown in the table of CODE128 Special Code
                    //// 2. Input the data in the respective formats
                    ////       Code Set A : Data from 00H to 5FH can be input
                    ////       Code Set B : Data from 20H to 7FH can be input
                    ////       Code Set C : Data from 00H(00) to 63H(99) can be input
                    //byte[] data = new byte[] { 0x7B, 0x42, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39 };
                    //_printerManager.PrintPageModeBarcode(10, 132, BarcodeSymbol.BARCODE_CODE128, data, ModuleSize.BARCODE_MODULE_WIDTH_2, 80, HriPosition.HRI_POSITION_ABOVE, CharacterFont.FONT_A);

                    // Print the page mode and partial cut with pre-feed
                    // If using printer does not have cutter, it will only feed paper
                    _printerManager.PrintPageMode(CuttingMethod.CUT_PARTIAL);

                    // Confirm print finished
                    _printerManager.GetPrinterResponse(PrinterResponseId.PRINTER_RESPONSE_REQUEST, 0, out int[] response);
                    if (response != null && response.Length != 0)
                    {
                        if (response[0] != (int)0x80)
                        {
                            return result = "PageModePrintSample Error";
                        }
                    }
                }
                catch (PrinterException ex)
                {
                    result = $"PageModePrintSample Error : {ex.HResult}";
                }
                finally
                {
                    try
                    {
                        // Exit page mode
                        _printerManager.ExitPageMode();
                    }
                    catch
                    {
                        // An exception error occurs if the page mode is not started or unsupported
                    }
                }

                return result;
            });
        }

        // Sample of StatusCallback
        public Task<string> StatusCallbackSampleAsync(Action<int> callback)
        {
            return Task.Run(() =>
            {
                string result = "";
                try
                {
                    // The event is called when printer status changed
                    _printerManager.SetStatusChangedEventHandler(callback);
                }
                catch (PrinterException ex)
                {
                    result = $"StatusCallbackSample Error : {ex.HResult}";
                }

                return result;
            });
        }

        // Sample of BarcodeScannerCallback
        public Task<string> BarcodeScannerCallbackSampleAsync(Action changedOnline, Action changedOffline, Action<byte[]> scanned)
        {
            return Task.Run(() =>
            {
                string result = "";
                try
                {
                    // The event is called when barcode scanner status changed offline
                    _printerManager.SetBarcodeScannerChangedOnlineEventHandler(changedOnline);

                    // The event is called when barcode scanner status changed online
                    _printerManager.SetBarcodeScannerChangedOfflineEventHandler(changedOffline);

                    // The event is called when barcode scanner scanned barcode
                    _printerManager.SetBarcodeScannerReadDataEventHandler(scanned);
                }
                catch (PrinterException ex)
                {
                    result = $"BarcodeScannerCallbackSample Error : {ex.HResult}";
                }

                return result;
            });
        }

        // Sample using object selection and template showing #1
        public Task<string> BeginPaymentSampleAsync(int total)
        {
            // Change the display content to match the language of the device.
            String currencyUnit = "$";
            String title = "Total";
            int rate = 100;
            String displayFormula = " {0:D1}.{1:D2}";
            int templateID = 119;
            if (GetCurrentLanguage().Contains("ja"))
            {
                //Language used: Japanese
                currencyUnit = "¥";
                title = "合計";
                rate = 1;
                displayFormula = " {0:D1}";
                templateID = 120;
            }
            string strTotal = string.Format(currencyUnit + displayFormula, total / rate, total % rate);

            return Task.Run(() =>
            {
                string result = "";
                try
                {
                    if (GetCurrentLanguage().Contains("ja"))
                    {
                        // Language used: Japanese
                        // Character set for Japanese
                        _printerManager.CodePage = CodePage.CODE_PAGE_KATAKANA;
                        _printerManager.InternationalCharacter = InternationalCharacter.COUNTRY_JAPAN;
                    }
                    else
                    {
                        // Language used: Other than Japanese
                        // Character set for English
                        _printerManager.CodePage = CodePage.CODE_PAGE_1252;
                        _printerManager.InternationalCharacter = InternationalCharacter.COUNTRY_USA;
                    }
                    
                    _printerManager.SelectTemplate(templateID, 80); // Select template (ID=119 : for List Up(En)) with Slide 80
                                                                    // Select template (ID=120 : for List Up(Jp)) with Slide 80

                    _printerManager.SelectTemplateTextObject(0);     // Select Text area 0
                    _printerManager.SetTemplateTextData(title);
                    _printerManager.SelectTemplateTextObject(1);     // Select Text area 1
                    _printerManager.SetTemplateTextData(strTotal);
                    _printerManager.ShowTemplate(0);                 // Display
                }
                catch (PrinterException ex)
                {
                    result = $"DisplaySample Error : {ex.HResult}";
                }

                return result;
            });
        }

        // Sample using object selection and template showing #2
        public Task<string> RegisterItemSampleAsync(int subTotal, string itemName, int price)
        {
            // Change the display content to match the language of the device.
            String currencyUnit = "$";
            int rate = 100;
            String displayFormula = " {0:D1}.{1:D2}";
            if (GetCurrentLanguage().Contains("ja"))
            {
                //Language used: Japanese
                currencyUnit = "¥";
                rate = 1;
                displayFormula = " {0:D1}";
            }
            string strSubTotal = string.Format(currencyUnit + displayFormula, subTotal / rate, subTotal % rate);
            string strPrice = string.Format(currencyUnit + displayFormula, price / rate, price % rate);

            return Task.Run(() =>
            {
                string result = "";
                try
                {
                    _printerManager.SelectTemplateTextObject(1);      // Select Text area 1
                    _printerManager.SetTemplateTextData(strSubTotal);
                    _printerManager.SelectTemplateTextObject(6);      // Select Text area 6
                    _printerManager.SetTemplateTextData(itemName);
                    _printerManager.SelectTemplateTextObject(7);      // Select Text area 7
                    _printerManager.SetTemplateTextData(strPrice);
                    _printerManager.ShowTemplate(0);                  // Display
                }
                catch (PrinterException ex)
                {
                    result = $"DisplaySample Error : {ex.HResult}";
                }

                return result;
            });
        }

        // Sample using object selection and template showing #3
        public Task<string> FinishPaymentSampleAsync(int total, int paid, int change)
        {
            // Change the display content to match the language of the device.
            String currencyUnit = "$";
            int rate = 100;
            String displayFormula = " {0:D1}.{1:D2}";
            int templateID = 123;
            int slideID = 82;
            if (GetCurrentLanguage().Contains("ja"))
            {
                //Language used: Japanese
                currencyUnit = "¥";
                rate = 1;
                displayFormula = " {0:D1}";
                templateID = 124;
                slideID = 83;
            }
            string strTotal = string.Format(currencyUnit + displayFormula, total / rate, total % rate);
            string strPaid = string.Format(currencyUnit + displayFormula, paid / rate, paid % rate);
            string strChange = string.Format(currencyUnit + displayFormula, change / rate, change % rate);

            return Task.Run(() =>
            {
                string result = "";
                try
                {
                    _printerManager.SelectTemplate(templateID, slideID); // Select template (ID=123 : for 3 lines(En)) with Slide 82
                                                                         // Select template (ID=124 : for 3 lines(Jp)) with Slide 83

                    _printerManager.SelectTemplateTextObject(3);    // Select Text area 3
                    _printerManager.SetTemplateTextData(strTotal);
                    _printerManager.SelectTemplateTextObject(4);    // Select Text area 4
                    _printerManager.SetTemplateTextData(strPaid);
                    _printerManager.SelectTemplateTextObject(5);    // Select Text area 5
                    _printerManager.SetTemplateTextData(strChange);

                    _printerManager.ShowTemplate(0);                // Display
                }
                catch (PrinterException ex)
                {
                    result = $"DisplaySample Error : {ex.HResult}";
                }

                return result;
            });
        }

        //	Sample of putting the display on standby
        public Task<string> StandbySampleAsync()
        {
            return Task.Run(() =>
            {
                string result = "";
                try
                {
                    _printerManager.EnterStandbyMode();
                }
                catch (PrinterException ex)
                {
                    result = $"DisplaySample Error : {ex.HResult}";
                }

                return result;
            });
        }

        // Sample of printing smart label
        public Task<string> SmartLabelSampleAsync()
        {
            return Task.Run(() =>
            {
                string result = "";
                try
                {
                    // Check offline
                    _printerManager.GetStatus(out int[] status);
                    if (status[0] == STATUS_OFFLINE)
                    {
                        return result = $"SmartLabelSample Error : {PrinterException.ERROR_OFFLINE}";
                    }

                    // Create smart label instance.
                    object context = null;
#if ANDROID
                    context = Platform.AppContext;
#endif
                    SmartLabelManager smartLabelManager = new SmartLabelManager(context);

                    // Specify a label file(*.sl) to print or replace data.
                    // Sample.sl is defined following objects.
                    //  * Text    Object (ID = 1) : "Jane Smith"
                    //  * Image   Object (ID = 1) : woman.jpg
                    //  * Barcode Object (ID = 1) : "0123456" (Code128)
                    // Label Type of Sample.sl is User Paper[ Printer:MP-B21L, PaperType:Receipt, PositionDetection:None, PaperWidth58mm, PaperLength:300mm ].
                    string labelFilePath = GetSampleFilePath("Sample.sl");
                    smartLabelManager.SelectSmartLabelFile(labelFilePath);

                    // Print an unedited Smart Label image
                    _printerManager.PrintSmartLabelImageData(smartLabelManager);

                    // Replace the text data with "John Smith".
                    smartLabelManager.ReplaceSmartLabelTextData(1, "John Smith");

                    // Replace the image data with "man.jpg".
                    // Get image data for replacement
                    string imageFilePath = GetSampleFilePath("man.jpg");
                    object imageObject = GetPlatformImageData(imageFilePath);
                    smartLabelManager.ReplaceSmartLabelImageData(1, imageObject);
                    // Dispose image data
                    DisposePlatformImageData(imageObject);

                    // Replace the barcode data with "ABCDEFG".
                    smartLabelManager.ReplaceSmartLabelBarcodeData(1, "ABCDEFG");

                    // Print the edited Smart Label image
                    _printerManager.PrintSmartLabelImageData(smartLabelManager);

                    // Full cut with pre-feed.
                    _printerManager.CutPaper(CuttingMethod.CUT_FULL);

                    // Confirm print finished
                    _printerManager.GetPrinterResponse(PrinterResponseId.PRINTER_RESPONSE_REQUEST, 0, out int[] response);
                    if (response != null && response.Length != 0)
                    {
                        if (response[0] != (int)0x80)
                        {
                            return result = "SmartLabelSample Error";
                        }
                    }
                }
                catch (PrinterException ex)
                {
                    result = $"SmartLabelSample Error : {ex.HResult}";
                }

                return result;
            });
        }

        // Sample of printing a file
        public Task<string> SendDataFileSampleAsync(String filePath)
        {
            return Task.Run(() =>
            {
                string result = "";
                try
                {
                    // Checks the printer status for 3 seconds and exits the loop immediately if online.
                    // In Android 15 and later,
                    // the network may disconnect while the file picker is being displayed,
                    // so the printer status should be checked.
                    bool isOnline = false;
                    long timeout = 3000;
                    DateTime startTime = DateTime.Now;
                    do
                    {
                        _printerManager.GetStatus(out int[] status);
                        if (status[0] != STATUS_OFFLINE)
                        {
                            isOnline = true;
                            break;
                        }
                    } while (DateTime.Now - startTime < TimeSpan.FromMilliseconds(timeout));
                    // Check offline
                    if (!isOnline)
                    {
                        return result = $"SendDataFileSample Error : {PrinterException.ERROR_OFFLINE}";
                    }

                    //Set the timeout time (Please set a value longer than the time it takes to send print data)
                    _printerManager.SendTimeout = 90000;
                    _printerManager.ReceiveTimeout = 90000;

                    // Specifies the print or data file.
                    _printerManager.SendDataFile(filePath, PrintAlignment.ALIGNMENT_LEFT,Dithering.DITHERING_DISABLE);

                    // Confirm print finished
                    _printerManager.GetPrinterResponse(PrinterResponseId.PRINTER_RESPONSE_REQUEST, 0, out int[] response);
                    if (response != null && response.Length != 0)
                    {
                        if (response[0] != (int)0x80)
                        {
                            return result = "SendDataFileSample Error";
                        }
                    }

                    //Set the timeout time
                    _printerManager.SendTimeout = 10000;
                    _printerManager.ReceiveTimeout = 10000;
                }
                catch (PrinterException ex)
                {
                    result = $"SendDataFileSample Error : {ex.HResult}";
                }

                return result;
            });   
        }

        // Sample of printing a PDF file
        public Task<string> PrintPDFSampleAsync(String filePath)
        {
            return Task.Run(() =>
            {
                string result = "";
                try
                {
                    // Checks the printer status for 3 seconds and exits the loop immediately if online.
                    // In Android 15 and later,
                    // the network may disconnect while the file picker is being displayed,
                    // so the printer status should be checked.
                    bool isOnline = false;
                    long timeout = 3000;
                    DateTime startTime = DateTime.Now;
                    do
                    {
                        _printerManager.GetStatus(out int[] status);
                        if (status[0] != STATUS_OFFLINE)
                        {
                            isOnline = true;
                            break;
                        }
                    } while (DateTime.Now - startTime < TimeSpan.FromMilliseconds(timeout));
                    // Check offline
                    if (!isOnline)
                    {
                        return result = $"PrintPDF Sample Error : {PrinterException.ERROR_OFFLINE}";
                    }

                    //Set the timeout time (Please set a value longer than the time it takes to send print data)
                    _printerManager.SendTimeout = 90000;
                    _printerManager.ReceiveTimeout = 90000;

                    // Specifies the PDF file.
                    // To print all pages of a PDF file, set “startIndex” to -1.
                    // If “startIndex” is set to -1, the value of “endIndex” will be ignored.
                    _printerManager.PrintPDF(filePath, -1, -1, Rotate.ROTATE_NONE, ImageScale.IMAGE_SCALE_WIDTH_FIT, -1, Dithering.DITHERING_DISABLE, PrintAlignment.ALIGNMENT_LEFT);
                    // To print any page of a PDF file
                    // Example: To print pages 2 through 5, specify 2 for “startIndex” and 5 for “endIndex”.
                    // _printerManager.PrintPDF(filePath, 2, 5, Rotate.ROTATE_NONE, ImageScale.IMAGE_SCALE_WIDTH_FIT, -1, Dithering.DITHERING_DISABLE, PrintAlignment.ALIGNMENT_LEFT);


                    // Confirm print finished
                    _printerManager.GetPrinterResponse(PrinterResponseId.PRINTER_RESPONSE_REQUEST, 0, out int[] response);
                    if (response != null && response.Length != 0)
                    {
                        if (response[0] != (int)0x80)
                        {
                            return result = "PrintPDF Sample Error";
                        }
                    }

                    //Set the timeout time
                    _printerManager.SendTimeout = 10000;
                    _printerManager.ReceiveTimeout = 10000;
                }
                catch (PrinterException ex)
                {
                    result = $"PrintPDF Sample Error : {ex.HResult}";
                }

                return result;
            });
        }


        // Sample of Open Drawer
        public Task<string> OpenDrawerSampleAsync()
        {
            return Task.Run(() =>
            {
                string result = "";
                try
                {
                    // Check offline
                    _printerManager.GetStatus(out int[] status);
                    if (status[0] == STATUS_OFFLINE)
                    {
                        return result = $"OpenDrawerSample Error : {PrinterException.ERROR_OFFLINE}";
                    }

                    // Specify the drawer you want to open.
                    _printerManager.OpenDrawer(DrawerNum.DRAWER_1,PulseWidth.ON_OFF_TIME_100);

                    // Confirm print finished
                    _printerManager.GetPrinterResponse(PrinterResponseId.PRINTER_RESPONSE_REQUEST, 0, out int[] response);
                    if (response != null && response.Length != 0)
                    {
                        if (response[0] != (int)0x80)
                        {
                            return result = "OpenDrawerSample Error";
                        }
                    }
                }
                catch (PrinterException ex)
                {
                    result = $"OpenDrawerSample Error : {ex.HResult}";
                }

                return result;
            });
        }
        

        // Sample of device search
        public async Task<string> SearchDeviceSample(PortType portType)
        {
            string result = "";
            try
            {
                // Search for printer
                await CheckBluetoothPermissions(portType);
                _printerManager.StartDiscoveryDevice(DeviceType.TYPE_PRINTER, portType, 5000, Completion);

                // If you want to retrieve the paired device when searching for a Bluetooth printer on your Android device,
                // you can retrieve it immediately by calling "CancelDiscoveryDevice()".
                //_printerManager.CancelDiscoveryDevice();

                //// Search for display (DSP-A01)
                //_printerManager.StartDiscoveryDevice(DeviceType.TYPE_DISPLAY, portType, 5000, Completion);
            }
            catch (PrinterException ex)
            {
                result = $"SearchSample Error : {ex.HResult}";
            }

            return result;
        }

        // Sample of completion delegate of StartDiscoveryDevice
        private void Completion()
        {
            DeviceSearchCompletedEvent?.Invoke(_printerManager.GetFoundDevice());
        }

        // Get Sample file path.
        // If file does not exist, save file to document folder of application
        private string GetSampleFilePath(string fileName)
        {
            var documentsFolder = "";
#if ANDROID
            documentsFolder = System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
#else
            documentsFolder = System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
#endif
            string filePath = System.IO.Path.Combine(documentsFolder, fileName);

            if (!System.IO.File.Exists(filePath))
            {
                var assembly = System.Reflection.IntrospectionExtensions.GetTypeInfo(typeof(MainPage)).Assembly;
                using (System.IO.Stream stream = assembly.GetManifestResourceStream($"Sample.Resources.Raw.{fileName}"))
                using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
                using (System.IO.FileStream fs = new System.IO.FileStream(filePath, System.IO.FileMode.Create, System.IO.FileAccess.ReadWrite))
                using (System.IO.BinaryWriter writer = new System.IO.BinaryWriter(fs))
                {
                    stream.CopyTo(ms);
                    writer.Write(ms.ToArray());
                }
            }

            return filePath;
        }
    }
}

