package com.miya.print;

import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.text.TextUtils;
import android.util.Log;

import com.miya.print.exception.PrinterException;
import com.miya.print.utils.BitmapUtils;
import com.miya.print.utils.ESCUtil;
import com.miya.print.utils.PrintLogger;
import com.miya.print.utils.ImageUtils;
import com.miya.print.utils.QRCodeUtil;
import com.printsdk.cmd.PrintCmd;
import com.printsdk.usbsdk.UsbDriver;

/**
 * 创捷打印驱动
 */
public class ChuangjiePrinter extends BasePrinter {

    private final static String TAG = ChuangjiePrinter.class.getSimpleName();

    private final static int PID11 = 8211;
    private final static int PID13 = 8213;
    private final static int PID15 = 8215;
    private final static int VENDORID = 1305;

    private UsbDriver mUsbDriver;
    private UsbManager mUsbManager;
    public UsbDevice mUsbDev1;   // 内置打印机
    public UsbDevice mUsbDev2;   // usb标签打印机
    public UsbDevice mUsbDev;    // 公共打印机
    private static final String ACTION_USB_PERMISSION = "com.usb.sample.USB_PERMISSION";

    /**
     * 字体大小，用于防止重复设置
     */
    int textSize = -1;

    @Override
    public boolean init(Context context) {
        PrintLogger.i(TAG, "开始初始化创捷打印机");
        this.context = context;
        if (mUsbDriver == null) {
            getUsbDriverService(context);
        }
        // USB线已经连接
        getUsbDriverService();
        return connet() == PrinterStatusEnum.CODE_SUCCESS.status;
    }

    @Override
    public int beginPrint() {
        return super.beginPrint();
    }

    @Override
    public int printText(int align, int size, String content, boolean isFeed) {
        int ret;
        if (textSize != size) {
            textSize = size;
            ret = setSizeText(size, size);
        }
        ret = setAlign(align);
        ret = printString(content);
        //创捷机器打印完后会强制走纸一行，这里不再判断是否走纸标志
        return ret;
    }

    @Override
    public int cutPaper() {
        if (null != mUsbDriver && null != mUsbDev) {
            int ret = mUsbDriver.write(PrintCmd.printFeedline(5));
            ret = mUsbDriver.write(PrintCmd.cutPage(0), mUsbDev);
            return ret;
        }
        return -1;
    }

    @Override
    public boolean release() {
        try {
            if (mUsbDriver != null && mUsbDev != null) {
                if (mUsbDriver.isConnected()) {
                    if (null != mUsbDev) {
                        mUsbDriver.disconnet(mUsbDev);
                    }
                }
                mUsbDev = null;
                mUsbDriver = null;
                context = null;
            }
            PrintLogger.i(TAG, "创捷打印资源已关闭");
            return true;
        } catch (Exception ex) {
            ex.printStackTrace();
            PrintLogger.e(TAG, ex.getMessage());
        }
        return false;
    }

    @Override
    public int getPrinterStatus() {
        if (mUsbDev != null) {
            status = getPrinterStatus(mUsbDev);
        }
        return status;
    }

    /**
     * 0 打印机正常
     * 1 打印机未连接或未上电
     * 2 打印机和调用库不匹配
     * 3 打印头打开
     * 4 切刀未复位
     * 5 打印头过热
     * 6 黑标错误
     * 7 纸尽
     * 8 纸将尽
     *
     * @return
     */
    public synchronized int connet() {
        int conState = -1;
        //有时候会出现mUsbDev为空，但是mUsbDriver还在连接的情况
        if (null == mUsbDev) {
            if (mUsbDriver.isConnected()) {
                mUsbDriver.disconnet();
            }
        }
        getUsbDriverService();
        //获取连接状态
        if (null != mUsbDev) {
            conState = getPrinterStatus(mUsbDev);
        }
        return conState;
    }


    public boolean isConnect() {
        if (null != mUsbDev) {
            return mUsbDriver.isConnected();
        }
        return false;
    }

