/*
Norden Logic Oy NL02x ESC print commands
(c) 2021 - 2024
T.H.

Android version 1.1.0
 */

package com.nordenlogic.android.usbserial.util;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

import java.io.FileInputStream;
import java.nio.charset.StandardCharsets;


public class NLESCPrint {


    /*********************************************************************************************************
     **  Font type macro, used in fontTypeSet() for June 2020 Firmware and newer updated 9.12.2024
     *********************************************************************************************************/
    public static final char FONT_TYPE_NORMAL =         0x00;                              /* Normal          bit 0      */
    public static final char FONT_TYPE_ITALIC =         0x02;                              /* Italic          bit 1      */
    public static final char FONT_TYPE_RESERVE =        0x04;                             /* Reserve         bit 2      */
    public static final char FONT_TYPE_BOLD =           0x08;                             /* Bold            bit 3      */
    public static final char FONT_TYPE_DOUBLE_HEIGHT =  0x10;                             /* Double height   bit 4      */
    public static final char FONT_TYPE_DOUBLE_WIDTH =   0x20;                             /* Double width    bit 5      */
    public static final char FONT_TYPE_REVERSE =        0x40;                             /* Reverse         bit 6      */
    public static final char FONT_TYPE_UNDERLINE =      0x80;                             /* Underline       bit 7      */

    /*********************************************************************************************************
     **  Printer state macro used in setPrinterCallBack June 2020 Firmware and newer
     *********************************************************************************************************/
    /* bit 0,1,4,5,6,7 currently reserved*/
    public static final char PRINTER_STATE_DEFAULT =       0x00;                              /* None/Disable                 */
    public static final char PRINTER_STATE_PAPEROUT =      0x04;                              /* Paper end  bit 2             */
    public static final char PRINTER_STATE_OVERHEAT =      0x08;                              /* Over heat  bit 3             */

    /*********************************************************************************************************
     **  Alignment marco, used in horizontalAlign()
     *********************************************************************************************************/
    public static final char ALIGN_LEFT	= 	0;							    /* Left                         */
    public static final char ALIGN_CENTER = 1;							    /* Center                       */
    public static final char ALIGN_RIGHT = 	2;					     	    /* Right                        */

    /*********************************************************************************************************
     **  Print font marco used in fontSizeSet ()
     *********************************************************************************************************/
    //double-byte
    public static final char FONT_SIZE_D_LARGE =    2;
    public static final char FONT_SIZE_D_SMALL =    1;

    //single-byte
    public static final char  FONT_SIZE_S_LARGE =   2;
    public static final char  FONT_SIZE_S_SMALL =   1;

    /*********************************************************************************************************
     **  Horizontal bit-image printing type macro used in picturePrintH()
     *********************************************************************************************************/
    public static final char PICTURE_TYPE_NORMAL =   0;                    /* Normal                       */

    /*********************************************************************************************************
     **  Bar code system macro used in barcodePrint()
     *********************************************************************************************************/
    public static final char  BARCODE_SYS_UPCA	=  0;
    public static final char  BARCODE_SYS_UPCE	=  1;
    public static final char  BARCODE_SYS_EAN13	=  2;
    public static final char  BARCODE_SYS_EAN8	=  3;
    public static final char  BARCODE_SYS_CODE39 =  4;
    public static final char  BARCODE_SYS_ITF25	=  5;
    public static final char  BARCODE_SYS_CODABAR =  6;
    public static final char  BARCODE_SYS_CODE93 =  7;
    public static final char  BARCODE_SYS_CODE128 =  8;

    /***********************************************************************************
     ** Printer Head Family Index used in setPrinterHead()
     ***********************************************************************************/
    public static final char MM58_FTP628MCL101 = 0;     /*58mm 6 stb 7.2V compatible designs*/
    public static final char MM80_FTP638MCL101 = 1;     /*80mm 5stb 7.2V compatible designs*/
    public static final char MM58_LTP02_245_13 = 2;     /*58mm 1stb line 7.2V designs*/
    public static final char MM58_LTP02_245_C1 = 3;     /*58mm 1stb line 4.0V designs*/
    public static final char MM58_CUTTER_384  =  4;     /*NL024 chip 7.2V/24V designs*/
    public static final char MM80_CUTTER_576  =  5;     /*NL024 chip 7.2V/24V designs*/
    public static final char MM58_M23_DH_H69 = 6;     /*58mm 1stb line 7.2V design*/
    public static final char MM58_M23_SX = 7;     /*58mm 1stb line 4.0V design*/


