package com.joe.print.mvp.print;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.hardware.usb.UsbManager;
import android.os.Build;
import android.os.IBinder;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.SparseArray;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.annotation.ColorRes;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.epson.epos2.printer.Printer;
import com.epson.epos2.printer.PrinterStatusInfo;
import com.epson.epos2.printer.ReceiveListener;
import com.gingersoft.gsa.cloud.app.GsaCloudApplication;
import com.gingersoft.gsa.cloud.common.constans.AppConstans;
import com.gingersoft.gsa.cloud.common.constans.DeliveryPickConstans;
import com.gingersoft.gsa.cloud.common.constans.ExpandConstant;
import com.gingersoft.gsa.cloud.common.constans.PrintConstans;
import com.gingersoft.gsa.cloud.common.core.delivery.OrderDetails;
import com.gingersoft.gsa.cloud.common.core.restaurant.RestaurantInfoManager;
import com.gingersoft.gsa.cloud.common.core.restaurant.utils.RestaurantExpandInfoUtils;
import com.gingersoft.gsa.cloud.common.logan.LoganManager;
import com.gingersoft.gsa.cloud.common.printer.AidlUtil;
import com.gingersoft.gsa.cloud.common.printer.plugins.PrinterFlowProxy;
import com.gingersoft.gsa.cloud.common.utils.log.LogUtil;
import com.gingersoft.gsa.cloud.common.utils.other.TextUtil;
import com.gingersoft.gsa.cloud.common.utils.time.TimeUtils;
import com.gingersoft.gsa.cloud.common.utils.view.ImageUtils;
import com.gingersoft.gsa.cloud.common.utils.view.LayoutToBitmapUtils;
import com.gingersoft.gsa.cloud.common.utils.view.QRCodeUtil;
import com.gingersoft.gsa.cloud.database.bean.PrinterDeviceBean;
import com.gingersoft.gsa.cloud.order.commodity.OrderDetail;
import com.gingersoft.gsa.cloud.print.PrintExecutor;
import com.gingersoft.gsa.cloud.print.PrintSocketHolder;
import com.gingersoft.gsa.cloud.print.PrinterWriter58mm;
import com.gingersoft.gsa.cloud.print.bean.PrintContent;
import com.gingersoft.gsa.cloud.print.bean.PrintTakeawayCheckoutContent;
import com.gingersoft.gsa.cloud.print.bean.PrintTakeawayFormContent;
import com.gingersoft.gsa.cloud.print.bean.UpdateBean;
import com.gingersoft.gsa.cloud.print.bean.base.PrintBillItem;
import com.gingersoft.gsa.cloud.print.bean.base.PrintFoodItem;
import com.gingersoft.gsa.cloud.print.bean.base.PrintPayTypeItem;
import com.gingersoft.gsa.cloud.print.impl.OnPrjPrintResultListener;
import com.google.zxing.WriterException;
import com.hyweb.n5.lib.constant.PrinterConstant;
import com.hyweb.n5.lib.util.PrinterUtil;
import com.hyweb.n5.server.aidl.IOnPrintCallback;
import com.jess.arms.integration.AppManager;
import com.joe.print.R;
import com.joe.print.mvp.model.bean.BillingBean;
import com.joe.print.mvp.model.bean.HtmlLable;
import com.joe.print.mvp.print.common.HtmlContract;
import com.joe.print.mvp.print.common.PrinterFinderCallback;
import com.joe.print.mvp.print.common.SendResultCode;
import com.joe.print.mvp.print.maker.IpPrintMaker;
import com.joe.print.mvp.print.service.PrjService;
import com.joe.print.mvp.print.usb.EscCommand;
import com.joe.print.mvp.print.usb.UsbPrint;
import com.joe.print.mvp.print.usb.UsbPrinter;
import com.joe.print.mvp.print.usb.UsbPrinterFinder;
import com.joe.print.mvp.print.utils.BBposPrint;
import com.joe.print.mvp.ui.view.BillItemView;
import com.joe.print.mvp.ui.view.BillTypeView;
import com.joe.print.mvp.ui.view.BillView;
import com.joe.print.mvp.ui.view.PrintFoodView;
import com.sunmi.peripheral.printer.InnerResultCallbcak;
import com.xuexiang.rxutil2.rxjava.RxJavaUtils;
import com.xuexiang.rxutil2.rxjava.task.RxIOTask;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import javax.inject.Inject;

import lombok.Getter;

import static com.joe.print.mvp.print.common.HtmlContract.LABLE_COLUMN;
import static com.joe.print.mvp.print.common.HtmlContract.LABLE_DIV;
import static com.joe.print.mvp.print.common.HtmlContract.LABLE_P;

@Getter
public abstract class PrinterRoot<T extends PrintContent> implements PrintExecutor.OnPrintResultListener, ReceiveListener {

    private final String TAG = getClass().getSimpleName();
    @Inject
    AppManager mAppManager;
    protected final String MONETARY_UNIT = "$";
    private final static int SUNMI_PAPER_WIDTH = 360;//商米打印機紙張寬度
    private final static int N5_PAPER_WIDTH = 500;//N5打印機紙張寬度

    final static String DELIMITER = "/";//將打印位置區分開來。。。。，暫時只有廚房單用到

    private static SparseArray<PrinterRoot> mPrinterStrategy = new SparseArray<>();

    static {
        mPrinterStrategy.put(PrintConstans.PRINT_TEST, new PrintTest());
        mPrinterStrategy.put(PrintConstans.PRINT_SERVE, new PrintServe());
        mPrinterStrategy.put(PrintConstans.PRINT_SLIP, new PrintSlip());
        mPrinterStrategy.put(PrintConstans.PRINT_BILL, new PrintBill());
        mPrinterStrategy.put(PrintConstans.PRINT_KITCHEN, new PrintPrjKitchen());
        mPrinterStrategy.put(PrintConstans.PRINT_CLEAN_MACHINE, new PrintCleanMachine());
        mPrinterStrategy.put(PrintConstans.PRINT_OTHER_ORDER, new PrintOtherOrder());
        mPrinterStrategy.put(PrintConstans.PRINT_INSTRUCTION, new PrintInstruction());
        mPrinterStrategy.put(PrintConstans.PRINT_OTHER_CLOSING, new PrintOtherOrderClosing());
        mPrinterStrategy.put(PrintConstans.PRINT_SKYORDER_QRCODE, new PrintQRCode());
    }

    public static PrinterRoot getPrinterByType(int type, PrintContent content) {
        if (mPrinterStrategy.indexOfKey(type) >= 0) {
            PrinterRoot printerRoot = mPrinterStrategy.get(type);
            printerRoot.setPrintContent(content);
            return printerRoot;
        }
        return null;
    }

    /**
     * 需要打印實體的類 需要重寫這個方法
     *
     * @param printContent
     */
    protected void setPrintContent(T printContent) {
    }


    /**
     * 把Map中Key相同，则各个value添加到一起，汇总值
     * 把partMap数据合并放到resultMap中。
     *
     * @param resultMap
     */
    public static <T, F, K extends Collection<F>> Map merge2ResultMap(Map<T, K> resultMap, T key2, K value) {
        for (Map.Entry<T, K> entry : resultMap.entrySet()) {
            T key = entry.getKey();
            if (resultMap.containsKey(key2)) {
                Objects.requireNonNull(resultMap.get(key2)).addAll(value);
            } else {
                resultMap.put(key2, value);
            }
        }
        if (resultMap.size() == 0) {
            resultMap.put(key2, value);
        }
        return resultMap;
    }