    public String getErrMsgByConnectState(int connectState) {
        switch (connectState) {
            case 0:
                return "打印机正常";
            case 1:
                return "打印机未连接或未上电";
            case 2:
                return "打印机和调用库不匹配";
            case 3:
                return "打印头打开";
            case 4:
                return "切刀未复位";
            case 5:
                return "打印头过热";
            case 6:
                return "黑标错误";
            case 7:
                return "纸尽";
            case 8:
                return "纸将尽";
        }
        return "";
    }


    public synchronized int disconnet() {
        int conState = -1;
        if (mUsbDriver.isConnected()) {
            if (null != mUsbDev) {
                mUsbDriver.disconnet(mUsbDev);
                conState = getPrinterStatus(mUsbDev);
            }
        }
        return conState;
    }


    public int getStatus() {
        int conState = -1;
        if (null != mUsbDev) {
            conState = getPrinterStatus(mUsbDev);
        }
        return conState;
    }


    public void setCharset(int country, int CPnumber) {
        if (null != mUsbDriver && null != mUsbDev) {
            mUsbDriver.write(PrintCmd.setCharset(country, CPnumber), mUsbDev);
        }
    }

    /**
     * 0是居左边
     *
     * @param iAlignment
     */
    public int setAlignMode(int iAlignment) {
        if (null != mUsbDriver && null != mUsbDev) {
            return mUsbDriver.write(PrintCmd.setAlignMode(iAlignment), mUsbDev);
        }
        return -1;
    }


    public int LF() {
        if (null != mUsbDriver && null != mUsbDev) {
            return mUsbDriver.write(PrintCmd.LF(), mUsbDev);
        }
        return -1;
    }


    public void setEnableUnderLine(int underline) {
        if (null != mUsbDriver && null != mUsbDev) {
            mUsbDriver.write(PrintCmd.setEnableUnderLine(underline), mUsbDev);
        }
    }


    public void setLeftAndRightMargin(int iMargin) {
        if (null != mUsbDriver && null != mUsbDev) {
            mUsbDriver.write(PrintCmd.setLeftAndRightMargin(iMargin), mUsbDev);
        }
    }


    public void setLeftMargin(int iMargin) {
        if (null != mUsbDriver && null != mUsbDev) {
            mUsbDriver.write(PrintCmd.setLeftMargin(iMargin), mUsbDev);
        }
    }


    public void setLineSpace(int iLinespace) {
        if (null != mUsbDriver && null != mUsbDev) {
            mUsbDriver.write(PrintCmd.setLineSpace(iLinespace), mUsbDev);
        }
    }

    /**
     * 切纸
     *
     * @param iMode 0==>全切；1==>半切
     */
    public void cutPage(int iMode) {
        if (null != mUsbDriver && null != mUsbDev) {
            mUsbDriver.write(PrintCmd.printFeedline(5));
            mUsbDriver.write(PrintCmd.cutPage(iMode), mUsbDev);
        }
    }

    @Override
    public int printImage(int align, Bitmap bm, boolean isFeed) {
        if (bm == null) {
            return PrinterStatusEnum.CODE_FAILED.getStatus();
        }
        int ret = setAlign(align);
        Bitmap actualBm = null;
        if (bm.getWidth() > MAX_IMG_WIDTH_80MM) {
            actualBm = BitmapUtils.scaleBitmap(bm, MAX_IMG_WIDTH_80MM, 0);
            ret = printQrcodeBitmap(actualBm);
        } else {
            if (this.align == 1) {
                //如果是居中打印，则拼接白色左边距
                actualBm = BitmapUtils.addWhiteLeftMargin(bm, (MAX_IMG_WIDTH_80MM - bm.getWidth()) / 2);
                ret = printQrcodeBitmap(actualBm);
            } else if (this.align == 2) {
                //居右打印
                actualBm = BitmapUtils.addWhiteLeftMargin(bm, MAX_IMG_WIDTH_80MM - bm.getWidth());
                ret = printQrcodeBitmap(actualBm);
            } else {
                //居左打印
                ret = printQrcodeBitmap(bm);
            }
        }
        if (actualBm != null) {
            actualBm.recycle();
        }
        if (isFeed) {
            feedPaper();
        }
        return ret;
    }