    /* ***********************************************************************
    * Set serial communcations parameters
     n=0 9600bps n=1 19200bps n=2 38400bps n=3 57600bps n=4 115200bps n=5 256000bps n=6 375000bps *ID 5 and 6 needs FW 1.22 or higher
     m=0 No Flow Control  m=1 *Default Software Flow Control (xon/xoff)
     m=2 Hardware Flow Control RTS/busy=1 Host Stop Send Data RTS/busy=0 Host Send Data

     Default is n=4  115200  m=1 xon/xoff
    * *********************************************************************** */
    public byte[] setComMode ( char ucComSet, char ucFlowSet)
    {
        byte [] buf = new byte[]{0x1D,0x28,0x00,0x00};//GS ( n m
        buf[2] = (byte)ucComSet; // 0,1,2,3,4,5,6
        buf[3] = (byte)ucFlowSet; //0,1,2
        return buf;
    }


    /*
    Set connected Print Head. Option is saved into flash
    n=0  MM58_FTP628MCL101   58mm 6 stb 7.2V compatible designs *default value
    n=1   MM80_FTP638MCL101   80mm 5stb 7.2V compatible designs
    n=2   MM58_LTP02_245_13   58mm 1stb line 7.2V designs
    n=3   MM58_LTP02_245_C1   58mm 1stb line 4.0V designs
    n=4   MM58_CUTTER_384     58mm NL024 chip 7.2V/24V designs
    n=5   MM80_CUTTER_576     80mm NL024 chip 7.2V/24V designs
    n=6   MM58_M23_DH_H69     58mm 1stb line 7.2V design
    n=7   MM58_M23_SX         58mm 1stb line 4.0V design
    */
    public byte[] setPrinterHead(char ucHeadIndex)
    {
        byte [] buf	= new byte[]{0x1B,0x5A,0x00};//ESC Z n
        buf[2] = (byte)ucHeadIndex;
        return buf;
    }

    /* ***********************************************************************
     * Printer ESC/POS init command
     * *********************************************************************** */
    public byte[] printerSoftInit()
    {
        byte [] buf = new byte[]{0x1B,0x40}; //ESC @
        return buf;
    }

    /* ***********************************************************************
     * Print new line
     * *********************************************************************** */
    public byte[] printLF ()
    {
        byte [] buf	 = new byte[]{0x0A}; //LF
        return buf;
    }

    /* ***********************************************************************
     * Print move to starting position
     * *********************************************************************** */
    public byte[]printCR ()
    {
        byte [] buf	 = new byte[]{0x0D}; //CR
        return buf;
    }


    /* ***********************************************************************
     * Send a string to be printed needs e.g a LF to print buffer
     * *********************************************************************** */
    public byte[] printStr(String str)
    {
        byte[] buf = str.getBytes();
        return buf;
    }


    /* ***********************************************************************
     * Printf and feed paper n dots
     * *********************************************************************** */
    public byte[] printAndFeedNDotLine (char ucDotLineNum)
    {
        byte [] buf	 = new byte[]{0x1B,0x4A,0x00}; //ESC J n
        buf[2] = (byte)ucDotLineNum;
        return buf;
    }

    /* ***********************************************************************
     * Set character printing mode normal, italic, bold etc.
     * *********************************************************************** */
    public byte[] fontTypeSet (char ucFontType)
    {
        byte [] buf	 = new byte[] {0x1B,0x21,0x00};//ESC ! n
        buf[2] = (byte)ucFontType;
        return buf;
    }

    /* ***********************************************************************
     * Set print alignment
     * *********************************************************************** */
    public byte[] horizontalAlign(char align)
    {
        byte [] buf	 = new byte[]{0x1B,0x61,0x00};//ESC a n
        buf[2] = (byte)align;
        return buf;
    }

    /*********************************************************************************************************
     ** Function name:           lineSpacingSet
     ** Descriptions:            This function is used to set the line space.
     ** input parameters:        ucDotLineNum: dots of line space; n = 0 ~ 255, default value: n = 33.
     ** Returned value:          byte[]
     *********************************************************************************************************/
    public byte[] lineSpacingSet (char ucDotLineNum)
    {
        byte [] buf	 = new byte[]{0x1B,0x33,0x00};//ESC 3 n
        buf[2] = (byte)ucDotLineNum;
        return buf;
    }