    /**
     * 獲取打印數據，根據打印次數
     *
     * @param mContext
     * @param deviceBean
     * @return
     */
    public Map<String, List<Bitmap>> getPrintBitmapByCount(Context mContext, PrinterDeviceBean deviceBean) {
        int printCount = getPrintCount(mContext);
        if (printCount <= 0) {
            return null;
        }
        Map<String, List<Bitmap>> printBitmap = getPrintBitmap(mContext, deviceBean);
        if (printBitmap != null) {
            List<Bitmap> bitmapList = printBitmap.get("");
            //根據打印次數，複製
            if (bitmapList != null) {
                int bitmapSize = bitmapList.size();
                for (int i = 0; i < printCount - 1; i++) {
                    for (int j = 0; j < bitmapSize; j++) {
                        bitmapList.add(bitmapList.get(j));
                    }
                }
                printBitmap.put("", bitmapList);
            }
            return printBitmap;
        }
        return null;
    }

    /**
     * @param mContext
     * @return key為打印位置，值為圖片集合的map
     */
    public abstract Map<String, List<Bitmap>> getPrintBitmap(Context mContext, PrinterDeviceBean deviceBean);

    /**
     * 獲取打印內容
     *
     * @return BBPOS是HTMl格式
     */
    public abstract String[] getPrintDatas(Context mContext, PrinterDeviceBean deviceBean);

    /**
     * 獲取打印次數
     *
     * @param context
     * @return
     */
    public abstract int getPrintCount(Context context);

    /**
     * 本機打印
     */
    public void locationPrint(List<Bitmap> bitmaps, String[] BBPosPrintDatas) {
        //本機打印
        String model = Build.MODEL;
        if (PrintConstans.PRINT_MODEL_V2.contains(model)) {
            sunmiPrint(bitmaps);
        } else if (PrintConstans.PRINT_MODEL_N5.contains(model)) {
            //N5打印
            n5Print(bitmaps);
        } else if (PrintConstans.PRINT_MODEL_WISEPOS.contains(model)) {
            //BBPOS Wisepos 打印 localhost 192.168.1.162
            //打印結果示例：<?xml version="1.0" encoding= "UTF-8" ?><WAPIResult><status>SUCCESS</status><requestType>PRINT</requestType><state>IDLE</state><systemInfo><appVersion>1.22.4.4.007</appVersion><OSVersion>9</OSVersion><ip>192.168.1.162</ip><mac>2059a018d3d6</mac><serialNumber>WSS503013000075</serialNumber><firmware>WSS50.501-02 (5.00.01.02.beta7)</firmware><hardware></hardware><terminalConfig>GNZZ_MTIPD_v13_with_AE_v1</terminalConfig><key>034040XXXXXXXXXXXXXX</key><bootloader>6.00.00.20 (6.00.00.34)</bootloader></systemInfo><timestamp>1601021267673</timestamp></WAPIResult>
            new BBposPrint().print(BBPosPrintDatas, false);
        } else {
//            listener.printFailure("暫不支持本機型打印");
            PrinterFlowProxy.newInstance().dispatchConnectionError(new Exception("暫不支持本機型打印"));
        }
    }

    /**
     * n5打印
     *
     * @param bitmaps
     */
    private void n5Print(List<Bitmap> bitmaps) {
        try {
            for (int i = 0; i < bitmaps.size(); i++) {
                PrinterUtil.appendImage(ImageUtils.zoomDrawable(bitmaps.get(i), N5_PAPER_WIDTH), PrinterConstant.ALIGN_CENTER);
                PrinterUtil.appendPrnStr("\n", 24, PrinterConstant.ALIGN_CENTER, false);
                PrinterUtil.appendPrnStr("\n", 24, PrinterConstant.ALIGN_CENTER, false);
            }
            startN5Print();
        } catch (RemoteException e) {
            e.printStackTrace();
            printFailure(e.getMessage(), UpdateBean.FAILED_PRINT_N5);
        }
    }

    /**
     * 商米打印
     *
     * @param bitmaps
     */
    private void sunmiPrint(List<Bitmap> bitmaps) {
        //商米打印
        PrinterFlowProxy.newInstance().dispatchConnectionSuccess();
        AidlUtil.getInstance().printBitmaps(bitmaps, SUNMI_PAPER_WIDTH, new InnerResultCallbcak() {
            @Override
            public void onRunResult(boolean isSuccess) {
                //返回接⼝执⾏的情况(并⾮真实打印):成功或失败
                if (isSuccess) {
                    printSuccess();
                } else {
                    printFailure("sunmi打印失敗", UpdateBean.FAILED_PRINT);
                }
            }

            @Override
            public void onReturnString(String result) {
                //部分接⼝会异步返回查询数据
            }

            @Override
            public void onRaiseException(int code, String msg) {
                //接⼝执⾏失败时，返回的异常状态
                PrinterFlowProxy.newInstance().dispatchPrintError(new Exception(msg), code);
                LoganManager.w_printer(TAG, "商米onRaiseException: " + code + msg);
            }

            @Override
            public void onPrintResult(int code, String msg) {
                //事务模式下真实的打印结果返回
                PrinterFlowProxy.newInstance().dispatchPrintSuccess();
            }
        });
    }


    private void startN5Print() {
        try {
            PrinterUtil.startPrint(true, new IOnPrintCallback.Stub() {
                @Override
                public void onPrintResult(int i) {
                    if (i == 0) {
                        //打印成功
                        printSuccess();
                        PrinterFlowProxy.newInstance().dispatchPrintSuccess();
                    } else {
                        //打印失敗
                        printFailure("打印失敗", i);
                    }
                }

                @Override
                public IBinder asBinder() {
                    return this;
                }
            });
        } catch (RemoteException e) {
            e.printStackTrace();
            //打印失敗
            printFailure(e.getMessage(), UpdateBean.FAILED_PRINT_N5);
        }
    }

    private PrintExecutor executor;
    private EpsonPrint mPrinter;

    /**
     * ip設備打印
     */
    public void ipDevicePrint(PrinterDeviceBean
                                      printerDeviceBean, List<Bitmap> bitmaps) {
        //獲取打印機機型，如果是EPSON的打印機，調用EPSON的打印方法
        if ((printerDeviceBean.getPrinterName() != null && printerDeviceBean.getPrinterName().toLowerCase().contains("EPSON".toLowerCase()))) {
            if (printerDeviceBean.getModel() != null) {
                if (printerDeviceBean.getModel().toLowerCase().contains("TM-U220B".toLowerCase())) {
                    RxJavaUtils.doInIOThread(new RxIOTask<Object>(0) {
                        @Override
                        public Void doInIOThread(Object o) {
                            mPrinter = new EpsonPrint();
                            mPrinter.initializeObject(GsaCloudApplication.getAppContext(), PrinterRoot.this, new OnPrjPrintResultListener() {
                                @Override
                                public void onResult(int errorCode, String prjIds) {
                                    PrinterRoot.this.onResult(errorCode);
                                }
                            });
                            for (int j = 0; j < bitmaps.size(); j++) {
                                mPrinter.putPrintData(printerDeviceBean.getIp(), bitmaps.get(j), "");
                            }
                            return null;
                        }
                    });
                    return;
                }
            }
        }
        ipPrint(printerDeviceBean, bitmaps);
    }

    public void disconnectEpson() {
        if (mPrinter != null) {
            mPrinter.disconnectPrinter();
        }
    }

