package com.miya.print;

import android.content.Context;
import android.graphics.Bitmap;

import com.miya.print.exception.PrinterException;
import com.miya.print.utils.BitmapUtils;
import com.miya.print.utils.PrintLogger;
import com.miya.print.utils.PrintFormatUtils;
import com.szsicod.print.escpos.PrinterAPI;
import com.szsicod.print.io.InterfaceAPI;
import com.szsicod.print.io.SerialAPI;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;

/**
 * 桑达机器打印驱动
 */
public class SangdaPrinter extends BasePrinter {

    final static String TAG = SangdaPrinter.class.getSimpleName();

    public PrinterAPI mPrinter;
    InterfaceAPI io = null;

    @Override
    public boolean init(Context context) {
        PrintLogger.i(TAG, "开始初始化桑达打印机");
        super.init(context);
        mPrinter = PrinterAPI.getInstance();
        if (isConnect()) {
            mPrinter.disconnect();
        }
        try {
            io = new SerialAPI(new File("/dev/ttyS1"), 38400, 0);
            if (PrinterAPI.SUCCESS == mPrinter.connect(io)) {
                PrintLogger.i(TAG, "桑达打印机连接成功");
                return true;
            } else {
                PrintLogger.e(TAG, "桑达打印机连接失败");
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        PrintLogger.e(TAG, "桑达打印机连接失败");
        return false;
    }

    @Override
    public boolean release() {
        disconnect();
        return true;
    }

    @Override
    public int printText(int align, int size, String content, boolean isFeed) {
        if (mPrinter != null) {
            int ret = setAlign(align);
            try {
                ret = mPrinter.printString(content, "GBK", isFeed);
                return ret;
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                throw new PrinterException(PrinterStatusEnum.CODE_FAILED.getStatus(), e.getMessage());
            }
        } else {
            throw new PrinterException(PrinterStatusEnum.CODE_FAILED.getStatus(), PrinterStatusEnum.CODE_FAILED.getDesc());
        }
    }

    @Override
    public int printBarcode(int align, String content, boolean isFeed) {
        if (mPrinter != null) {
            int ret = setAlign(align);
            try {
                //通过printString传入打印指令实现条码的打印
                ret = mPrinter.printString(PrintFormatUtils.getBarcodeCmd(content), "GBK", isFeed);
//                ret = mPrinter.printBarCode(73, content.length(), content);
                return ret;
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                throw new PrinterException(PrinterStatusEnum.CODE_FAILED.getStatus(), e.getMessage());
            }
        } else {
            throw new PrinterException(PrinterStatusEnum.CODE_FAILED.getStatus(), PrinterStatusEnum.CODE_FAILED.getDesc());
        }
    }

    @Override
    public int printQrcode(int align, String content, boolean isFeed) {
        if (mPrinter != null) {
            int ret = setAlign(align);
            ret = mPrinter.printQRCode(content, 6, false);
            if (isFeed) {
                ret = feedPaper();
            }
            return changeStatus2Custom(ret);
        } else {
            throw new PrinterException(PrinterStatusEnum.CODE_FAILED.getStatus(), PrinterStatusEnum.CODE_FAILED.getDesc());
        }
    }

    @Override
    public int printImage(int align, Bitmap bm, boolean isFeed) {
        if (mPrinter != null && bm != null) {
            int ret = setAlign(align);
            try {
                Bitmap actualBm = BitmapUtils.scaleBitmap(bm, MAX_IMG_WIDTH_80MM, 0);
                if (bm.getWidth() > MAX_IMG_WIDTH_80MM) {
                    //如果超过阈值，则缩放至目标大小
                    ret = mPrinter.printRasterBitmap(actualBm);
                } else {
                    ret = mPrinter.printRasterBitmap(bm);
                }
                if (actualBm != null) {
                    actualBm.recycle();
                }
                changeStatus2Custom(ret);
            } catch (IOException e) {
                e.printStackTrace();
                throw new PrinterException(PrinterStatusEnum.CODE_FAILED.getStatus(), e.getMessage());
            }
            //桑达打印图片时，本身就会强制走纸一行，这里不再判断是否再走纸
            return ret;
        } else {
            throw new PrinterException(PrinterStatusEnum.CODE_FAILED.getStatus(), PrinterStatusEnum.CODE_FAILED.getDesc());
        }
    }

    @Override
    public int setAlign(int align) {
        if (mPrinter != null) {
            if (this.align != align &&
                    (align == 0 || align == 1 || align == 2)) {
                int ret = mPrinter.setAlignMode(align);
                changeStatus2Custom(ret);
                this.align = align;
            }
            return PrinterStatusEnum.CODE_SUCCESS.getStatus();
        } else {
            throw new PrinterException(PrinterStatusEnum.CODE_FAILED.getStatus(), PrinterStatusEnum.CODE_FAILED.getDesc());
        }
    }

    @Override
    public int feedPaper() {
        if (mPrinter != null) {
            int ret = mPrinter.printFeed();
            return changeStatus2Custom(ret);
        } else {
            throw new PrinterException(PrinterStatusEnum.CODE_FAILED.getStatus(), PrinterStatusEnum.CODE_FAILED.getDesc());
        }
    }

    @Override
    public int cutPaper() {
        if (mPrinter != null) {
            int ret = mPrinter.cutPaper(66, 0);
            return ret;
        } else {
            throw new PrinterException(PrinterStatusEnum.CODE_FAILED.getStatus(), PrinterStatusEnum.CODE_FAILED.getDesc());
        }
    }

    @Override
    public int getPrinterStatus() {
        if (mPrinter != null) {
            //这个方法参数中的n只能取1或49
            int ret = mPrinter.getPrinterStatus(1);
            //做一个状态对应转换，转换为自定义标准的状态码类型
            switch (ret) {
                case 0:
                    //正常状态
                    return PrinterStatusEnum.CODE_SUCCESS.status;
                case 12:
                    //缺纸
                    return PrinterStatusEnum.CODE_NO_PAPER.status;
                case 3:
                    //纸将尽
                    return PrinterStatusEnum.CODE_FEW_PAPER.status;
            }
            return PrinterStatusEnum.CODE_UNKOWN.status;
        } else {
            throw new PrinterException(PrinterStatusEnum.CODE_FAILED.getStatus(), PrinterStatusEnum.CODE_FAILED.getDesc());
        }
    }

    public PrinterAPI getPrinter() {
        return mPrinter;
    }


    public void disconnect() {
        if (mPrinter != null) {
            mPrinter.disconnect();
            mPrinter = null;
            PrintLogger.i(TAG, "桑达打印资源已经关闭");
        }
    }

    public boolean isConnect() {
        if (mPrinter != null) {
            return mPrinter.isConnect();
        }
        return false;
    }

    /**
     * 将桑达的状态码翻译成PrinterStatusEnum中的标准状态码
     * 注：内部会自动抛出不允许的异常状态
     *
     * @param status 桑达返回的状态码
     * @return PrinterStatusEnum中的标准状态码
     */
    private int changeStatus2Custom(int status) {
        if (status == 0) {
            //正常状态
            return PrinterStatusEnum.CODE_SUCCESS.status;
        }
        if (status == -1) {
            //数据传输错误,请检查连接并重新发送
            throw new PrinterException(PrinterStatusEnum.CODE_FAILED.status, "数据传输错误,请检查连接并重新发送");
        }
        if ((status & 0x200) > 0) {
            return PrinterStatusEnum.CODE_FEW_PAPER.status;
        }
        if ((status & 0x400) > 0 || (status & 0x08) > 0) {
            //缺纸
            throw new PrinterException(PrinterStatusEnum.CODE_NO_PAPER.status, PrinterStatusEnum.CODE_NO_PAPER.desc);
        }
        if ((status & 0x4) > 0) {
            //脱机状态
            throw new PrinterException(PrinterStatusEnum.CODE_NOT_CONNECTED.status, "发生错误");
        }
        if ((status & 0x20) > 0) {
            //盖板打开
            throw new PrinterException(PrinterStatusEnum.CODE_NOT_CONNECTED.getStatus(), "盖板打开");
        }
        if ((status & 0x1) > 0) {
            //脱机
            throw new PrinterException(PrinterStatusEnum.CODE_NOT_CONNECTED.status, "脱机");
        }
        if ((status & 0x100) > 0) {
            //机械错误
            throw new PrinterException(PrinterStatusEnum.CODE_FAILED.status, "机械错误");
        }
        if ((status & 0x80) > 0) {
            //不可恢复错误
            throw new PrinterException(PrinterStatusEnum.CODE_FAILED.status, "不可恢复错误");
        }
        return PrinterStatusEnum.CODE_SUCCESS.status;
    }

    @Deprecated
    public String getStatusDescribe() {
        int status = mPrinter.getStatus();
        Arrays.fill(statusList, 0);
        try {
            if (status == -1) {
                statusList[0] = 1;
                return "数据传输错误,请检查连接并重新发送";
            }
            StringBuilder builder = new StringBuilder();
            StringBuffer descriptBuffer = new StringBuffer();
            StringBuffer troubleBuffer = new StringBuffer();
            //传感应状态
            if ((status & 0x200) > 0) {
                statusList[1] = 1;
                descriptBuffer.append("少纸, ");//[1]
                troubleBuffer.append("PaperFew|");
            }

            if ((status & 0x400) > 0 || (status & 0x08) > 0) {
                statusList[2] = 1;
                descriptBuffer.append("缺纸, ");
                troubleBuffer.append("OutOfPaper|");

            }
            //脱机状态
            if ((status & 0x4) > 0) {
                descriptBuffer.append("发生错误, ");
                troubleBuffer.append("happen error|");

            }
            if ((status & 0x20) > 0) {
                statusList[4] = 1;
                descriptBuffer.append("盖板打开, ");
                troubleBuffer.append("box open|");

            }
            //打印机状态
            if ((status & 0x1) > 0) {
                statusList[3] = 1;
                descriptBuffer.append("脱机, ");
                troubleBuffer.append("Offline|");

            }
            if ((status & 0x2) > 0 || (status & 0x10) > 0) {
                descriptBuffer.append("正在feed, ");//[8]
                troubleBuffer.append("feeding|");

            }

            //错误状态
            if ((status & 0x100) > 0) {
                statusList[5] = 1;
                descriptBuffer.append("机械错误, ");
                troubleBuffer.append("MachineError|");

            }

            if ((status & 0x40) > 0) {
                statusList[6] = 1;
                descriptBuffer.append("可自动恢复错误, ");
                troubleBuffer.append("CorrectingError|");

            }

            if ((status & 0x80) > 0) {
                statusList[7] = 1;
                descriptBuffer.append("不可恢复错误, ");
                troubleBuffer.append("NotCorrectError|");

            }

            String descript = descriptBuffer.toString().trim();

            if (!descript.isEmpty()) {
                descript = descript.substring(0, descript.length() - 1);
            } else {
                descript = "正常";
            }
            return descript;
        } catch (Exception e) {

            return "Offline123123";
        }
    }

    private static int[] statusList = {        //错误列表
            //数据传输错误0
            0,
            0,                            //少纸1
            0,                            //缺纸2
            0,                            //脱机3
            0,                            //机头抬起4
            0,                            //机械错误5
            0,                            //可自动恢复错误6
            0,                            //不可恢复错误7
            //offline130

    };

    /**
     * 判断打印机是否可以正常打印
     */
    public static boolean isPrinterOk() {
        for (int i = 0; i < statusList.length; i++) {
            if (statusList[i] != 0) {
                return false;
            }
        }
        return true;
    }

    /**
     * 判断缺纸
     *
     * @return
     */
    public static boolean isOutOfPaper() {
        if (statusList[2] == 1) {
            return true;
        }
        return false;
    }

    /**
     * 判断脱机
     *
     * @return
     */
    public static boolean isOffline() {
        if (statusList[0] == 1 || statusList[3] == 1) {
            return true;
        }
        return false;
    }

}