    /******************************************************************************************
     ** Function name: lineSpacingDefaults
     ** Descriptions:  This functions is used to set the line spacing to defaults
     ** Returned value: none
     ***************************************************************************************/
    public byte[] lineSpacingDefaults ()
    {
        byte [] buf	 = new byte[]{0x1B,0x32};//ESC 2
        return buf;
    }



    /**************************************************************************************
     ** Function name: horizontalTabSet
     ** input parameters:
     ucNBuf: array of column position
     ucDataNum: number of tabs
     **********************************************************************************/
    public byte[] horizontalTabSet (byte[] ucNBuf, char ucDataNum)
    {
        byte [] buf	 = new byte[]{0x1B,0x44};//ESC D
        byte [] buf1	 = new byte[ucDataNum+3];
        byte [] term = new byte[]{0x00}; //null terminator signal for function

        System.arraycopy(buf, 0, buf1, 0, 2);
        System.arraycopy(ucNBuf, 0, buf1, 2, (char)ucDataNum);
        System.arraycopy(term, 0, buf1, ucDataNum+2,1);
        return buf1;
    }

    /*********************************************************************************************************
     ** Function name:           horizontalTab
     ** Descriptions:            This function is used to move the printing position to the next tab position
     **                          in horizontal. The tab position is set by horizontalTabSet().
     ** input parameters:        none
     ** Returned value:          none
     ********************************************************************************************************/
    public byte[] horizontalTab()
    {
        byte [] buf	 = new byte[]{0x09}; //HT
        return buf;
    }

    /*********************************************************************************************************
     ** Function name:           printAndFeedNFontLine
     ** Descriptions:            This function is used to print and feed paper for n font lines. However, when
     **                          the printer buffer is empty, it only feeds paper for n lines but not print.
     **                          This function only affects one line. The line space settings by ESC 3 and ESC 2
     **                          commands are not affected.
     ** input parameters:        ucFontLineNum: Feed paper for n lines, n = 0 ~ 255
     ** Returned value:          byte[]
     *********************************************************************************************************/
    public byte[] printAndFeedNFontLine (char ucFontLineNum)
    {
        byte [] buf	 = new byte[] {0x1B,0x64,0x00};//ESC d n
        buf[2] = (byte)ucFontLineNum;
        return buf;
    }



    /*********************************************************************************************************
     ** Function name:           picturePrintH
     ** Descriptions:            This function is used to print raster bit image.
     ** input parameters:        ucType: raster bit image modes as follows:
     **                                  PICTURE_TYPE_NORMAL         normal
     **                          usHSize: horizontal byte number
     **                          usVSize: vertical dot number
     **                          pucDataBuf: starting address of the image buffer
     ** Returned value:          byte[]
     *********************************************************************************************************/
    public byte[] picturePrintH (char ucType,
                                    char usHSize,
                                    char usVSize,
                                      byte [] ucDataBuf)
    {
        byte [] buf	 = new byte[]{0x1D,0x76,0x30,0x00,0x00,0x00,0x00,0x00};//GS v 0
        buf[3] = (byte)ucType;
        buf[4] = (byte)(usHSize & 0xFF); 		// xL
        buf[5] = (byte)((usHSize >> 8) & 0xFF);	// xH
        buf[6] = (byte)(usVSize & 0xFF);		// yL
        buf[7] = (byte)((usVSize >> 8) & 0xFF);	// yH

        byte [] bitmapbuf = new byte[ucDataBuf.length+buf.length];

        System.arraycopy(buf, 0, bitmapbuf, 0, buf.length);
        System.arraycopy(ucDataBuf, 0, bitmapbuf, buf.length, ucDataBuf.length);
        return bitmapbuf;
    }



    /*********************************************************************************************************
     ** Function name:          setLeftMargin
     ** Descriptions:            Sets the left margin n dots
     *********************************************************************************************************/
    public byte[] setLeftMargin (char ucDots)
    {
        byte [] buf	 = new byte[]{0x1B,0x6C,0x00};//ESC l n
        buf[2] = (byte)ucDots;
        return buf;
    }