    private void ipPrint(PrinterDeviceBean printerDeviceBean, List<Bitmap> bitmaps) {
        if (executor == null) {
            executor = new PrintExecutor()
                    .setOnStateChangedListener(state -> {
                        switch (state) {
                            case PrintSocketHolder.STATE_0:
                                LoganManager.w_printer(TAG, "打印機狀態 --> 生成页面数据");
                                break;
                            case PrintSocketHolder.STATE_1:
                                LoganManager.w_printer(TAG, "打印機狀態 --> 创建Socket连接");
                                break;
                            case PrintSocketHolder.STATE_2:
                                LoganManager.w_printer(TAG, "打印機狀態 --> 获取输出流");
                                break;
                            case PrintSocketHolder.STATE_3:
                                LoganManager.w_printer(TAG, "打印機狀態 --> 写入页面数据");
                                break;
                            case PrintSocketHolder.STATE_4:
                                LoganManager.w_printer(TAG, "打印機狀態 --> 关闭输出流");
                                break;
                            default:
                                break;
                        }
                        LogUtil.e("eee", "executePrint----打印狀態：" + state);
                        if (state == PrintSocketHolder.STATE_4) {
                            printSuccess();
                        }
                    })
                    .setOnPrintResultListener(this::onResult);
        }
        IpPrintMaker maker = new IpPrintMaker(480, bitmaps, printerDeviceBean.getIp(), printerDeviceBean.getPort());
        executor.doPrinterRequestAsync(maker);
    }

    /**
     * usb打印
     *
     * @param context
     * @param bitmaps
     */
    public void usbPrint(Context context, List<Bitmap> bitmaps) {
        UsbPrint usbPrint = new UsbPrint(context, (code, printId) -> {
            //打印結果
            if (code == SendResultCode.SEND_SUCCESS) {
                printSuccess();
            } else if (code == SendResultCode.SEND_FAILED) {
                printFailure("usb打印失敗", UpdateBean.FAIL_USB_PRINT);
            }
        });
        UsbPrinterFinder printerFinder = new UsbPrinterFinder(context, new PrinterFinderCallback<UsbPrinter>() {
            @Override
            public void onStart() {

            }

            @Override
            public void onFound(UsbPrinter usbPrinter) {

            }

            @Override
            public void onFinished(List<UsbPrinter> usbPrinters) {
                if (usbPrinters != null && usbPrinters.size() > 0) {
                    for (Bitmap bitmap : bitmaps) {
                        EscCommand esc = new EscCommand();
                        ArrayList<byte[]> bytes = new ArrayList<>();
                        try {
                            bytes.addAll(new PrinterWriter58mm().getImageByte(bitmap));
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        bytes.add(esc.getPrintAndFeedLines((byte) 8));
                        bytes.add(esc.getCutPaper());
                        bytes.add(esc.getCleanCache());
                        if (usbPrinters.size() > 0) {
                            usbPrint.sendPrintCommand(usbPrinters.get(0), bytes);
                        }
                    }
                } else {
                    boolean hasPermission = new Intent().getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false);
                    printFailure("未找到USB打印機", UpdateBean.FAIL_USB_PRINT_NOT_FIND);
                }
            }
        });
        printerFinder.startFinder();
    }

    /**
     * view轉為縮放後的bitmap
     */
    final Bitmap viewToZoomBitmap(Context context, View view, PrinterDeviceBean printerDeviceBean) {
        LayoutToBitmapUtils.layoutView(context, view);//先测量view
//        return LayoutToBitmapUtils.loadBitmapFromView(view);
        //轉為bitmap
        return zoomBitmap(printerDeviceBean, LayoutToBitmapUtils.loadBitmapFromView(view));
    }

    /**
     * 縮放bitmap
     *
     * @param printerDeviceBean
     * @param bitmap
     * @return
     */
    private Bitmap zoomBitmap(PrinterDeviceBean printerDeviceBean, Bitmap bitmap) {
        int printWidth;
        if (PrjService.isPinPrinter(printerDeviceBean)) {
            //epson针式打印機
            printWidth = 200;
            return ImageUtils.dotMatrixZoomDrawable(bitmap, printWidth);
        } else {
            if (printerDeviceBean != null && printerDeviceBean.getPaperSpecification() != null) {
                printWidth = Double.valueOf(printerDeviceBean.getPaperSpecification()).intValue();
            } else {
                //如果打印機沒設置寬度
                printWidth = 480;
            }
        }
        return ImageUtils.zoomDrawable(bitmap, printWidth);
    }

    @Override
    public void onResult(int errorCode) {
        switch (errorCode) {
            case PrintSocketHolder.ERROR_0:
                PrinterFlowProxy.newInstance().dispatchPrintSuccess();
                printSuccess();
                return;
            case PrintSocketHolder.ERROR_6:
                LoganManager.w_printer(TAG, "生成打印數據失敗");
                printConnectError(UpdateBean.getStateByCode(errorCode));
                break;
            case PrintSocketHolder.ERROR_7:
                LoganManager.w_printer(TAG, "連接打印機失敗");
                printConnectError(UpdateBean.getStateByCode(errorCode));
                break;
            case PrintSocketHolder.ERROR_10:
                LoganManager.w_printer(TAG, "打印機連接成功，發送數據出現問題");
                printFailure(UpdateBean.getStateByCode(errorCode), errorCode);
                break;
            case PrintSocketHolder.ERROR_9:
                LoganManager.w_printer(TAG, "IP地址為空");
                printConnectError(UpdateBean.getStateByCode(errorCode));
                break;
            case PrintSocketHolder.ERROR_66:
                LoganManager.w_printer(TAG, "關閉Socket出錯");
                printDisconnect("關閉打印機連接出错");
                break;
            case PrintSocketHolder.ERROR_11:
                printFailure("打印機沒紙了", UpdateBean.FAIL_NOT_PAPER);
                break;
            case PrintSocketHolder.ERROR_12:
                //暫時只有針式打印機有
                printConnectError("打印機初始化失敗");
                break;
            case PrintSocketHolder.ERROR_TIMEOUT:
                printConnectError("連接打印機超時");
                break;
            default:
                break;
        }
    }

    @Override
    public void onPtrReceive(Printer printer, int i, PrinterStatusInfo printerStatusInfo, String s) {
        if (i == 0) {
            printSuccess();
        } else {
            printFailure("打印失敗", UpdateBean.FAILED_PRINT);
        }
    }

    private void printSuccess() {
        PrinterFlowProxy.newInstance().dispatchPrintSuccess();
    }

    private void printFailure(String msg, int code) {
        PrinterFlowProxy.newInstance().dispatchPrintError(new Exception(msg), code);
    }

    private void printConnectError(String msg) {
        PrinterFlowProxy.newInstance().dispatchConnectionError(new Exception(msg));
    }

    private void printDisconnect(String msg) {
        PrinterFlowProxy.newInstance().dispatchDisconnect(new Exception(msg));
    }

    public View getLine(Context mContext) {
        TextView textView = new TextView(mContext);
        textView.setMaxLines(1);
        textView.setText(mContext.getString(R.string.print_split_line));
        return textView;
    }

    /**
     * 獲取中間是文字的線條
     *
     * @param content 文字內容
     */
    public View getTextLine(Context mContext, String content) {
        View view = View.inflate(mContext, R.layout.print_model_text_line, null);
        TextView textView = view.findViewById(R.id.print_model_center_text);
        textView.setText(content);
        return view;
    }

    public View getHalfLine(Context mContext) {
        return View.inflate(mContext, R.layout.print_model_half_line, null);
    }

    public View getHeader(Context mContext) {
        View view = View.inflate(mContext, R.layout.print_model_header, null);
        TextView tvBrandName = view.findViewById(R.id.print_brand_name);
        TextView tvRestaurantName = view.findViewById(R.id.print_restaurant_name);
        TextView tvRestaurantPhone = view.findViewById(R.id.print_restaurant_phone);
        tvBrandName.setText(RestaurantInfoManager.newInstance().getBrandName());
        tvRestaurantName.setText(RestaurantInfoManager.newInstance().getRestaurantName());
        String printHeaderRestaurantPhone = GsaCloudApplication.functionConfiguration.getPrintHeaderRestaurantPhoneVaule();
        if (!TextUtils.isEmpty(printHeaderRestaurantPhone)) {
            tvRestaurantPhone.setText(printHeaderRestaurantPhone);
            tvRestaurantPhone.setVisibility(View.VISIBLE);
        }
        return view;
    }