    /**
     * 打印二维码
     * 注：由于机器限制，此方法无法居右打印二维码，当选择居右打印时，仍会居左打印二维码
     *
     * @param align
     * @param content
     * @param isFeed
     * @return
     */
    @Override
    public int printQrcode(int align, String content, boolean isFeed) {
        int ret = setAlign(align);
        Bitmap qrBm = QRCodeUtil.createQRCodeBitmap(content, 220);
        if (qrBm != null) {
            ret = printImage(align, qrBm, true);
            qrBm.recycle();
        } else {
            throw new PrinterException(PrinterStatusEnum.CODE_FAILED.status, PrinterStatusEnum.CODE_FAILED.desc);
        }
//        //创捷机器打印二维码不能通过setAlign实现居中，永远会居左打印
//        if (this.align == 0) {
//            //居左打印
//            ret = printQrcode(content, 0, 6, 1);
//        } else if (this.align == 1) {
//            //居中打印
//            ret = printQrcode(content, 24, 6, 1);
//        } else if (this.align == 2) {
//            //居右
//            ret = printQrcode(content, 24, 6, 1);
//        }
//        if (isFeed) {
//            ret = feedPaper();
//        }
        return ret;
    }

    @Override
    public int printBarcode(int align, String content, boolean isFeed) {
        int ret = setAlign(align);
        //创捷机器打印条码只能居左、居中打印,并且内部会强制走纸
        ret = printBarCode(content);
        return ret;
    }

    @Override
    public int feedPaper() {
        return LF();
    }

    @Override
    public int setAlign(int align) {
        int ret = PrinterStatusEnum.CODE_SUCCESS.getStatus();
        if (this.align != align &&
                (align == 0 || align == 1 || align == 2)) {
            ret = setAlignMode(align);
            this.align = align;
        }
        return ret;
    }

    public int printBarCode(String barcode) {
        int printState = -1;
        if (null != mUsbDriver && null != mUsbDev) {
            printState = mUsbDriver.write(PrintCmd.printBarCode(2, 120, 0, 2, 10, barcode), mUsbDev);// 一维条码打印
        }
        return printState;
    }


    public int printBarCode(String barcode, int codeType) {
        int printState = -1;
        if (null != mUsbDriver && null != mUsbDev) {
            printState = mUsbDriver.write(PrintCmd.printBarCode(2, 120, 0, 2, codeType, barcode), mUsbDev);// 一维条码打印
        }
        return printState;
    }

    /**
     * 打印二维码
     *
     * @param StrData  内容
     * @param iLmargin 左边距，取值0-27 单位mm
     * @param iMside   单位长度，即QR码大小，取值1-8，（有些打印机型只支持1-4）
     * @param iRound   环绕模式，0环绕（混排，有些机型不支持）、1立即打印（不混排）
     * @return
     */
    @Deprecated
    public int printQrcode(String StrData, int iLmargin, int iMside, int iRound) {
        int printState = -1;
        if (null != mUsbDriver && null != mUsbDev) {
            printState = mUsbDriver.write(PrintCmd.printQrcode(StrData, iLmargin, iMside, iRound), mUsbDev);
        }
        return printState;
    }

    /**
     * 打印图片
     *
     * @param data 源图片
     * @return
     */
    @Deprecated
    public int printQrcodeBitmap(Bitmap data) {
        int printState = -1;
        if (null != mUsbDriver && null != mUsbDev) {
            Bitmap bm = ImageUtils.getSinglePic(data);
            int[] pixData = ImageUtils.getPixelsByBitmap(bm);
            printState = mUsbDriver.write(PrintCmd.printQrcodeBitmap(pixData, data.getWidth(), data.getHeight()));
            if (bm != null) {
                bm.recycle();
            }
        }
        return printState;
    }