    /*********************************************************************************************************
     ** Function name:           setRightMargin
     ** Descriptions:            Sets the left margin n dots
     *********************************************************************************************************/
    public byte[] setRightMargin (char ucDots)
    {
        byte [] buf	 = new byte[]{0x1B,0x51,0x00};//ESC Q n
        buf[2] = (byte)ucDots;
        return buf;
    }

    /*********************************************************************************************************
     ** Function name:           printerState
     ** Descriptions:            Query printer state
     Returns the paper status and temperature of the printer in 2 lines
     1st line:
     0 =NoPaper 1 = Paper Ok
     2nd line:
     xxC = temperature in Celsius
     *********************************************************************************************************/
    public byte[] printerState()
    {
        byte [] buf	 = new byte[]{0x10,0x04};//DLE EOT
        return buf;
    }


    /*****************************************************************************************
     ** Function name: absolutePrintPos
     ** input parameters:
     ucLNum and ucHNum: 0≤nL≤255, 0≤nH≤255
     ** Returned value: none
     ***************************************************************************************/
    public byte[] absolutePrintPos (char ucLNum,char ucHNum )
    {
        byte [] buf	 = new byte[] {0x1B,0x24,0x00,0x00};//ESC $ nL nH
        buf[2] = (byte)ucLNum;
        buf[3] = (byte)ucHNum;
        return buf;
    }


    /********************************************************
     Set font grayscale
     *******************************************************/
    public byte[] setFontGrayScale (char ucScale)
    {
        byte [] buf	 = new byte[] {0x1B,0x6D,0x00};//ESC m n
        buf[2] = (byte)ucScale;
        return buf;
    }

    /********************************************************
     Starts double-byte character mode e.g Japanese , Chinese , Korean
     *******************************************************/
    public byte[] setDbMode ()
    {
        byte [] buf	 = new byte[] {0x1C,0x26};//FS &
        return buf;

    }

    /********************************************************
     Cancels double-byte character mode e.g Japanese , Chinese , Korean
     *******************************************************/
    public byte[] cancelDbMode ()
    {
        byte [] buf	 = new byte[]{0x1C,0x2E};//FS .
        return buf;

    }


    /**************************************************************'
     //double-byte
     #define  FONT_SIZE_D_LARGE     2
     #define  FONT_SIZE_D_SMALL      1

     //single-byte
     #define  FONT_SIZE_S_LARGE              2
     #define  FONT_SIZE_S_SMALL               1
     ***************************************************************/
    public byte[] setFontMode (char ucFont)
    {
        byte [] buf	 = new byte[]{0x1B,0x4D,0x00};//ESC M n
        buf[2] = (byte)ucFont; // 1,2
        return buf;
    }


    /***************************************************************************************************
     Set the height of the bar code
     height can be between 1 and 128 inclusive
     ******************************************************************************************************/
    public byte[] barcodeHeightSet(char ucHeight)
    {
        byte [] buf	 = new byte[]{0x1D,0x68,0x00};//GS h n
        buf[2] = (byte)ucHeight;
        return buf;
    }


    /***************************************************************************************************
     Set the width of the bar code
     width can be 1,2,3,4
     *****************************/
    public byte[] barcodeWidthSet(char ucWidth)
    {
        byte [] buf	 = new byte[]{0x1D,0x77,0x00};
        buf[2] = (byte)ucWidth;
        return buf;
    }


    /*********************************************************
     Show barcode text yes or no
     n=1, show text, *default
     n=0, hide text
     *********************************************************/
    public byte[] barcodeTextYesNo(char ucYesNo)
    {
        byte [] buf	 = new byte[]{0x1D,0x48,0x00};//GS H n
        buf[2] = (byte)ucYesNo;  //0,1
        return buf;
    }


    /**************************************************************************
     ** Bar code system macro used in barcodePrint
     #define  BARCODE_SYS_UPCA              0
     #define  BARCODE_SYS_UPCE              1
     #define  BARCODE_SYS_EAN13              2
     #define  BARCODE_SYS_EAN8              3
     #define  BARCODE_SYS_CODE39              4
     #define  BARCODE_SYS_ITF25              5
     #define  BARCODE_SYS_CODABAR          6
     #define  BARCODE_SYS_CODE93              7
     #define  BARCODE_SYS_CODE128          8

     ********************************************************************************/
    public byte[] barcodePrint(char ucBarcodeSys, byte[]ucDataBuf, char ucCodeLen)
    {
        byte [] buf	 = new byte[]{0x1D,0x6B,0x00,0x00};//GS k m n d[k]
        buf[2] = (byte)(ucBarcodeSys+65); //ASCII A,B....
        buf[3] = (byte)ucCodeLen;

        byte [] barbuf = new byte[ucDataBuf.length+buf.length];

        System.arraycopy(buf, 0, barbuf, 0, buf.length);
        System.arraycopy(ucDataBuf, 0, barbuf, buf.length, ucDataBuf.length);
        return barbuf;

    }