    public View getTakeawayOrderInfo(Context mContext, OrderDetails.DataBean data) {
        View view = View.inflate(mContext, R.layout.print_model_takeaway_order_info, null);
        // 訂單類型
        TextView tvOrderType = view.findViewById(R.id.print_model_center_text);
        TextView tvPayType = view.findViewById(R.id.tv_print_model_pay_type);
        TextView tvDeliveryTime = view.findViewById(R.id.tv_print_model_delivery_time);
        TextView tvBillNumber = view.findViewById(R.id.tv_print_model_bill_number);
        TextView tvOrderNumber = view.findViewById(R.id.tv_print_model_order_number);
        TextView tvTakeFoodCode = view.findViewById(R.id.tv_print_model_order_take_food_code);
        TextView tvCreateTime = view.findViewById(R.id.tv_print_model_order_create_time);
        TextView tvClosingTime = view.findViewById(R.id.tv_print_model_order_closing_time);
        TextView tvRemark = view.findViewById(R.id.tv_print_model_remark);
        //訂單類型
        tvOrderType.setText(data.getShowTextByOrderType());
        tvClosingTime.setVisibility(View.GONE);
        if (data.getOrderPayType() == 2) {
            //支付時間，只有在線支付有
            if (!TextUtil.isEmptyOrNullOrUndefined(data.getPayTime())) {
                tvClosingTime.setText("支付時間：" + data.getPayTime());
                tvClosingTime.setVisibility(View.VISIBLE);
            }
        }
        if (TextUtil.isNotEmptyOrNullOrUndefined(data.getShowTextByOrderPayType())) {
            //支付類型
            tvPayType.setText(data.getShowTextByOrderPayType());
        }
        //送達時間
        tvDeliveryTime.setText(data.getOrderType() == 2 ? data.getSEND_TIME() : data.getTakeTime());
        if (TextUtil.isEmptyOrNullOrUndefined(tvDeliveryTime.getText().toString())) {
            tvDeliveryTime.setVisibility(View.GONE);
        }
        tvBillNumber.setText("編號：" + data.getORDER_NO());

        if (TextUtil.isEmptyOrNullOrUndefined(data.getBillNo())) {
            if (DeliveryPickConstans.COLD_CHAIN_TYPE.equals(data.getOrderType() + "")) {
                //凍鏈
                tvOrderNumber.setText("訂單號：" + data.getID());
                tvOrderNumber.setVisibility(View.VISIBLE);
            } else {
                tvOrderNumber.setVisibility(View.GONE);
            }
        } else {
            tvOrderNumber.setText("訂單碼：" + data.getBillNo());
        }

        //取餐碼
        if (data.getOrderType() == 7) {
            //自取  顯示 取餐碼+訂單碼
            if (!TextUtil.isEmptyOrNullOrUndefined(data.getTakeFoodCode())) {
                tvTakeFoodCode.setText("取餐碼：" + data.getTakeFoodCode());
            }
        } else {
            //外送  顯示訂單碼
            tvTakeFoodCode.setText("訂單碼：" + data.getTakeFoodCode());
        }
        if (data.getTakeFoodCode() == null || data.getTakeFoodCode().equals("0")) {
            tvTakeFoodCode.setVisibility(View.GONE);
        }
        tvCreateTime.setText("開單時間：" + TimeUtils.parseTimeRepeat(data.getCREATE_TIME(), TimeUtils.DEFAULT_DATE_FORMAT));
        //備註
        if (!TextUtil.isEmptyOrNullOrUndefined(data.getRemark())) {
            tvRemark.setText("備註：" + data.getRemark());
            tvRemark.setVisibility(View.VISIBLE);
        } else {
            tvRemark.setVisibility(View.GONE);
        }
        return view;
    }

    protected View getTableMealMemberIntegerView(Context mContext, OrderDetails.DataBean data, String integralQrcode) {
        View view = View.inflate(mContext, R.layout.print_model_meal_member_integer_info, null);
        LinearLayout ll_member_info = view.findViewById(R.id.ll_member_info);
        TextView tvMemberNum = view.findViewById(R.id.tv_print_model_member_number);//會員號碼
        TextView tvMemberName = view.findViewById(R.id.tv_print_model_member_name);//會員名稱
        TextView tvMemberPhone = view.findViewById(R.id.tv_print_model_member_phone);//會員電話
        TextView tvNowPoint = view.findViewById(R.id.tv_print_model_nowPoints);//現在的積分
        TextView tvAddPoints = view.findViewById(R.id.tv_print_model_addPoints);//本次添加積分
        TextView tvOldPoints = view.findViewById(R.id.tv_print_model_oldPoints);//之前的積分

        LinearLayout llIntegralQrcode = view.findViewById(R.id.ll_integral_qrcode);
        ImageView ivIntegralQrcode = view.findViewById(R.id.iv_integral_qrcode);

        if (data.getAddPoints() != 0 || data.getOldPoints() != 0 || data.getNowPoints() != 0) {
            tvAddPoints.setText("本次積分：" + data.getAddPoints());
            tvNowPoint.setText("結餘積分：" + data.getNowPoints());
            tvOldPoints.setText("上次積分：" + data.getOldPoints());
            //名稱中間替換為*號
            if (data.getMEMBER_NAME() != null && data.getMEMBER_NAME().length() > 0) {
                tvMemberName.setText("會員名稱：" + getReplaceAfter(data.getMEMBER_NAME()));
            }
            if (data.getPHONE() != null && data.getPHONE().length() > 0) {
                tvMemberPhone.setText("會員電話：" + getReplaceAfter(data.getPHONE()));
            }
            tvMemberNum.setText("會員號碼：" +getReplaceAfter(data.getMemberPhone()));
            ll_member_info.setVisibility(View.VISIBLE);
        } else {
            ll_member_info.setVisibility(View.GONE);
        }
        //生成積分QRCode碼（飯糰APP掃碼獲得積分）
        if ((boolean) RestaurantExpandInfoUtils.getValue(ExpandConstant.ToPrintQRCode, false) == false) {
            llIntegralQrcode.setVisibility(View.GONE);
        } else {
            if (!TextUtils.isEmpty(integralQrcode)) {
                llIntegralQrcode.setVisibility(View.VISIBLE);
                Bitmap QRImage = null;
                try {
                    QRImage = QRCodeUtil.makeQRImage(integralQrcode, 220, 220);
                } catch (WriterException e) {
                    e.printStackTrace();
                }
                ivIntegralQrcode.setImageBitmap(QRImage);
            } else {
                llIntegralQrcode.setVisibility(View.GONE);
            }
        }
        return view;
    }

