package com.joe.print.mvp.print;

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

import com.epson.epos2.Epos2Exception;
import com.epson.epos2.printer.Printer;
import com.epson.epos2.printer.PrinterStatusInfo;
import com.epson.epos2.printer.ReceiveListener;
import com.joe.print.mvp.model.bean.PrintInfoBean;

import java.util.ArrayList;
import java.util.List;

import io.reactivex.disposables.Disposable;

public class EpsonPrint implements ReceiveListener {

    private final String TAG = this.getClass().getSimpleName();
    private Printer mPrinter = null;

    private ReceiveListener receiveListener;

    private static EpsonPrint epsonPrint;

    public static EpsonPrint getInstance() {
        synchronized (EpsonPrint.class) {
            if (epsonPrint == null) {
                epsonPrint = new EpsonPrint();
            }
        }
        return epsonPrint;
    }

    /**
     * 初始化
     *
     * @return
     */
    public boolean initializeObject(Context context, ReceiveListener receiveListener) {
        if (mPrinter != null) {
            return true;
        }
        try {
            this.receiveListener = receiveListener;
            //第一個參數是機型，第二個參數是語言，
            mPrinter = new Printer(Printer.TM_U220, Printer.MODEL_TAIWAN, context);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        mPrinter.setReceiveEventListener(this);
        return true;
    }

    public void disconnectPrinter() {
        if (mPrinter == null) {
            return;
        }
        while (true) {
            try {
                mPrinter.disconnect();
                break;
            } catch (final Exception e) {
                Log.e(TAG, "斷開連接報錯" + e.getMessage() + e.getClass().getName());
                if (e instanceof Epos2Exception) {
                    //Note: If printer is processing such as printing and so on, the disconnect API returns ERR_PROCESSING.
                    if (((Epos2Exception) e).getErrorStatus() == Epos2Exception.ERR_PROCESSING) {

                    } else {
                        break;
                    }
                } else {
                    break;
                }
            }
        }
    }

    public PrinterStatusInfo getStatus() {
        if (mPrinter == null) {
            return null;
        }
        return mPrinter.getStatus();
    }

    public void finalizeObject() {
        if (mPrinter == null) {
            return;
        }
        mPrinter.clearCommandBuffer();
        mPrinter.setReceiveEventListener(null);
        mPrinter = null;
    }

    private int lineCount = 42;

    /**
     * 創建打印數據
     *
     * @return
     */
    private boolean createPrintData(Bitmap bitmap) {
//        String method = "";
        StringBuilder textData = new StringBuilder();
//        final int barcodeWidth = 2;
//        final int barcodeHeight = 100;
        if (mPrinter == null) {
            return false;
        }
        try {
//                method = "addPulse";
//            mPrinter.addPulse(Printer.PARAM_DEFAULT,
//                    Printer.PARAM_DEFAULT);
//            method = "addTextAlign";
//            mPrinter.addPageBegin();
//            mPrinter.addTextFont(Printer.FONT_A);
//            mPrinter.addTextLang(Printer.LANG_ZH_TW);
            mPrinter.addTextAlign(Printer.ALIGN_CENTER);
//            method = "addImage";
            Log.e("ccc", "Epson寬度：" + bitmap.getWidth() + "高度：" + bitmap.getHeight());
            mPrinter.addImage(bitmap, 0, 0,
                    bitmap.getWidth(),
                    bitmap.getHeight(),
                    Printer.COLOR_1,
                    Printer.MODE_MONO_HIGH_DENSITY,//高密度
                    Printer.HALFTONE_DITHER,//半色調抖動
                    Printer.PARAM_DEFAULT,
                    Printer.COMPRESS_NONE);//壓縮

            //COLOR_NONE 為普通顏色 COLOR_2為紅色
//            mPrinter.addTextSize(2, 2);
//            mPrinter.addTextStyle(0,0,1, Printer.COLOR_1);
//            mPrinter.addText("炒爐打印測試\n");
//
//            //第一個參數不清楚作用，第二個參數ul是加下劃線，第三個參數em是加深顏色，第四個參數color修改文字顏色
//            mPrinter.addTextAlign(Printer.ALIGN_LEFT);
//            mPrinter.addTextStyle(0,0,0, Printer.COLOR_1);
//            mPrinter.addText("時間：" + TimeUtil.getCurrentDate(TimeUtil.dateFormatYMDHMS)+"\n");
//            mPrinter.addTextSize(1, 1);
//            mPrinter.addText("-------項目-------\n");
//            mPrinter.addText("--測試子食品      x1\n");
//            mPrinter.addTextAlign(Printer.ALIGN_CENTER);
//            mPrinter.addText("----Powered by Gingersoft----\n");
//            mPrinter.addTextLang(Printer.LANG_ZH_TW);
//            textData.append("------項目-----\n");
//            textData.append("測試食品      x1\n");
//            textData.append("測試子食品    x1\n");
//            mPrinter.addTextSize(3, 3);
//            mPrinter.addText(textData.toString());

//            textData.setLength(0);
//            mPrinter.addFeedLine(2);
//            mPrinter.addPageEnd();
            mPrinter.addCut(Printer.CUT_FEED);

            //            textData.append("\n");
//            textData.append("7/01/07 16:58 6153 05 0191 134\n");
//            textData.append("ST# 21 OP# 001 TE# 01 TR# 747\n");
//            textData.append("------------------------------\n");
//            method = "addText";
//            mPrinter.addText(textData.toString());


//            mPrinter.addTextStyle(0,0,0,Printer.COLOR_2);
//            mPrinter.addText(textData.toString());
//            mPrinter.addCut(Printer.CUT_FEED);
//            textData.delete(0, textData.length());
//
//            textData.append("400 OHEIDA 3PK SPRINGF  9.99 R\n");
//            textData.append("410 3 CUP BLK TEAPOT    9.99 R\n");
//            textData.append("445 EMERIL GRIDDLE/PAN 17.99 R\n");
//            textData.append("438 CANDYMAKER ASSORT   4.99 R\n");
//            textData.append("474 TRIPOD              8.99 R\n");
//            textData.append("433 BLK LOGO PRNTED ZO  7.99 R\n");
//            textData.append("458 AQUA MICROTERRY SC  6.99 R\n");
//            textData.append("493 30L BLK FF DRESS   16.99 R\n");
//            textData.append("407 LEVITATING DESKTOP  7.99 R\n");
//            textData.append("441 **Blue Overprint P  2.99 R\n");
//            textData.append("476 REPOSE 4PCPM CHOC   5.49 R\n");
//            textData.append("461 WESTGATE BLACK 25  59.99 R\n");
//            textData.append("------------------------------\n");
//            method = "addText";
//            mPrinter.addText(textData.toString());
//            textData.delete(0, textData.length());
//
//            textData.append("SUBTOTAL                160.38\n");
//            textData.append("TAX                      14.43\n");
//            method = "addText";
//            mPrinter.addText(textData.toString());
//            textData.delete(0, textData.length());
//
//            method = "addTextSize";
//            mPrinter.addTextSize(2, 2);
//            method = "addText";
//            mPrinter.addText("TOTAL    174.81\n");
//            method = "addTextSize";
//            mPrinter.addTextSize(1, 1);
//            method = "addFeedLine";
//            mPrinter.addFeedLine(1);
//
//            textData.append("CASH                    200.00\n");
//            textData.append("CHANGE                   25.19\n");
//            textData.append("------------------------------\n");
//            method = "addText";
//            mPrinter.addText(textData.toString());
//            textData.delete(0, textData.length());
//
//            textData.append("Purchased item total number\n");
//            textData.append("Sign Up and Save !\n");
//            textData.append("With Preferred Saving Card\n");
//            method = "addText";
//            mPrinter.addText(textData.toString());
//            textData.delete(0, textData.length());
//            method = "addFeedLine";
//            mPrinter.addFeedLine(2);
//            mPrinter.addPageEnd();
//            mPrinter.addCut(Printer.CUT_FEED);
//
//            method = "addBarcode";
//            mPrinter.addBarcode("01209457",
//                    Printer.BARCODE_CODE39,
//                    Printer.HRI_BELOW,
//                    Printer.FONT_A,
//                    2, 100);
        } catch (Exception e) {
            e.printStackTrace();
            mPrinter.clearCommandBuffer();
            return false;
        }
//        textData = null;
        return true;
    }

    /**
     * true 打印中
     * false 未打印
     */
    private boolean isPrint = false;
    private String ipAddress;
    private List<Bitmap> bitmaps = new ArrayList<>();

    public void putPrintString(String ip, List<PrintInfoBean> printInfoBeans) {
        if (mPrinter == null) {
            return;
        }
        connectByIp(ip, mPrinter.getStatus());
        mPrinter.clearCommandBuffer();
        try {
            for (PrintInfoBean printInfoBean : printInfoBeans) {
                if (printInfoBean.getGravity() == 0) {
                    mPrinter.addTextAlign(Printer.ALIGN_LEFT);
                }
                if (printInfoBean.getGravity() == 1) {
                    mPrinter.addTextAlign(Printer.ALIGN_CENTER);
                }
                if (printInfoBean.getGravity() == 2) {
                    mPrinter.addTextAlign(Printer.ALIGN_RIGHT);
                }
                //如果打印多列內容，並且字體大小配置多個，則每一列取自己對應的字體大小
                for (int i = 0; i < printInfoBean.getContent().length; i++) {
                    print(printInfoBean, i);
                }
                mPrinter.addFeedLine(1);
            }
            mPrinter.addPulse(Printer.DRAWER_LOW, Printer.PULSE_100);
            mPrinter.addCut(Printer.CUT_FEED);
            mPrinter.sendData(Printer.PARAM_DEFAULT);
        } catch (Exception e) {
            e.printStackTrace();
            mPrinter.clearCommandBuffer();
        }
    }

    private int location = 0;
    private void print(PrintInfoBean printInfoBean, int i) throws Epos2Exception {
        if (i == 0) {
            location = 0;
        }
        if (printInfoBean.getIsBold().length == 1) {
            mPrinter.addTextStyle(0, 0, printInfoBean.getIsBold()[0] ? 1 : 0, Printer.COLOR_1);
        } else {
            if (printInfoBean.getIsBold()[i]) {
                mPrinter.addTextStyle(0, 0, 0, Printer.COLOR_1);
            } else {
                mPrinter.addTextStyle(0, 0, 1, Printer.COLOR_1);
            }
        }
        StringBuilder space = new StringBuilder();
        if (printInfoBean.getSize().length == 1) {
            for (int j = 0; j < location/printInfoBean.getSize()[0]; j++) {
                space.append(" ");
            }
            mPrinter.addTextSize((int) printInfoBean.getSize()[0], (int) printInfoBean.getSize()[0]);
            location += printInfoBean.getContent()[i].length() * printInfoBean.getSize()[0];
        } else {
            for (int j = 0; j < location/printInfoBean.getSize()[i]; j++) {
                space.append(" ");
            }
            mPrinter.addTextSize((int) printInfoBean.getSize()[i], (int) printInfoBean.getSize()[i]);
            location += printInfoBean.getContent()[i].length() * printInfoBean.getSize()[i];
        }
        if (printInfoBean.getLanguage().length == 1) {
            setLanguage(printInfoBean.getLanguage()[0]);
        } else {
            setLanguage(printInfoBean.getLanguage()[i]);
        }
        mPrinter.addText(space + printInfoBean.getContent()[i]);
//        mPrinter.addLineSpace(100);//行間距
    }

    private void setLanguage(String language) throws Epos2Exception {
        if ("en".equals(language)) {
            //切換對應語言
            mPrinter.addTextLang(Printer.LANG_EN);
        } else if ("ja".equals(language)) {
            mPrinter.addTextLang(Printer.LANG_JA);
        } else if ("cn".equals(language)) {
            mPrinter.addTextLang(Printer.LANG_ZH_CN);
        } else if ("tw".equals(language)) {
            mPrinter.addTextLang(Printer.LANG_ZH_TW);
        } else if ("ko".equals(language)) {
            mPrinter.addTextLang(Printer.LANG_KO);
        } else if ("th".equals(language)) {
            mPrinter.addTextLang(Printer.LANG_TH);
        } else if ("vi".equals(language)) {
            mPrinter.addTextLang(Printer.LANG_VI);
        } else if ("multi".equals(language)) {
            mPrinter.addTextLang(Printer.LANG_MULTI);
        }
    }

    public static double getChineseValueLength(String value) {
        double valueLength = 0;
        String chinese = "[\u4e00-\u9fa5]";
        for (int i = 0; i < value.length(); i++) {
            String temp = value.substring(i, i + 1);
            if (temp.matches(chinese)) {
                valueLength += 1.5;
            } else {
                valueLength += 1;
            }
        }
        return valueLength;
    }

    public int putPrintData(String ip, Bitmap bitmap) {
        //把bitmap存隊列中，下次打印
        bitmaps.add(bitmap);
        if (isPrint) {
            //開啟定時，如果在10秒後沒執行回調，就修改打印狀態為沒打印
//            startTimer(10);
            return 0;
        }
        isPrint = true;
        return printData(ip, bitmap);
    }

    //重試次數5次
    private int resetCount = 5;

    private int printData(String ip, Bitmap bitmap) {
        mPrinter.clearCommandBuffer();
        if (!createPrintData(bitmap)) {
            return 0;
        }
        if (mPrinter == null) {
            return 0;
        }
        connectByIp(ip, mPrinter.getStatus());
        PrinterStatusInfo statusInfo = mPrinter.getStatus();
//        if (statusInfo.getConnection() != 1) {
//            if (resetCount > 0) {
//                //沒連接上打印機，延遲2秒後再試
//                resetCount--;
//                if (resetCount < 3) {
//                    //試了兩次還不能連接上，斷開連接
//                    disconnectPrinter();
//                }
//                startTimer(5);
//            }
//            return 0;
//        }
        if (statusInfo.getPaper() == 2) {
            //沒紙了
            return 2;
        }
        try {
            mPrinter.sendData(Printer.PARAM_DEFAULT);
            if (timerDisposable != null) {
                timerDisposable.dispose();
            }
        } catch (Exception e) {
            mPrinter.clearCommandBuffer();
            disconnectPrinter();
            isPrint = false;
            return 0;
        }
        return 1;
    }

    private Disposable timerDisposable;

//    private void startTimer(long delay) {
//        if (timerDisposable != null) {
//            timerDisposable.dispose();
//        }
//        Observable.timer(delay, TimeUnit.SECONDS)
//                .subscribe(new Observer<Long>() {
//                    @Override
//                    public void onSubscribe(Disposable d) {
//                        timerDisposable = d;
//                    }
//
//                    @Override
//                    public void onNext(Long aLong) {
//                        isPrint = false;
//                        Log.e(TAG, "時間到了沒回調");
//                        if (bitmaps.size() > 0) {
//                            printData(ipAddress, bitmaps.get(0));
//                        }
//                    }
//
//                    @Override
//                    public void onError(Throwable e) {
//
//                    }
//
//                    @Override
//                    public void onComplete() {
//
//                    }
//                });
//    }


    private void connectByIp(String ip, PrinterStatusInfo statusInfo) {
        if (statusInfo != null) {
            Log.e(TAG, "連接狀態1111：" + statusInfo.getConnection());
            if (statusInfo.getConnection() != 1) {
                //未連接
                if (connectPrinter(ip)) {
                    ipAddress = ip;
                }
            } else {
                //已連接，判斷這次是否是上次的ip，如果不是，斷開連這個ip
                if (ipAddress != null && !ipAddress.equals(ip)) {
                    Log.e(TAG, "不是上次的ip，斷開重連");
                    disconnectPrinter();
                    finalizeObject();
                    if (connectPrinter(ip)) {
                        ipAddress = ip;
                    }
                }
            }
        } else {
            if (connectPrinter(ip)) {
                ipAddress = ip;
            }
        }
        Log.e(TAG, "連接狀態222：" + statusInfo.getConnection());
    }

    private void loginfo(PrinterStatusInfo statusInfo) {
        int connection = statusInfo.getConnection();
        int online = statusInfo.getOnline();
        int coverOpen = statusInfo.getCoverOpen();
        int paper = statusInfo.getPaper();
        int paperFeed = statusInfo.getPaperFeed();
        int panelSwitch = statusInfo.getPanelSwitch();
        int waitOnline = statusInfo.getOnline();
        int drawer = statusInfo.getDrawer();
        int errorStatus = statusInfo.getErrorStatus();
        int autoRecoverError = statusInfo.getAutoRecoverError();
        int buzzer = statusInfo.getBuzzer();
        int adapter = statusInfo.getAdapter();
        int batteryLevel = statusInfo.getBatteryLevel();
        Log.e(TAG, "connection->" + connection + "|online->" + online + "|coverOpen->" + coverOpen + "|paper->" + paper + "|paperFeed->" + paperFeed + "|panelSwitch->" + panelSwitch + "|waitOnline->" + waitOnline + "|drawer->" + drawer + "|errorStatus->" + errorStatus + "|autoRecoverError->" + autoRecoverError + "|buzzer->" + buzzer + "|adapter->" + adapter + "|batteryLevel->" + batteryLevel);
    }


    private boolean connectPrinter(String ip) {
        if (mPrinter == null) {
            return false;
        }
        try {
            mPrinter.connect("TCP:" + ip, Printer.PARAM_DEFAULT);
        } catch (Exception e) {
            Log.e(TAG, "連接打印機報錯" + e.getMessage() + e.getClass().getName());
            e.printStackTrace();
            disconnectPrinter();
            return false;
        }
        return true;
    }

    @Override
    public void onPtrReceive(Printer printer, int i, PrinterStatusInfo printerStatusInfo, String s) {
        this.mPrinter = printer;
        mPrinter.clearCommandBuffer();
        Log.e(TAG, "1111回調，還剩下：" + bitmaps.size() + "未打印，連接狀態：" + printerStatusInfo.getConnection());
        resetCount = 5;
        Log.e(TAG, "2222打印成功，還剩下：" + bitmaps.size() + "未打印" + s);
        if (timerDisposable != null && !timerDisposable.isDisposed()) {
            timerDisposable.dispose();
        }
        if (bitmaps.size() > 0) {
            bitmaps.remove(0);
        }
        Log.e(TAG, "3333打印完成，還剩下：" + bitmaps.size() + "未打印");
        if (bitmaps.size() > 0) {
//            startTimer(2);
            printData(ipAddress, bitmaps.get(0));
        } else {
            isPrint = false;
            if (receiveListener != null) {
                receiveListener.onPtrReceive(printer, i, printerStatusInfo, s);
            }
        }
    }
}