    /***************************************************************************
     Clear print buffer

     clears and resets the print buffer
     **********************************************************************/
    public byte[] clearPrintBuffer ()
    {
        byte [] buf	 = new byte[]{0x10,0x14};//DLE DC4
        return buf;
    }


    /****************************************************************
     Query firmware information
     Returns information about the firmware in 4 lines
     1st line: controller type
     2nd line: firmware version
     3rd line: firmware date
     4th line: firmware/controller for family of print head
     ********************************************************************/
    public byte[] getFirmwareInfo ()
    {
        byte [] buf	 = new byte[] {0x10,0x05};//DLE EOT
        return buf;
    }


    /*
    Sends a full cut command to the controller
    requires NL024 and head with cutter

    */
    public byte[] fullCut()
    {
        byte [] buf	 = new byte[]{0x1B,0x69};//ESC i
        return buf;
    }


/*
Sends a partial cut command to the controller
requires NL024 and head with cutter

*/

    public byte[] partialCut()
    {

        byte [] buf	 = new byte[]{0x1B,0x6E};//ESC n
        return buf;
    }

    /*********************************************************************************************************
     ** Function name:        setPrinterCallBack
     ** Descriptions:            This function is used to set the printer states automatic callback. Notice that
     **                          all the options are disabled by default, so user should configure them before
     **                          the first printing after printer was powered on or exited form low power mode.
     **                          Otherwise, unpredicted result may occur
     ** input parameters:       ucCallBack
     options for state returned (default value n = 0),
     it is multiple selected
     **                                  PRINTER_STATE_DEFAULT        normal/disable
     **                                  PRINTER_STATE_PAPEROUT     paper end
     **                                  PRINTER_STATE_OVERHEAT      over heat
     ** Returned value:          byte[]
     *********************************************************************************************************/
    public byte[] setPrinterCallBack(char ucCallBack)
    {
        byte [] buf	 = new byte[]{0x1D,0x61,0x00};//GS a n
        buf[2] = (byte)ucCallBack;
        return buf;
    }

    /****************************************************************************************
     ** Function name:        downloadNVBitmap
     ** Descriptions:            This function is used to load bitmaps into flash memory
     ** input parameters:     ucLocation: bit image location in flash:
     **                                  n: 1, 2, 3, 4
     **                                  ucAlign: m in general use 0
     **                                  usHSize: horizontal byte number
     **                                  usVSize: vertical dot number
     **                                  pucDataBuf: starting address of the image buffer
     ** Returned value:          byte[]
     ****************************************************************************************/
    public byte[] downloadNVBitmap (char ucLocation,
                                       char ucAlign,
                                       char usHSize,
                                       char usVSize,
                                       byte [] ucDataBuf)
    {
        byte [] buf	 = new byte[]{0x1D,0x71,0x00,0x00,0x00,0x00,0x00,0x00};//FS q
        buf[2] = (byte)ucLocation;
        buf[3] = (byte)ucAlign;
        buf[4] = (byte)(usHSize & 0xFF);         // xL
        buf[5] = (byte)((usHSize >> 8) & 0xFF);    // xH
        buf[6] = (byte)(usVSize & 0xFF);        // yL
        buf[7] = (byte)((usVSize >> 8) & 0xFF);    // yH

        byte [] bitmapbuf = new byte[ucDataBuf.length+buf.length];

        System.arraycopy(buf, 0, bitmapbuf, 0, buf.length);
        System.arraycopy(ucDataBuf, 0, bitmapbuf, buf.length, ucDataBuf.length);
        return bitmapbuf;
    }