    protected View getTakeawayMemberIntegerView(Context mContext, OrderDetails.DataBean data) {
        View view = View.inflate(mContext, R.layout.print_model_takeaway_member_integer_info, null);

        if (RestaurantExpandInfoUtils.getValue(ExpandConstant.PrintMemberInfo, false)) {
            TextView tvMemberNum = view.findViewById(R.id.tv_print_model_member_number);//會員號碼
            TextView tvMemberName = view.findViewById(R.id.tv_print_model_member_name);//會員名稱
            TextView tvMemberPhone = view.findViewById(R.id.tv_print_model_member_phone);//會員電話
            TextView tvNowPoint = view.findViewById(R.id.tv_print_model_nowPoints);//現在的積分
            TextView tvAddPoints = view.findViewById(R.id.tv_print_model_addPoints);//本次添加積分
            TextView tvOldPoints = view.findViewById(R.id.tv_print_model_oldPoints);//之前的積分

            if (data.getAddPoints() != 0 || data.getOldPoints() != 0 || data.getAddPoints() != 0) {
                tvAddPoints.setText("本次積分：" + data.getAddPoints());
                tvNowPoint.setText("結餘積分：" + data.getNowPoints());
                tvOldPoints.setText("上次積分：" + data.getOldPoints());
                //名稱中間替換為*號
                if (data.getMEMBER_NAME() != null && data.getMEMBER_NAME().length() > 0) {
                    tvMemberName.setText("會員名稱：" + getReplaceAfter(data.getMEMBER_NAME()));
                }
                if (data.getPHONE() != null && data.getPHONE().length() > 0) {
                    tvMemberPhone.setText("會員電話：" + getReplaceAfter(data.getPHONE()));
                }
                tvMemberNum.setText("會員號碼：" +getReplaceAfter(data.getMemberPhone()));
            } else {
                view.setVisibility(View.GONE);
            }
        } else {
            view.setVisibility(View.GONE);
        }
        return view;
    }

    protected String getReplaceAfter(String str) {
        if (str != null && str.length() > 0) {
            int replaceStrCount = str.length() / 2;
            StringBuilder buffer = new StringBuilder();
            if (replaceStrCount >= 5) {
                replaceStrCount = str.length() - 5;
            }
            for (int i = 0; i < replaceStrCount; i++) {
                buffer.append("*");
            }
            String header = str.substring(0, 1);
            String tail = str.substring(replaceStrCount + 1);
            return header + buffer.toString() + tail;
        }
        return "";
    }

    protected View getTakeawayLargeAmount(Context mContext, String title, String amount) {
        View view = View.inflate(mContext, R.layout.print_model_takeaway_total_amount, null);
        TextView tvTitle = view.findViewById(R.id.tv_total_text);
        TextView tvAmount = view.findViewById(R.id.tv_total);
        tvTitle.setText(title);
        tvAmount.setText(amount);
        return view;
    }

    protected View getTakeawayBillInfoView(Context mContext, List<PrintBillItem> data) {
//        return getVerticalRecyclerView(mContext, new BillItemAdapter(data));
        return new BillItemView(mContext, data);
    }

    protected void addTakeawayPayViews(Context mContext, ViewGroup parent, List<OrderDetails.DataBean.PayMultiple> payMultiples, double payAmount) {
        if (payMultiples != null && payMultiples.size() > 0) {
            for (OrderDetails.DataBean.PayMultiple payMultiple : payMultiples) {
                if (!TextUtil.isEmptyOrNullOrUndefined(payMultiple.getPayName())) {
                    parent.addView(getTakeawayLargeAmount(mContext, payMultiple.getPayName(), MONETARY_UNIT + payMultiple.getAmount()));
                }
            }
            parent.addView(getLine(mContext));
        }
        //支付金額
        parent.addView(getTakeawayLargeAmount(mContext, "支付金額：", MONETARY_UNIT + payAmount));
        parent.addView(getLine(mContext));
    }

    protected View getTakeawayMemberInfoView(Context mContext, String address, String receiver, String phone) {
        LinearLayout layout = new LinearLayout(mContext);
        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        layoutParams.topMargin = getDimensionPixelSize(mContext, R.dimen.dp_5);
        if (!TextUtil.isEmptyOrNullOrUndefined(address)) {
            View addressView = getTakeawayTextView(mContext, address);
            addressView.setLayoutParams(layoutParams);
            layout.addView(addressView);
        }
        if (!TextUtil.isEmptyOrNullOrUndefined(receiver)) {
            View receiverView = getTakeawayTextView(mContext, receiver);
            receiverView.setLayoutParams(layoutParams);
            layout.addView(receiverView);
        }
        if (!TextUtil.isEmptyOrNullOrUndefined(phone)) {
            View phoneView = getTakeawayTextView(mContext, phone);
            phoneView.setLayoutParams(layoutParams);
            layout.addView(phoneView);
        }
        return layout;
    }

    protected void getTakeawayReceiver(Context mContext, OrderDetails.DataBean data, LinearLayout layout) {
        String address = "";
        String receiver = "";
        if (data.getOrderType() == 2) {
            //收貨地址
            address = "地址：" + data.getAddressDetail();
            //收貨人
            receiver = "收貨人：" + data.getRECEIVER();
        }
        if (!TextUtil.isEmptyOrNullOrUndefined(address)) {
            layout.addView(getTakeawayTextView(mContext, address));
        }
        if (!TextUtil.isEmptyOrNullOrUndefined(receiver)) {
            layout.addView(getTakeawayTextView(mContext, receiver));
        }

        layout.addView(getTakeawayTextView(mContext, "手機號：" + data.getPHONE()));
    }

    protected View getTakeawayTextView(Context mContext, String text) {
        return getTextView(mContext, text, Gravity.LEFT, 26, getColor(mContext, R.color.black));
    }


    public View getDiningTableOrderInfo(Context mContext, String diningTable, String people, String orderNum, String createTime) {
        View view = View.inflate(mContext, R.layout.print_model_dining_table_order_info, null);
        TextView tvDiningTable = view.findViewById(R.id.tv_print_model_dining_table);
        TextView tvPeople = view.findViewById(R.id.tv_print_model_people);
        TextView tvOrderNum = view.findViewById(R.id.tv_print_model_order_number);
        TextView tvCreateTime = view.findViewById(R.id.tv_print_model_data);
        tvDiningTable.setVisibility(diningTable == null ? View.GONE : View.VISIBLE);
        tvPeople.setVisibility(people == null ? View.GONE : View.VISIBLE);
        tvOrderNum.setVisibility(orderNum == null ? View.GONE : View.VISIBLE);
        tvCreateTime.setVisibility(createTime == null ? View.GONE : View.VISIBLE);

        tvDiningTable.setText(diningTable);
        tvPeople.setText(people);
        tvOrderNum.setText(orderNum);
        tvCreateTime.setText(createTime);
        return view;
    }

    protected List<PrintFoodItem> orderDetailCastPrintFoodItem(List<OrderDetail> orderDetailList) {
        List<PrintFoodItem> foodItemList = new ArrayList<>();
        if (orderDetailList != null && orderDetailList.size() > 0) {
            for (int i = 0; i < orderDetailList.size(); i++) {
                OrderDetail orderDetail = orderDetailList.get(i);
                foodItemList.add(new PrintFoodItem(orderDetail.getProductName(), orderDetail.getNumber(), orderDetail.getPrice(), orderDetail.getItemType()));
            }
        }
        return foodItemList;
    }

    /**
     * 獲取食品列表
     * 結賬單、印單。外送都用這個
     *
     * @param mContext
     * @param foodList   食品信息
     * @param deviceBean 打印設備
     * @param type       0 食品清單，1 結賬單
     * @param showPrice  是否顯示價格
     * @return
     */
    public View getDiningFoodList(Context mContext, List<PrintFoodItem> foodList, PrinterDeviceBean deviceBean, int type, boolean showPrice) {
////        List<OrderDetail> newsFoodList = new ArrayList<>();
////        for (OrderDetail orderDetail : foodList) {
////            //如果食品設置了0元不打印並且食品等於0元，或者設置了不打印到單，就不打印
////            if (!(orderDetail.getPrintToBill() == 0 && orderDetail.getPrice() == 0)
////                    || OrderDetail.isPrint((int) orderDetail.getPrintTo(), type)) {
////                newsFoodList.add(orderDetail);
////            }
////        }
//        return getVerticalRecyclerView(mContext, new FoodAdapter(foodList, deviceBean, showPrice));
        return new PrintFoodView(mContext, foodList, deviceBean, showPrice);
    }

