package com.printer.demo.utils;

import android.annotation.SuppressLint;
import android.content.Context;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;

//import com.printer.sdk.BT.ReadDataFromBT;
import androidx.annotation.RequiresApi;

import com.printer.sdk.Barcode;
import com.printer.sdk.utils.XLog;
//import com.printer.sdk.net.ReadDataFromNET;
//import com.printer.sdk.usb.ReadDataFromUSB;
//import com.sprt.yxz.printservice.Utils.XLog;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.util.HashMap;

/**
 * Created by yangxuezhi on 2019-10-18.
 */

public class Printer {
    private static final int MESSAGE_NO_PRINTER = 0;
    private static final int EXCEPTION_PERMISSION = 1;
    private static final int FAIL_TO_PERMISSION = 2;
    private static final int SUCCESS_TO_OPEN_USB = 3;
    private static final int FAIL_TO_OPEN_USB = 4;
    private static final int SUCCESS_TO_INIT_SOURCE = 5;
    private static final int CLOSE_SOURCE = 6;
    public static boolean isServiceStarted;

    private Context mContext;
    private UsbManager mUsbManager;
    private UsbDevice mUsbDevice = null;
    private UsbDeviceConnection connection;
    private UsbInterface usbInterface;
    private UsbEndpoint EP1EndPoint_IN;
    private UsbEndpoint EP1EndPoint_OUT;
    private UsbEndpoint EP2EndPoint_IN;
    private UsbEndpoint EP2EndPoint_OUT;
    private final int NUM_EP1EndPoint_OUT = 0x01;
    private final int NUM_EP2EndPoint_OUT = 0x02;
    private final int NUM_EP1EndPoint_IN = 0x81;
    private final int NUM_EP2EndPoint_IN = 0x82;
    private static final int SPRTVID1 = 0x0483;
    private static final int SPRTPID1 = 0x5720;
    private static final int SPRTVID2 = 0x067B;
    private static final int SPRTPID2 = 0x2305;
    private static final int SPRTVID3 = 0x6868;
    private static final int SPRTPID3 = 0x0200;
    private static final int USB_MAX_NUMBER = 16 * 1024;
    private final String TAG = "Printer";
    public static Printer mPrinter;
    //请求USB权限
    private static final String ACTION_USB_PERMISSION = "com.android.usb.USB_PERMISSION";