    /****************************************************************************************
     ** Function name:         printNVBitmap
     ** Descriptions:            This function prints a bitmap loaded in flash memory
     ** input parameters:     ucBitmapIndex bit image location in flash:
     **                                  n: 1, 2, 3, 4
     **                                 ucMode:
     **                                  m: 0 (print in normal mode 1:1)
     ** Returned value:          byte[]
     ****************************************************************************************/
    public byte[] printNVBitmap(char ucBitmapIndex, char ucMode)
    {
        byte [] buf	 = new byte[]{0x1C,0x70,0x00,0x00};//FS p n m
        buf[2] = (byte)ucBitmapIndex; //index range 1,2,3,4
        buf[3] = (byte) ucMode; //mode value is 0 for 1:1 normal mode bitmap
        return buf;
    }



    /****************************************************************************************
     ** Function name:        setQRSizeVersion
     ** Descriptions:            This function sets the QR code size/version
     ** input parameters:     ucModuleSizeRange:
     **                                  n: 0,1,2
     **                                  n=0  //module size  21->53
     **                                  n=1  //module size  57->121
     **                                  n=2  //module size  125->177
     ** Returned value:          byte[]
     ****************************************************************************************/
    public byte[] setQRSizeVersion(char ucModuleSizeRange)
    {
        byte [] buf	 = new byte[]{0x1D,0x28,0x6B,0x03,0x00,0x31,0x43,0x00};
        buf[7] = (byte)ucModuleSizeRange; //0x00,0x01,0x02
        return buf;
    }



    /****************************************************************************************
     ** Function name:        setQRcodeErrorCorrection
     ** Descriptions:            This function sets the error correction level for QR code
     ** input parameters:     ucErrorCorrectionLevel:
     **                                  n: 0,1,2,3
     **                                  n=0    // 7% of codewords can be restored
     **                                  n=1    // 15% of codewords can be restored
     **                                  n=2    // 25% of codewords can be restored
     **                                  n=3    // 30% of codewords can be restored
     ** Returned value:          byte[]
     ****************************************************************************************/
    public byte[] setQRcodeErrorCorrection(char ucErrorCorrectionLevel)
    {
        byte [] buf	 = new byte[]{0x1D,0x28,0x6B,0x03,0x00,0x31,0x45,0x00};
        buf[7] = (byte)ucErrorCorrectionLevel; //0x00,0x01,0x02,0x03
        return buf;
    }


    /****************************************************************************************
     ** Function name:        transferQRcodeData
     ** Descriptions:            This function is used to transfer data and QR encode
     ** input parameters:    Please check documentation for function details
     **                                  usBufferSize: size of buffer
     **                                  pucDataBuf: starting address of the data buffer
     ** Returned value:        byte[]
     ****************************************************************************************/
    public byte[] transferQRcodeData (char usbufferSize, byte [] ucDataBuf)
    {
        byte [] buf	 = new byte[]{0x1D,0x28,0x6B,0x00,0x00,0x31,0x50,0x30};

        char usCompleteBufferwithFunc;
        usCompleteBufferwithFunc = (char)(usbufferSize+3);
        //we need to add 3 bytes for the control function parameters for pL and pH
        //to the passed usBufferSize
        // they represent: cn=0x31, fn=0x50, m=0x30
        buf[3] = (byte)(usCompleteBufferwithFunc & 0xFF); // pL
        buf[4] = (byte)((usCompleteBufferwithFunc >> 8) & 0xFF);// pH

        byte [] databuf = new byte[ucDataBuf.length+buf.length];

        System.arraycopy(buf, 0, databuf, 0, buf.length);
        System.arraycopy(ucDataBuf, 0, databuf, buf.length, ucDataBuf.length);
        return databuf;
    }


    /****************************************************************************************
     ** Function name:        printQRcodeData
     ** Descriptions:            This function is used to print the QR code buffer
     ** input parameters:     none
     ** Returned value:        byte[]
     ****************************************************************************************/
    public byte[] printQRcodeData ()
    {
        byte [] buf	 = new byte[]{0x1D,0x28,0x6B,0x03,0x00,0x31,0x51,0x30};
        return buf;
    }


    /****************************************************
     *
     *
     *
     * HELPER FUNCTIONS
     *
     *
     */