    /**
     * 結賬單和印單
     *
     * @param mContext
     * @param billingBeans
     * @return
     */
    public View getDiningBillInfo(Context mContext, List<BillingBean> billingBeans) {
//        return getVerticalRecyclerView(mContext, new BillAdapter(billingBeans));
        return new BillView(mContext, billingBeans);
    }

    /**
     * 結賬單，支付方式
     *
     * @param mContext
     * @param payBillMoneys 支付方式數據
     * @return
     */
    public View getDiningBillPayMethod(Context mContext, List<PrintBillItem> payBillMoneys) {
//        return getVerticalRecyclerView(mContext, new BillTypeAdapter(payBillMoneys));
        return new BillTypeView(mContext, payBillMoneys);
    }

    /**
     * 不用recyclerview，recyclerview可能會導致食品顯示不出來
     *
     * @param mContext
     * @param adapter
     * @return
     */
    @Deprecated
    public View getVerticalRecyclerView(Context mContext, RecyclerView.Adapter adapter) {
        RecyclerView recyclerView = new RecyclerView(mContext);
        recyclerView.setLayoutManager(new LinearLayoutManager(mContext));
        recyclerView.setAdapter(adapter);
        return recyclerView;
    }

    public View getAmountText(Context mContext, String text) {
        return getTextView(mContext, text, Gravity.RIGHT, 28, ContextCompat.getColor(mContext, R.color.black));
    }

    public TextView getTextView(Context mContext, String text, int gravity, float textSize) {
        TextView textView = new TextView(mContext);
        textView.setWidth(LinearLayout.LayoutParams.MATCH_PARENT);
        textView.setText(text);
        textView.setTextColor(Color.BLACK);
        textView.setTextSize(textSize);
        textView.setGravity(gravity);
        return textView;
    }

    public TextView getTextView(Context mContext, String text, int gravity, float textSize, int textColor) {
        TextView textView = new TextView(mContext);
        textView.setWidth(LinearLayout.LayoutParams.MATCH_PARENT);
        textView.setText(text);
        textView.setTextColor(textColor);
        textView.setTextSize(textSize);
        textView.setGravity(gravity);
        return textView;
    }

    public int getDimensionPixelSize(Context mContext, int textSizeId) {
        return mContext.getResources().getDimensionPixelSize(textSizeId);
    }

    public int getColor(Context mContext, @ColorRes int colorId) {
        return ContextCompat.getColor(mContext, colorId);
    }


    public void setText(View parentView, int viewId, String text) {
        ((TextView) parentView.findViewById(viewId)).setText(text);
    }

    public void setIsShow(View parentView, int viewId, boolean isShow) {
        parentView.findViewById(viewId).setVisibility(isShow ? View.VISIBLE : View.GONE);
    }

    public final int HTML_PRINT_GRAVITY_LEFT = 0;
    public final int HTML_PRINT_GRAVITY_CENTER = 1;
    public final int HTML_PRINT_GRAVITY_RIGHT = 2;

    protected String getPLable(String content, int gravity) {
        if (gravity == HTML_PRINT_GRAVITY_CENTER) {
            return "<p align='center'>" + content + "</p>";
        } else if (gravity == HTML_PRINT_GRAVITY_RIGHT) {
            return "<p align='right'>" + content + "</p>";
        } else if (gravity == HTML_PRINT_GRAVITY_LEFT) {
            return "<p align='left'>" + content + "</p>";
        } else {
            return "<p align='left'>" + content + "</p>";
        }
    }

    protected String getHtmlQrCode(String url) {
        return "<qrcode scale='1'>" + url + "</qrcode><br/>";
    }

    protected String getWholeLine() {
        return getLine(90, HTML_PRINT_GRAVITY_LEFT);
    }

    protected String getLine(int length, int gravity) {
        StringBuilder content = new StringBuilder();
        for (int i = 0; i < length; i++) {
            content.append("-");
        }
        return getPLable(content.toString(), gravity);
    }

    protected String generateHtmlFoodInfoTwoColumns(List<OrderDetail> foodList) {
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < foodList.size(); i++) {
            OrderDetail orderDetail = foodList.get(i);
            String foodName;
            if (orderDetail.getItemType() == 2) {
                foodName = "---" + orderDetail.getProductName();
            } else if (orderDetail.getItemType() == 3) {
                foodName = "-----" + orderDetail.getProductName();
            } else {
                foodName = orderDetail.getProductName();
            }
            stringBuilder.append(getBBPosLineString(foodName, "X" + orderDetail.getNumber()));
        }
        return stringBuilder.toString();
    }

    protected String generateHtmlFoodInfo(List<OrderDetail> foodList) {
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < foodList.size(); i++) {
            OrderDetail orderDetail = foodList.get(i);
            String foodName;
            if (orderDetail.getItemType() == 2) {
                foodName = "---" + orderDetail.getProductName();
            } else if (orderDetail.getItemType() == 3) {
                foodName = "-----" + orderDetail.getProductName();
            } else {
                foodName = orderDetail.getProductName();
            }
            stringBuilder.append(getBBPosLineString(foodName, "X" + orderDetail.getNumber(), "$" + orderDetail.getPrice()));
        }
        return stringBuilder.toString();
    }

    protected String getBBPosLineString(String name1, String name2) {
        return PrintUtils.getLineString(name1, name2, PrintUtils.BBPOS_Chinese_Length, PrintUtils.lineLength);
    }

    protected String getBBPosLineString(String name1, String name2, String name3) {
        return PrintUtils.getLineString(name1, name2, name3, PrintUtils.BBPOS_Chinese_Length);
    }

    private static final String font_size_total_amount = "48";
    private static final String font_size_pay_type = "48";
    private static final String font_size_pay_amuount = "48";
    private static final String font_size_integral = "48";

    protected String getTakewayPrintContent(PrintTakeawayFormContent printContent, PrinterDeviceBean deviceBean) {

        List<HtmlLable> htmlLables = new ArrayList<>();

        /**
         * 頭部
         */
        htmlLables.add(new HtmlLable(LABLE_DIV, printContent.getBrand(),
                new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_ALIGN, HtmlContract.value_align_center, HtmlContract.value_type_string),
                new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_FONT_SIZE, "28")));
        htmlLables.add(new HtmlLable(LABLE_DIV, printContent.getResturantName(),
                new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_ALIGN, HtmlContract.value_align_center, HtmlContract.value_type_string),
                new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_FONT_SIZE, "28")));

        htmlLables.add(new HtmlLable(LABLE_DIV, HtmlContract.dividing_line_half + printContent.getOrderType() + HtmlContract.dividing_line_half, new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_FONT_SIZE, "28")));

        htmlLables.add(new HtmlLable(LABLE_DIV, printContent.getPayType(),
                new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_ALIGN, HtmlContract.value_align_center, HtmlContract.value_type_string),
                new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_FONT_SIZE, "35")));

//        htmlLables.addAll(getRowInformation(new HtmlLable[]{new HtmlLable(LABLE_COLUMN, printContent.getDeliveryTime())}, 28));

        htmlLables.add(new HtmlLable(LABLE_DIV, printContent.getDeliveryTime(), new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_FONT_SIZE, "26")));
        /**
         * 訂單信息
         */