    private Handler mHandler = new Handler(Looper.getMainLooper()) {
        @SuppressLint("ShowToast")
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MESSAGE_NO_PRINTER:
                    Toast.makeText(mContext, "没有找到打印机", Toast.LENGTH_LONG).show();
                    break;
                case EXCEPTION_PERMISSION:
                    Toast.makeText(mContext, "USB申请权限异常", Toast.LENGTH_LONG).show();
                    break;
                case FAIL_TO_PERMISSION:
                    Toast.makeText(mContext, "USB申请权限失败", Toast.LENGTH_LONG).show();
                    break;
                case SUCCESS_TO_OPEN_USB:
                    //Toast.makeText(mContext, "USB开口成功", Toast.LENGTH_LONG).show();
                    break;
                case FAIL_TO_OPEN_USB:
                    Toast.makeText(mContext, "USB开口失败", Toast.LENGTH_LONG).show();
                    break;
                case SUCCESS_TO_INIT_SOURCE:
                    Toast.makeText(mContext, "初始化资源成功", Toast.LENGTH_LONG).show();
                    break;
                case CLOSE_SOURCE:
                    Toast.makeText(mContext, "关闭所有资源", Toast.LENGTH_LONG).show();
                    break;
                default:
                    break;
            }

        }

    };

    @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB_MR1)
    private Printer(Context context) {
        mContext = context.getApplicationContext();
        mUsbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
        //获取mUsbDevice对象
        HashMap<String, UsbDevice> devices = mUsbManager.getDeviceList();
        for (UsbDevice device : devices.values()) {
            if (isUsbPrinter(device)) {
                mUsbDevice = device;
                break;
            }
        }
        //  XLog.d(mContext, TAG, "yxz at Printer.java 实例化Printer对象");
    }

    @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB_MR1)
    public static synchronized Printer getInstance(Context context) {
        if (mPrinter == null) {
            mPrinter = new Printer(context);
        }
        return mPrinter;
    }


    /**
     * 关闭当前USB连接，释放资源
     */
    @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB_MR1)
    public void close() {
        if (connection != null) {
            closeThreadPool();
        }
        closeUSB();
    }

    @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB_MR1)
    public synchronized int readData(byte[] buffer, int timeout) {
        int readLen = 0;
        if (connection == null)
            return readLen;
        readLen = connection.bulkTransfer(EP1EndPoint_IN, buffer, buffer.length, timeout);
        return readLen;
    }

    @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB_MR1)
    public synchronized int writeData(byte[] srcData, int len, int timeout) {
        int writLen = 0;
        if (connection == null)
            return writLen;
        writLen = connection.bulkTransfer(EP1EndPoint_OUT, srcData, len, timeout);
        return writLen;
    }

    @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB_MR1)
    public synchronized int proResposePrinter(byte[] srcData, int len, int timeout) {

        int writLen = 0;
        if (connection == null)
            return writLen;
        writLen = connection.bulkTransfer(EP1EndPoint_OUT, srcData, len, timeout);
        return writLen;

    }


    @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB_MR1)
    public synchronized int readPrinter(byte[] buffer, int timeout) {
        int readLen = 0;
        if (connection == null)
            return readLen;
        readLen = connection.bulkTransfer(EP2EndPoint_IN, buffer, buffer.length, timeout);
        return readLen;
    }

    @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB_MR1)
    public synchronized int writePrinter(byte[] srcData, int len, int timeout) {
        int writLen = 0;
        if (connection == null) {
            XLog.e(TAG, "connection==null");
            return writLen;
        }

        // USB方式android端限制，单包通信数据最大为16kb。
        int packetSize = 1024 * 16;
        int num = srcData.length / packetSize;
        byte pack[] = new byte[packetSize];
        byte temp[] = new byte[srcData.length - packetSize * num];
        if (num >= 1) {
            for (int i = 0; i <= num - 1; i++) {
                System.arraycopy(srcData, i * packetSize, pack, 0, packetSize);
                writLen = connection.bulkTransfer(EP2EndPoint_OUT, pack, pack.length, timeout);
                try {
                    Thread.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.arraycopy(srcData, num * packetSize, temp, 0, srcData.length - packetSize * num);
            if (connection.bulkTransfer(EP2EndPoint_OUT, temp, temp.length, timeout) < 0) {
                XLog.e(TAG, "yxz at PrinterInstance.java sendBytesData() sendBytesData failed! USBPort 第" + num
                        + "包发送失败");
                return -3;
            }
        } else {
            if (connection.bulkTransfer(EP2EndPoint_OUT, srcData, srcData.length, timeout) < 0) {
                XLog.e(TAG, "yxz at PrinterInstance.java sendBytesData() sendBytesData failed! USBPort 第" + num
                        + "包发送失败");
                return -3;
            }
        }

        return srcData.length;
    }

    public int printText(String content) {
        byte[] data;
        try {
            data = content.getBytes("gbk");
        } catch (UnsupportedEncodingException var4) {
            var4.printStackTrace();
            data = content.getBytes();
        }
        return this.writePrinter(data, data.length, 200);
    }


    @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB_MR1)
    public int setFont(int mCharacterType, int mWidth, int mHeight, int mBold, int mUnderline) {
        byte mFontSize = 0;
        byte mFontMode = 0;
        if (mBold != 0 && mBold != 1) {
            mBold = 0;
        }
        mFontMode |= (mBold << 3);// 选择加粗模式
        if (mUnderline != 0 && mUnderline != 1) {
            mUnderline = 0;
        }
        mFontMode |= (mUnderline << 7);// 选择下划线模式
        if (mCharacterType != 0 && mCharacterType != 1) {
            mCharacterType = 0;// 12*24字体
        }
        mFontMode |= (mCharacterType << 0);
        writePrinter(new byte[]{29, 33, mFontMode}, 3, 100);
        if (mWidth < 0 || mWidth > 7) {
            mWidth = 0;
        }
        mFontSize |= (mWidth << 4);
        if (mHeight < 0 | mHeight > 7) {
            mHeight = 0;
        }
        mFontSize |= mHeight;
        return writePrinter(new byte[]{29, 33, mFontSize}, 3, 100);// 选择字符大小
    }

    @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB_MR1)
    public void setPrinter(int command, int value) {

        byte[] arrayOfByte = new byte[3];
        switch (command) {
            case 0:
                arrayOfByte[0] = 27;
                arrayOfByte[1] = 74;
                break;
            case 1:
                arrayOfByte[0] = 27;
                arrayOfByte[1] = 100;
            case 2:
            case 3:
            case 5:
            case 6:
            case 7:
            case 8:
            case 9:
            case 10:
            case 12:
            default:
                break;
            case 4:
                arrayOfByte[0] = 27;
                arrayOfByte[1] = 86;
                break;
            case 11:
                arrayOfByte[0] = 27;
                arrayOfByte[1] = 32;
                break;
            case 13:
                arrayOfByte[0] = 27;
                arrayOfByte[1] = 97;
                if (value > 2 || value < 0) {
                    value = 0;
                }
        }

        arrayOfByte[2] = (byte) value;
        this.writePrinter(arrayOfByte, arrayOfByte.length, 100);
    }

    public int printBarCode(Barcode barcode) {
        return this.writePrinter(barcode.getBarcodeData(), barcode.getBarcodeData().length, 200);
    }

    /**
     * @param srcData
     * @return -100连接失败
     * <=0写数据失败
     * >0写成功的数据长度
     * @throws Exception
     */
