package com.gingersoft.gsa.cloud.print;

import android.os.AsyncTask;

import com.gingersoft.gsa.cloud.common.logan.LoganManager;
import com.gingersoft.gsa.cloud.common.utils.log.LogUtil;
import com.gingersoft.gsa.cloud.print.impl.OnPrjPrintResultListener;
import com.xuexiang.rxutil2.rxjava.RxJavaUtils;
import com.xuexiang.rxutil2.rxjava.task.RxAsyncTask;

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

import io.reactivex.disposables.Disposable;

/**
 * 打印执行者
 *
 * @author admin
 */
public class PrintExecutor {
    protected final String TAG = this.getClass().getSimpleName();

    private static PrintExecutor printExecutor;

    public static PrintExecutor getInstance() {
        if (printExecutor == null) {
            printExecutor = new PrintExecutor();
        }
        return printExecutor;
    }

    private PrintSocketHolder holder;
    /**
     * 存儲所有prj的id集合
     */
    private String prjIds;
    private PrintSocketHolder.OnStateChangedListener listener;
    private OnPrintResultListener mListener;
    private OnPrjPrintResultListener onPrjPrintResultListener;

    public PrintExecutor() {
        holder = PrintSocketHolder.getInstance();
        holder.closeSocket();
        printDataMakers = new ArrayList<>();
    }

    /**
     * 需要執行的任務隊列
     */
    List<PrintDataMaker> printDataMakers;
    /**
     * 重啟打印的服務
     */
    private Disposable resetPrintDis;

    /**
     * 异步执行打印请求
     */
    public void doPrinterRequestAsync(PrintDataMaker maker) {
        holder.setOnStateChangedListener(listener);
        if (printDataMakers.size() <= 0) {
            LogUtil.i("eee", "prj熱敏打印執行第一個任務");
            printDataMakers.add(maker);
//            new PrintTask().execute(maker);
            executePrint(maker);
        } else {
            //如果隊列裡有任務在執行，只添加進去，等待執行完成之後，再來執行這個
            LogUtil.i("eee", "prj熱敏打印添加隊列，前面還有" + printDataMakers.size() + "個任務");
            printDataMakers.add(maker);
            startReset();
        }
    }

    private void executePrint(PrintDataMaker maker) {
        RxJavaUtils.executeAsyncTask(new RxAsyncTask<PrintDataMaker, Integer>(maker) {
            @Override
            public Integer doInIOThread(PrintDataMaker o) {
                LogUtil.i("eee", "executePrint----doInIOThread");
                return doRequest(o);
            }

            @Override
            public void doInUIThread(Integer i) {
                LogUtil.i("eee", "executePrint----doInUIThread" + i);
                if (resetPrintDis != null) {
                    resetPrintDis.dispose();
                }
                //移除掉當前任務
                if (printDataMakers.size() > 0) {
                    printDataMakers.remove(0);
                }
                //執行下一個任務
                if (printDataMakers.size() > 0) {
//                    new PrintTask().execute(printDataMakers.get(0));
                    executePrint(printDataMakers.get(0));
                    startReset();
                }
                LogUtil.d("eee", "executePrint----doInUIThread熱敏打印完成後，任務數量" + printDataMakers.size());
                //返回結果
                if (i != null) {
                    onResult(i);
                }
            }
        });
    }

    private void startReset() {
        if (resetPrintDis != null) {
            resetPrintDis.dispose();
        }
        resetPrintDis = RxJavaUtils.delay(30, aLong -> {
            //如果三十秒之後，任務還沒在打印完成方法中取消，可能打印程序卡住了，在這裡執行下一個任務
            LogUtil.e("eee", "prj熱敏打印等待時間超過三十秒，自動重新打印");
            if (printDataMakers.size() > 0) {
//                new PrintTask().execute(printDataMakers.get(0));
                executePrint(printDataMakers.get(0));
            }
        });
    }

    /**
     * 执行打印请求
     *
     * @return 错误代码
     */
    private int doRequest(PrintDataMaker maker) {
        //通知狀態
        holder.onPrinterStateChanged(PrintSocketHolder.STATE_0);
        //獲取打印數據
        List<byte[]> data = maker.getPrintData();
        //如果是打印prj，需要獲取prj的id
        prjIds = maker.getPrjIds();
        LogUtil.d("eee", "prj doRequest食品id：" + prjIds);
        //判斷是否連接，如果未連接就先連接
        int prepare = holder.prepareSocket(maker.getIp(), maker.getPort());
        if (prepare != PrintSocketHolder.ERROR_0) {
            return prepare;
        }
        return holder.sendData(data);
    }

    /**
     * 打印任務
     */
    private class PrintTask extends AsyncTask<PrintDataMaker, Integer, Integer> implements
            PrintSocketHolder.OnStateChangedListener {

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            LogUtil.i("eee", "prjService熱敏任務onPreExecute");
            holder.setOnStateChangedListener(this);
        }

        @Override
        protected Integer doInBackground(PrintDataMaker... makers) {
            LogUtil.i("eee", "prjService熱敏任務開始");
            holder.closeSocket();
            if (makers == null || makers.length < 1) {
                return PrintSocketHolder.ERROR_0;
            }
            LogUtil.e("eee", "prjService熱敏任務開始，prjID為" + makers[0].getPrjIds());
            return doRequest(makers[0]);
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            LogUtil.i("eee", "prjService熱敏任務onProgressUpdate" + values.toString());
            if (values == null || values.length < 1) {
                return;
            }
            if (listener != null) {
                listener.onStateChanged(values[0]);
            }
        }

        @Override
        protected void onPostExecute(Integer integer) {
            super.onPostExecute(integer);
            LogUtil.i("eee", "prjService熱敏任務onPostExecute" + integer);
            if (resetPrintDis != null) {
                resetPrintDis.dispose();
            }
            //移除掉當前任務
            if (printDataMakers.size() > 0) {
                printDataMakers.remove(0);
            }
            //執行下一個任務
            if (printDataMakers.size() > 0) {
                new PrintTask().execute(printDataMakers.get(0));
                startReset();
            }
            LogUtil.d("eee", "prjService熱敏打印完成後，任務數量" + printDataMakers.size());
            //返回結果
            if (integer != null) {
                onResult(integer);
            }
        }


        @Override
        public void onStateChanged(int 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;
            }
            publishProgress(state);
        }
    }

    /**
     * 打印结果
     *
     * @param errorCode 错误代码
     */
    private void onResult(int errorCode) {
        try {
            if (mListener != null) {
                mListener.onResult(errorCode);
            }
            if (onPrjPrintResultListener != null) {
                onPrjPrintResultListener.onResult(errorCode, prjIds);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 设置状态监听
     *
     * @param listener 监听
     */
    public PrintExecutor setOnStateChangedListener(PrintSocketHolder.OnStateChangedListener listener) {
        this.listener = listener;
        return this;
    }

    /**
     * 设置结果回调
     *
     * @param listener 回调
     */
    public PrintExecutor setOnPrintResultListener(OnPrintResultListener listener) {
        this.mListener = listener;
        return this;
    }

    /**
     * 打印結果回調
     */
    public interface OnPrintResultListener {
        void onResult(int errorCode);
    }

    public PrintExecutor setOnPrjPrintResultListener(OnPrjPrintResultListener onPrjPrintResultListener) {
        this.onPrjPrintResultListener = onPrjPrintResultListener;
        return this;
    }
}