//        htmlLables.add(new HtmlLable(LABLE_DIV, HtmlContract.dividing_line));
        if (!TextUtils.isEmpty(printContent.getOrderNo())) {
            htmlLables.addAll(getRowInformation(new HtmlLable[]{new HtmlLable(LABLE_COLUMN, printContent.getOrderNo())}, 26));
        }
        if (!TextUtils.isEmpty(printContent.getBillNo())) {
            htmlLables.addAll(getRowInformation(new HtmlLable[]{new HtmlLable(LABLE_COLUMN, printContent.getBillNo())}, 26));
        }
        if (!TextUtils.isEmpty(printContent.getOrderTakeFoodCode())) {
            htmlLables.addAll(getRowInformation(new HtmlLable[]{new HtmlLable(LABLE_COLUMN, printContent.getOrderTakeFoodCode())}, 48));
        }
        if (!TextUtils.isEmpty(printContent.getBillingTime())) {
            htmlLables.addAll(getRowInformation(new HtmlLable[]{new HtmlLable(LABLE_COLUMN, printContent.getBillingTime())}, 24));
        }
        if (!TextUtil.isEmptyOrNullOrUndefined(printContent.getPayTime())) {
            //支付時間
            htmlLables.addAll(getRowInformation(new HtmlLable[]{new HtmlLable(LABLE_COLUMN, printContent.getPayTime())}, 24));
        }
        /**
         * 食品信息
         */
        htmlLables.add(new HtmlLable(LABLE_P, HtmlContract.dividing_line_half + "項目" + HtmlContract.dividing_line_half, new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_FONT_SIZE, "28")));
        htmlLables.addAll(getBBPosFoodLineString(printContent.getFoodItemList(), deviceBean));
        htmlLables.add(new HtmlLable(LABLE_P, HtmlContract.dividing_line));
        /**
         * 總金額，支付信息
         */
        //賬單項(合計，送貨費)
        List<PrintBillItem> billItemList = printContent.getBillItemList();
        if (billItemList.size() > 0) {
            for (PrintBillItem billItem : billItemList) {
                htmlLables.addAll(getRowInformation(new HtmlLable[]{
                        new HtmlLable(LABLE_COLUMN, billItem.getBillName()),
                        new HtmlLable(LABLE_COLUMN, billItem.getBillAmount(), new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_OFFSET, HtmlContract.value_offset_last))}, 28));
            }
            htmlLables.add(new HtmlLable(LABLE_P, HtmlContract.dividing_line));
        }
        //總金額
        htmlLables.addAll(getRowInformation(new HtmlLable[]{
                new HtmlLable(LABLE_COLUMN, printContent.getTotalAmountText()),
                new HtmlLable(LABLE_COLUMN, printContent.getTotalAmount(), new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_OFFSET, HtmlContract.value_offset_last))}, 35));
        htmlLables.add(new HtmlLable(LABLE_P, HtmlContract.dividing_line));
        if (printContent instanceof PrintTakeawayCheckoutContent) {
            //TODO 外送結賬有支付方式
            PrintTakeawayCheckoutContent takeawayCheckoutContent = (PrintTakeawayCheckoutContent) printContent;
            //支付方式
            List<PrintPayTypeItem> payTypeList = takeawayCheckoutContent.getPayTypeList();
            if (payTypeList != null) {
                for (PrintPayTypeItem payTypeItem : payTypeList) {
                    if (!TextUtils.isEmpty(payTypeItem.getPayAmount())) {
                        htmlLables.addAll(getRowInformation(new HtmlLable[]{
                                new HtmlLable(LABLE_COLUMN, payTypeItem.getPayName()),
                                new HtmlLable(LABLE_COLUMN, payTypeItem.getPayAmount(), new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_OFFSET, HtmlContract.value_offset_last))}, 30));
                    }
                }
            }
            htmlLables.add(new HtmlLable(LABLE_P, HtmlContract.dividing_line));
        }
        //支付金額
        htmlLables.addAll(getRowInformation(new HtmlLable[]{
                new HtmlLable(LABLE_COLUMN, printContent.getPayAmountText()),
                new HtmlLable(LABLE_COLUMN, printContent.getPayAmount(), new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_OFFSET, HtmlContract.value_offset_last))}, 35));
        htmlLables.add(new HtmlLable(LABLE_P, HtmlContract.dividing_line));

        /**
         * 會員積分、配送信息
         */
        List<String> items = new ArrayList<>();
        if (RestaurantExpandInfoUtils.getValue(ExpandConstant.PrintMemberInfo, false)) {
            items.add(printContent.getMemberName());
            items.add(printContent.getMemberNumber());
            items.add(printContent.getMemberPhone());
            items.add(printContent.getMemberOldPoints());
            items.add(printContent.getMemberAddPoints());
            items.add(printContent.getMemberNowPoints());
            items.add(HtmlContract.dividing_line);
        }
        if (!TextUtils.isEmpty(printContent.getAdress())) {
            items.add("地址: " + printContent.getAdress());
        }
        if (!TextUtils.isEmpty(printContent.getReceiver())) {
            items.add(printContent.getReceiver());
        }
        items.add(printContent.getPhone());
        for (String item : items) {
            if (!TextUtils.isEmpty(item)) {
//                htmlLables.addAll(getRowInformation(new HtmlLable[]{new HtmlLable(LABLE_COLUMN, item)}, 22));
                htmlLables.add(new HtmlLable(LABLE_DIV, item, new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_FONT_SIZE, "24")));
            }
        }
        return getHtmlLables(htmlLables.toArray(new HtmlLable[htmlLables.size()]));
    }


    /**
     * BBPos公共的食品行打印信息拼裝
     *
     * @param foodItemList
     * @return
     */
    protected List<HtmlLable> getBBPosFoodLineString(List<PrintFoodItem> foodItemList, PrinterDeviceBean printerDeviceBean) {
        int foodFontSize = 24;
        int modifierFontSize = 24;
        /**
         * 0預設
         * 1是
         * 2否
         */
        int foodIsBold = printerDeviceBean.getFoodIsBold();
        int modifierIsBold = printerDeviceBean.getModifierIsBold();
        int foodIsItalic = printerDeviceBean.getFoodIsItalic();
        int modifierIsItalic = printerDeviceBean.getModifierIsItalic();
        try {
            foodFontSize = Integer.parseInt(printerDeviceBean.getFoodFont()) * 2;
            modifierFontSize = Integer.parseInt(printerDeviceBean.getModifierFont()) * 2;
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }

        List<String> nameList = new ArrayList<>();
        List<Integer> numList = new ArrayList<>();
        List<Double> priceList = new ArrayList<>();
        List<Integer> itemTypes = new ArrayList<>();

        for (int i = 0; i < foodItemList.size(); i++) {
            PrintFoodItem foodItem = foodItemList.get(i);
            nameList.add(foodItem.getName());
            numList.add(foodItem.getNum());
            priceList.add(foodItem.getPrice());
            itemTypes.add(foodItem.getItemType());
        }

        List<HtmlLable> htmlLables = new ArrayList<>();

        for (int i = 0; i < nameList.size(); i++) {
            String name = nameList.get(i);
            int num = 0;
            double price = -9999;
            int fontSize = 24;
            boolean isBold = false;
            boolean isItalic = false;
            if (numList.size() > i) {
                num = numList.get(i);
            }
            if (priceList.size() > i) {
                price = priceList.get(i);
            }
            if (itemTypes.size() > i) {
                int itemType = itemTypes.get(i);
                if (itemType == 3) {
                    fontSize = modifierFontSize;
                    isBold = modifierIsBold == 1 ? true : false;
                    isItalic = modifierIsItalic == 1 ? true : false;
                } else {
                    fontSize = foodFontSize;
                    isBold = foodIsBold == 1 ? true : false;
                    isItalic = foodIsItalic == 1 ? true : false;
                }
            }
            List<String> name1s = PrintUtils.getFormatList(name, PrintUtils.foodNameSpace, PrintUtils.BBPOS_Chinese_Length);
            if (name1s.size() > 1) {
                //食品名需要獨佔一行，甚至換行顯示
                //需要佔用的行數
                int lines = name1s.size() / 2;
                if (lines > 1) {
                    //大於一行
                    for (int j = 0; j < lines; j++) {
                        htmlLables.addAll(getRowFoodInformation(name, fontSize, isBold, isItalic));
                    }
                    htmlLables.addAll(getRowFoodInformation(num, price, fontSize, isBold, isItalic));
                } else {
                    //一行
                    htmlLables.addAll(getRowFoodInformation(name, fontSize, isBold, isItalic));
                    htmlLables.addAll(getRowFoodInformation(num, price, fontSize, isBold, isItalic));
                }
            } else {
                htmlLables.addAll(getRowFoodInformation(name, num, price, fontSize, isBold, isItalic));
            }
        }
        return htmlLables;
    }

    protected String getHtmlLables(HtmlLable... lables) {
        StringBuilder stringBuilder = new StringBuilder();
        for (HtmlLable lable : lables) {
            if (TextUtils.isEmpty(lable.getLablename()) || (!lable.getLablename().contains("row") && TextUtils.isEmpty(lable.getValue()))) {
                continue;
            }
            if (lable.getLablename().contains("row") || lable.getLablename().contains("br")) {
                //<row>,<br>標籤直接追加即可
                stringBuilder.append(lable.getLablename());
                continue;
            }
            if (lable.getAttributesList() != null) {
                stringBuilder.append("<" + lable.getLablename() + traverseAttributes(lable.getAttributesList()) + ">" + lable.getValue() + "</" + lable.getLablename() + ">\n");
            } else {
                stringBuilder.append("<" + lable.getLablename() + ">" + lable.getValue() + "</" + lable.getLablename() + ">\n");
            }
        }
        return stringBuilder.toString();
    }

    protected String traverseAttributes(HtmlLable.Attributes[] attributesMap) {
        StringBuilder stringBuilder = new StringBuilder();
        for (HtmlLable.Attributes attributes : attributesMap) {
            stringBuilder.append(" ");
            stringBuilder.append(attributes.getAttributesName());
            stringBuilder.append("=");
            String attributesVaule = attributes.getAttributesVaule();
            if (attributes.getValueType() == HtmlContract.value_type_string) {
                stringBuilder.append("\"" + attributes.getAttributesVaule() + "\"");
            } else {
//                if (StringUtils.isNumeric(attributesVaule)) {
                stringBuilder.append(attributes.getAttributesVaule());
//                } else {
//                    stringBuilder.append("\"" + attributes.getAttributesVaule() + "\"");
//                }
            }
        }
        return stringBuilder.toString();
    }

    /**
     * 獲取一行信息,多個column 可配置字體大小
     *
     * @param lables
     * @param fontSize
     * @return
     */
    protected List<HtmlLable> getRowInformation(HtmlLable[] lables, int fontSize) {
        List<HtmlLable> htmlLables = new ArrayList<>();
        htmlLables.add(new HtmlLable(getRowLableStart(new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_FONT_SIZE, String.valueOf(fontSize)))));
        if (lables != null) {
            for (HtmlLable lable : lables) {
                htmlLables.add(new HtmlLable(LABLE_COLUMN, lable.getValue(), lable.getAttributesList()));
            }
        }
        htmlLables.add(new HtmlLable(getRowLableEnd()));
        return htmlLables;
    }

    /**
     * 獲取一行食品信息(食品名稱)
     *
     * @param name
     * @return
     */
    private List<HtmlLable> getRowFoodInformation(String name, int fontSize, boolean isBold, boolean isItalic) {
        List<HtmlLable> htmlLables = new ArrayList<>();
        htmlLables.add(new HtmlLable(getRowLableStart(new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_FONT_SIZE, String.valueOf(fontSize)))));
        if (isBold) {
            htmlLables.add(new HtmlLable(LABLE_COLUMN, name, new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_BOLD, HtmlContract.value_bold_1)));
        } else {
            htmlLables.add(new HtmlLable(LABLE_COLUMN, name));
        }
        htmlLables.add(new HtmlLable(getRowLableEnd()));
        return htmlLables;
    }

    /**
     * 獲取一行食品信息(數量，金額)
     *
     * @param num
     * @param amount
     * @return
     */
    private List<HtmlLable> getRowFoodInformation(int num, double amount, int fontSize, boolean isBold, boolean isItalic) {
        List<HtmlLable> htmlLables = new ArrayList<>();
        htmlLables.add(new HtmlLable(getRowLableStart(new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_FONT_SIZE, String.valueOf(fontSize)))));
        if (isBold) {
            htmlLables.add(new HtmlLable(LABLE_COLUMN, String.valueOf(num),
                    new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_BOLD, HtmlContract.value_bold_1),
                    new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_OFFSET, HtmlContract.value_offset_percentage_foodNum)));
        } else {
            htmlLables.add(new HtmlLable(LABLE_COLUMN, String.valueOf(num),
                    new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_OFFSET, HtmlContract.value_offset_percentage_foodNum)));
        }
        if (amount != -9999) {
            if (isBold) {
                htmlLables.add(new HtmlLable(LABLE_COLUMN, AppConstans.CARSH_STR + amount,
                        new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_BOLD, HtmlContract.value_bold_1),
                        new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_OFFSET, HtmlContract.value_offset_last)));
            } else {
                htmlLables.add(new HtmlLable(LABLE_COLUMN, AppConstans.CARSH_STR + amount, new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_OFFSET, HtmlContract.value_offset_last)));
            }
        }
        htmlLables.add(new HtmlLable(getRowLableEnd()));
        return htmlLables;
    }

    /**
     * 獲取一行食品信息(食品名稱，數量，金額)
     *
     * @param name
     * @param num
     * @param amount
     * @return
     */
    private List<HtmlLable> getRowFoodInformation(String name, int num, double amount, int fontSize, boolean isBold, boolean isItalic) {
        List<HtmlLable> htmlLables = new ArrayList<>();
        htmlLables.add(new HtmlLable(getRowLableStart(new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_FONT_SIZE, String.valueOf(fontSize)))));
        if (isBold) {
            htmlLables.add(new HtmlLable(LABLE_COLUMN, name,
                    new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_BOLD, HtmlContract.value_bold_1)));
        } else {
            htmlLables.add(new HtmlLable(LABLE_COLUMN, name));
        }
        if (isBold) {
            htmlLables.add(new HtmlLable(LABLE_COLUMN, String.valueOf(num),
                    new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_BOLD, HtmlContract.value_bold_1),
                    new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_OFFSET, HtmlContract.value_offset_percentage_foodNum)));
        } else {
            htmlLables.add(new HtmlLable(LABLE_COLUMN, String.valueOf(num), new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_OFFSET, HtmlContract.value_offset_percentage_foodNum)));
        }
        if (amount != -9999) {
            if (isBold) {
                htmlLables.add(new HtmlLable(LABLE_COLUMN, AppConstans.CARSH_STR + amount,
                        new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_BOLD, HtmlContract.value_bold_1),
                        new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_OFFSET, HtmlContract.value_offset_last)));
            } else {
                htmlLables.add(new HtmlLable(LABLE_COLUMN, AppConstans.CARSH_STR + amount, new HtmlLable.Attributes(HtmlContract.ATTRIBUTES_OFFSET, HtmlContract.value_offset_last)));
            }
        }
        htmlLables.add(new HtmlLable(getRowLableEnd()));
        return htmlLables;
    }

    protected String getRowLableStart() {
        return "<row>\n";
    }

    protected String getRowLableEnd() {
        return "</row>\n";
    }

    protected String getRowLableStart(HtmlLable.Attributes... attributes) {
        return "<row " + traverseAttributes(attributes) + ">\n";
    }

    protected String getBrLable() {
        return "<br/>\n";
    }

}