//    public int usbWriteData(byte[] srcData)  {
//        // USB方式android端限制，单包通信数据最大为16kb。
//        int packetSize = USB_MAX_NUMBER;
//        int num = srcData.length / packetSize;
//        byte pack[] = new byte[packetSize];
//        byte temp[] = new byte[srcData.length - packetSize * num];
//        int totalLen = 0;
//        if (num >= 1) {
//            for (int i = 0; i <= num - 1; i++) {
//                System.arraycopy(srcData, i * packetSize, pack, 0, packetSize);
//                int writeLen = writePrinter(pack, pack.length,0);
//                if (writeLen<0) {
//                    return writeLen;
//                }
//                totalLen += writeLen;
//            }
//            System.arraycopy(srcData, num * packetSize, temp, 0, srcData.length - packetSize * num);
//            int tempLen = writePrinter(temp, temp.length,0);
//            if (tempLen < 0) {
//                return tempLen;
//            }
//            totalLen += tempLen;
//        } else {
//            return writePrinter(srcData, srcData.length,0);
//        }
//        return totalLen;
//    }

    /**
     * 判断USB设备是不是SPRT打印机
     *
     * @param device USB设备对象
     * @return true 是  false 不是
     */
    @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB_MR1)
    public static boolean isUsbPrinter(UsbDevice device) {
        if (device == null)
            return false;
        int vendorId = device.getVendorId();
        int productId = device.getProductId();
        if ((SPRTVID1 == vendorId && SPRTPID1 == productId) || (SPRTVID2 == vendorId && SPRTPID2 == productId) || (SPRTVID3 == vendorId && SPRTPID3 == productId))
            return true;
        else
            return false;
    }

    @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB_MR1)
    public boolean initUSB() {
        boolean result = openUSB();
        Log.e(TAG, "initUSB = " + result);
        if (result) {
            runThreadPool();
        }
        return result;
    }

    public void runThreadPool() {
        Log.e("ThreadError", "Thread----------- runThreadPool----");
//        ReadDataFromNET.getInstance(mContext).start();
//        ReadDataFromBT.getInstance(mContext).start();
//        ReadDataFromUSB.getInstance(mContext).start();
//        Core.getInstance(mContext).start();
        isServiceStarted = true;
        XLog.d(TAG, "yxz at Printer.java runThreadPool() 启动线程池");
        this.mHandler.obtainMessage(SUCCESS_TO_INIT_SOURCE).sendToTarget();
        mPrinter.writePrinter(new byte[]{0x1d, 0x49, 0x44}, 3, 100); //huoqu sn;
        Log.d("handerson", "wirte printer");
    }

    public void closeThreadPool() {
        //停止所有通信口（USB,NET,BT）的读写线程，数据解析线程（Core）
        XLog.d(TAG, "closeThreadPool: 停止所有通信口（USB,NET,BT）的读写线程，数据解析线程");
//        ReadDataFromNET.getInstance(mContext).MyInterrupt();
//        ReadDataFromBT.getInstance(mContext).MyInterrupt();
//        ReadDataFromUSB.getInstance(mContext).MyInterrupt();
//        Core.getInstance(mContext).MyInterrupt();
        isServiceStarted = false;
        this.mHandler.obtainMessage(CLOSE_SOURCE).sendToTarget();
        XLog.d(TAG, "yxz at Printer.java closeThreadPool() 关闭线程池");
    }

    //20200607  yxz  升级打印机固件时的开口操作
    @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB_MR1)
    public boolean openUSB() {
        //如果当前开口，则关闭端口
        XLog.d("yxz", "如果当前开口，则关闭端口  connection : " + connection);
        close();
        //获取mUsbDevice对象
        mUsbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
        HashMap<String, UsbDevice> devices = mUsbManager.getDeviceList();
        for (UsbDevice device : devices.values()) {
            if (isUsbPrinter(device)) {
                mUsbDevice = device;
                break;
            }
        }
        if (mUsbDevice == null || mUsbManager == null || !isUsbPrinter(mUsbDevice)) {
            XLog.d(TAG, "yxz at Printer.java openUSB() 没有找到打印机");
            this.mHandler.obtainMessage(MESSAGE_NO_PRINTER).sendToTarget();
            return false;
        }
        //获取权限代码
        try {
            Class c;
            c = Class.forName("android.hardware.usb.UsbManager");
            Method m = c.getMethod("grantPermission", new Class[]{UsbDevice.class});
            Object o = m.invoke(mUsbManager, new Object[]{mUsbDevice});
            XLog.d(TAG, "yxz at Printer.java openUSB() 申请权限成功");
        } catch (Exception e) {
            e.printStackTrace();
            XLog.e(TAG, "yxz at Printer.java openUSB() 申请权限异常：e.getMessage:" + e.getMessage());
            this.mHandler.obtainMessage(EXCEPTION_PERMISSION).sendToTarget();
            return false;
        }

        //判断打印机权限
        if (!mUsbManager.hasPermission(mUsbDevice)) {
            XLog.e(TAG, "yxz at Printer.java openUSB() 申请权限失败");
            this.mHandler.obtainMessage(FAIL_TO_PERMISSION).sendToTarget();
            return false;
        }
        //打印机有权限，打开连接
        usbInterface = mUsbDevice.getInterface(0);
        connection = mUsbManager.openDevice(mUsbDevice);
        if (connection != null && connection.claimInterface(usbInterface, true)) {
            for (int i = 0; i < usbInterface.getEndpointCount(); i++) {
                // USBEndpoint为读写数据所需的节点
                UsbEndpoint ep = usbInterface.getEndpoint(i);
                if (ep.getType() != UsbConstants.USB_ENDPOINT_XFER_BULK)
                    continue;
                if (ep.getDirection() == UsbConstants.USB_DIR_OUT && ep.getAddress() == NUM_EP2EndPoint_OUT)
                    EP2EndPoint_OUT = ep;
                if (ep.getDirection() == UsbConstants.USB_DIR_IN && ep.getAddress() == NUM_EP2EndPoint_IN)
                    EP2EndPoint_IN = ep;
                if (ep.getDirection() == UsbConstants.USB_DIR_IN && ep.getAddress() == NUM_EP1EndPoint_IN)
                    EP1EndPoint_IN = ep;
                if (ep.getDirection() == UsbConstants.USB_DIR_OUT && ep.getAddress() == NUM_EP1EndPoint_OUT)
                    EP1EndPoint_OUT = ep;
            }
            this.mHandler.obtainMessage(SUCCESS_TO_OPEN_USB).sendToTarget();
            return true;
        } else {
            XLog.e(TAG, "yxz at Printer.java openUSB() 打开USB失败,connection:" + connection);
            this.mHandler.obtainMessage(FAIL_TO_OPEN_USB).sendToTarget();
            return false;
        }

    }

    /**
     * 关闭当前USB连接，释放资源
     */
    @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB_MR1)
    public void closeUSB() {
        mUsbManager = null;
        mUsbDevice = null;
        if (connection != null) {
            connection.releaseInterface(usbInterface);
            // 只能关闭一次
            connection.close();
            connection = null;
            usbInterface = null;
            EP1EndPoint_IN = null;
            EP1EndPoint_OUT = null;
            EP2EndPoint_IN = null;
            EP2EndPoint_OUT = null;
            XLog.d(TAG, "yxz at Printer.java closeUSB() 关闭u口");
        }
    }


}