    /**
     * 设置放大倍数
     *
     * @param width  取值0～8，取为0时代表默认大小
     * @param height 取值0～8，取为0时代表默认大小
     * @return
     */
    public int setSizeText(int width, int height) {
        int printState = -1;
        if (null != mUsbDriver && null != mUsbDev) {
            printState = mUsbDriver.write(PrintCmd.setSizeText(width, height), mUsbDev);
        }
        return printState;
    }


    public int printString(String data) {
        int printState = -1;
        if (null != mUsbDriver && null != mUsbDev) {
            if (TextUtils.isEmpty(data)) {
                data = "";
            }
            printState = mUsbDriver.write(PrintCmd.printString(data, 0), mUsbDev);// 一维条码打印
        }
        return printState;
    }


    public int printStringByBytes(byte[] data) {
        int printState = -1;
        if (null != mUsbDriver && null != mUsbDev) {
            printState = mUsbDriver.write(data, mUsbDev);// 一维条码打印
        }
        return printState;
    }


    public void setEnableBold(int iBold) {
        if (null != mUsbDriver && null != mUsbDev) {
            mUsbDriver.write(PrintCmd.setEnableBold(iBold), mUsbDev);
        }
    }


    /**
     * 获取UsbDriverService服务
     *
     * @return
     */
    private boolean getUsbDriverService() {
        boolean blnRtn = false;
        try {
            if (!mUsbDriver.isConnected()) {
                // USB线已经连接
                for (UsbDevice device : mUsbManager.getDeviceList().values()) {
                    if ((device.getProductId() == PID11 && device.getVendorId() == VENDORID)
                            || (device.getProductId() == PID13 && device.getVendorId() == VENDORID)
                            || (device.getProductId() == PID15 && device.getVendorId() == VENDORID)) {
                        blnRtn = mUsbDriver.usbAttached(device);
                        if (blnRtn == false) {
                            break;
                        }
                        blnRtn = mUsbDriver.connect(device);
                        // 打开设备
                        if (blnRtn) {
                            //内置打印机
                            if (device.getProductId() == PID11) {
                                mUsbDev1 = device;
                                mUsbDev = mUsbDev1;
                            } else {//USB打印机
                                mUsbDev2 = device;
                                mUsbDev = mUsbDev2;
                                PrintLogger.i(TAG, "USB连接成功");
                                break;
                            }
                        } else {
                            PrintLogger.i(TAG, "USB连接失败");
                            break;
                        }
                    }
                }
            } else {
                blnRtn = true;
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return blnRtn;
    }


    public void initPrint(Context context) {
        this.context = context;
        if (mUsbDriver == null) {
            getUsbDriverService(context);
        }
        // USB线已经连接
        getUsbDriverService();
    }

    /**
     * 初始化设备
     *
     * @param context
     */
    private void getUsbDriverService(Context context) {
        mUsbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
        mUsbDriver = new UsbDriver(mUsbManager, context);
        PendingIntent permissionIntent1 = PendingIntent.getBroadcast(context, 0,
                new Intent(ACTION_USB_PERMISSION), 0);
        mUsbDriver.setPermissionIntent(permissionIntent1);
        // Broadcast listen for new devices
        IntentFilter filter = new IntentFilter();
        filter.addAction(ACTION_USB_PERMISSION);
        filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
        filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
        context.registerReceiver(mUsbReceiver, filter);
    }

    /**
     * 0 打印机正常
     * 1 打印机未连接或未上电
     * 2 打印机和调用库不匹配
     * 3 打印头打开
     * 4 切刀未复位
     * 5 打印头过热
     * 6 黑标错误
     * 7 纸尽
     * 8 纸将尽
     *
     * @param usbDev
     * @return
     */
    private int getPrinterStatus(UsbDevice usbDev) {
        int iRet = -1;
        byte[] bRead1 = new byte[1];
        byte[] bWrite1 = PrintCmd.getStatus1();
        if (mUsbDriver.read(bRead1, bWrite1, usbDev) > 0) {
            iRet = PrintCmd.checkStatus1(bRead1[0]);
        }

        if (iRet != 0)
            return iRet;

        byte[] bRead2 = new byte[1];
        byte[] bWrite2 = PrintCmd.getStatus2();
        if (mUsbDriver.read(bRead2, bWrite2, usbDev) > 0) {
            iRet = PrintCmd.checkStatus2(bRead2[0]);
        }

        if (iRet != 0)
            return iRet;

        byte[] bRead3 = new byte[1];
        byte[] bWrite3 = PrintCmd.getStatus3();
        if (mUsbDriver.read(bRead3, bWrite3, usbDev) > 0) {
            iRet = PrintCmd.checkStatus3(bRead3[0]);
        }

        if (iRet != 0)
            return iRet;

        byte[] bRead4 = new byte[1];
        byte[] bWrite4 = PrintCmd.getStatus4();
        if (mUsbDriver.read(bRead4, bWrite4, usbDev) > 0) {
            iRet = PrintCmd.checkStatus4(bRead4[0]);
        }
        return iRet;
    }

    /**
     * 0 打印机正常
     * 1 打印机未连接或未上电
     * 2 打印机和调用库不匹配
     * 3 打印头打开
     * 4 切刀未复位
     * 5 打印头过热
     * 6 黑标错误
     * 7 纸尽
     * 8 纸将尽
     *
     * @param status
     * @return
     */
    public String getPrinterStatus(int status) {

        if (status == 0) {
            return "正常";
        }
        if (status == 1) {
            return "打印机未连接或未上电";
        }
        if (status == 2) {
            return "打印机和调用库不匹配";
        }
        if (status == 3) {
            return "打印头打开";
        }
        if (status == 4) {
            return "切刀未复位";
        }
        if (status == 5) {
            return "打印头过热";
        }
        if (status == 6) {
            return "黑标错误";
        }
        if (status == 7) {
            return "纸尽";
        }
        if (status == 8) {
            return "正常";
        }
        return "打印机未连接或未上电";
    }


    /*
     *  BroadcastReceiver when insert/remove the device USB plug into/from a USB port
     *  创建一个广播接收器接收USB插拔信息：当插入USB插头插到一个USB端口，或从一个USB端口，移除装置的USB插头
     */
    BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
                UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                if ((device.getProductId() == PID11 && device.getVendorId() == VENDORID)
                        || (device.getProductId() == PID13 && device.getVendorId() == VENDORID)
                        || (device.getProductId() == PID15 && device.getVendorId() == VENDORID)) {
                    if (mUsbDriver.usbAttached(intent)) {
                        if (device.getProductId() == PID11) {
                            mUsbDev1 = device;
                        } else {
                            mUsbDev2 = device;
                        }
                    }
                }

            } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
                UsbDevice device = (UsbDevice) intent
                        .getParcelableExtra(UsbManager.EXTRA_DEVICE);
                if ((device.getProductId() == PID11 && device.getVendorId() == VENDORID)
                        || (device.getProductId() == PID13 && device.getVendorId() == VENDORID)
                        || (device.getProductId() == PID15 && device.getVendorId() == VENDORID)) {
                    mUsbDriver.disconnet(device);
                    if (device.getProductId() == PID11)
                        mUsbDev1 = null;
                    else
                        mUsbDev2 = null;
                }
            } else if (ACTION_USB_PERMISSION.equals(action)) {
                synchronized (this) {
                    UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                        if ((device.getProductId() == PID11 && device.getVendorId() == VENDORID)
                                || (device.getProductId() == PID13 && device.getVendorId() == VENDORID)
                                || (device.getProductId() == PID15 && device.getVendorId() == VENDORID)) {
                            if (mUsbDriver.connect(device)) {
                                if (device.getProductId() == PID11)
                                    mUsbDev1 = device;
                                else
                                    mUsbDev2 = device;
                            }
                        }
                    } else {
                        Log.d(TAG, "permission denied for device " + device);
                    }
                }
            }
        }
    };
}