    /*Android Bitmap Helper*/
    public byte[] initImageCommand(int bytesByLine, int bitmapHeight) {
        int
                xH = bytesByLine / 256,
                xL = bytesByLine - (xH * 256),
                yH = bitmapHeight / 256,
                yL = bitmapHeight - (yH * 256);

        byte[] imageBytes = new byte[8 + bytesByLine * bitmapHeight];
        System.arraycopy(new byte[]{0x1D, 0x76, 0x30, 0x00, (byte) xL, (byte) xH, (byte) yL, (byte) yH}, 0, imageBytes, 0, 8);
        return imageBytes;
    }

    /**
     * Convert Bitmap instance to a byte array compatible with ESC/POS printer.
     *
     * @param bitmap Bitmap to be convert
     * @return Bytes contain the image in ESC/POS command
     */
    public byte[] printBitmapToBytes(Bitmap bitmap) {
        int
                bitmapWidth = bitmap.getWidth(),
                bitmapHeight = bitmap.getHeight(),
                bytesByLine = (int) Math.ceil(((float) bitmapWidth) / 8f);

        byte[] imageBytes = initImageCommand(bytesByLine, bitmapHeight);

        int i = 8;
        for (int posY = 0; posY < bitmapHeight; posY++) {
            for (int j = 0; j < bitmapWidth; j += 8) {
                StringBuilder stringBinary = new StringBuilder();
                for (int k = 0; k < 8; k++) {
                    int posX = j + k;
                    if (posX < bitmapWidth) {
                        int color = bitmap.getPixel(posX, posY),
                                r = (color >> 16) & 0xff,
                                g = (color >> 8) & 0xff,
                                b = color & 0xff;

                        if (r > 160 && g > 160 && b > 160) {
                            stringBinary.append("0");
                        } else {
                            stringBinary.append("1");
                        }
                    } else {
                        stringBinary.append("0");
                    }
                }
                imageBytes[i++] = (byte) Integer.parseInt(stringBinary.toString(), 2);
            }
        }

        return imageBytes;
    }


    /**
     * Convert Bitmap instance to a byte array compatible with ESC/POS printer.
     *
     * @param bitmap Bitmap to be convert
     * @return Bytes contain the image in ESC/POS command
     */
    public byte[] bitmapToBytes(Bitmap bitmap) {
        int
                bitmapWidth = bitmap.getWidth(),
                bitmapHeight = bitmap.getHeight(),
                bytesByLine = (int) Math.ceil(((float) bitmapWidth) / 8f);

        byte[] imageBytes = new byte[128];

        int i = 8;
        for (int posY = 0; posY < bitmapHeight; posY++) {
            for (int j = 0; j < bitmapWidth; j += 8) {
                StringBuilder stringBinary = new StringBuilder();
                for (int k = 0; k < 8; k++) {
                    int posX = j + k;
                    if (posX < bitmapWidth) {
                        int color = bitmap.getPixel(posX, posY),
                                r = (color >> 16) & 0xff,
                                g = (color >> 8) & 0xff,
                                b = color & 0xff;

                        if (r > 160 && g > 160 && b > 160) {
                            stringBinary.append("0");
                        } else {
                            stringBinary.append("1");
                        }
                    } else {
                        stringBinary.append("0");
                    }
                }
                imageBytes[i++] = (byte) Integer.parseInt(stringBinary.toString(), 2);
            }
        }

        return imageBytes;
    }


    public static int calculateInSampleSize(
            BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {

            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) >= reqHeight
                    && (halfWidth / inSampleSize) >= reqWidth) {
                inSampleSize *= 2;
            }
        }

        return inSampleSize;
    }


    public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
                                                         int reqWidth, int reqHeight) {

        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, resId, options);

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(res, resId, options);
    }

    /*********************************************************************************************************
     ** Function name:           enterSleepMode
     ** Descriptions:            puts the controller into low power mode
     ** Return value:            none
     ** Note:                    Send any command to wake up the controller, then continue to print
     *********************************************************************************************************/
    public byte[] enterSleepMode ()
    {
        byte [] buf	 = new byte[]{0x10,0x16};//Power Management command.
        return buf;
    }



    public Bitmap loadImageBitmap(Context context, String name, String extension){
        name = name + "." + extension;
        FileInputStream fileInputStream;
        Bitmap bitmap = null;
        try{
            fileInputStream = context.openFileInput(name);
            bitmap = BitmapFactory.decodeStream(fileInputStream);
            fileInputStream.close();
        } catch(Exception e) {
            e.printStackTrace();
        }
        return bitmap;
    }

}
