package com.gingersoft.gsa.cloud.print;

import com.gingersoft.gsa.cloud.common.constans.PrintConstans;
import com.gingersoft.gsa.cloud.common.logan.LoganManager;
import com.gingersoft.gsa.cloud.common.printer.plugins.PrinterPlugins;
import com.gingersoft.gsa.cloud.common.utils.other.TextUtil;

import java.io.IOException;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.List;

/**
 * 打印Socket
 */
public class PrintSocketHolder {

    private final static PrintSocketHolder printSocketHolder = new PrintSocketHolder();

    public static PrintSocketHolder getInstance() {
        synchronized (printSocketHolder) {
            return printSocketHolder;
        }
    }

    protected final String TAG = this.getClass().getSimpleName();

    public static final int STATE_0 = 0;// 生成测试页面数据
    public static final int STATE_1 = -1;// 创建Socket连接
    public static final int STATE_2 = -2;// 获取输出流
    public static final int STATE_3 = -3;// 写入测试页面数据
    public static final int STATE_4 = -4;// 关闭输出流

    public static final int ERROR_0 = 3;// 成功
    public static final int ERROR_4 = 4;// 打印失败

    public static final int ERROR_6 = 6;// 生成打印数据失败
    public static final int ERROR_7 = 7;// 创建Socket失败，未連接到打印機
    public static final int ERROR_TIMEOUT = 8;// 連接打印機超時
    public static final int ERROR_9 = 9;// IP地址为空
    public static final int ERROR_10 = 10;// 打印機連接成功，獲取輸入流失敗或者發送數據出現問題
    public static final int ERROR_11 = 11;// 打印機沒紙了
    public static final int ERROR_12 = 12;// 打印機初始化失敗，暫時只有針式打印機有

    public static final int ERROR_66 = 66;// 关闭Socket出错


    private Socket socket;
    private OutputStream out;
    private WeakReference<OnStateChangedListener> mListener;

    private PrintSocketHolder() {
    }

    public int createSocket(String ip, int port) {
        onPrinterStateChanged(STATE_1);
        if (TextUtil.isEmptyOrNullOrUndefined(ip)) {
            return ERROR_9;
        }
        try {
            PrinterPlugins.getOnPrinterFlowHandler().connectionBefore("網絡打印機", ip, port, PrintConstans.SO_TIMEOUT, PrintConstans.PRINT_TIMEOUT);
            socket = new Socket();
            //建立連接
            InetSocketAddress socketAddress = new InetSocketAddress(ip, port);
            //设置超时时间
            socket.setSoTimeout(PrintConstans.SO_TIMEOUT);
            socket.connect(socketAddress, PrintConstans.PRINT_TIMEOUT);//开始连接ip
        } catch (SocketTimeoutException e) {
            e.printStackTrace();
            LoganManager.w_printer(TAG, "連接打印機超時: " + ip + ":" + port + "." + e.getMessage());
            return ERROR_TIMEOUT;
        } catch (ConnectException e) {
            e.printStackTrace();
            LoganManager.w_printer(TAG, "連接打印機失敗: " + ip + ":" + port + "." + e.getMessage());
            return ERROR_7;
        } catch (IOException e) {
            e.printStackTrace();
            PrinterPlugins.getOnPrinterFlowHandler().connectionError(e);
            return ERROR_7;
        } catch (Exception e) {
            closeSocket();
            e.printStackTrace();
            LoganManager.w_printer(TAG, "連接打印機異常: " + ip + ":" + port + "." + e.getMessage());
            return ERROR_7;
        }
        return ERROR_0;
    }

    public int getOutputStream() {
        onPrinterStateChanged(STATE_2);
        try {
            out = socket.getOutputStream();
        } catch (IOException e) {
            LoganManager.w_printer(TAG, "獲取打印機輸入流異常: " + socket.getInetAddress() + e.getMessage());
            closeSocket();
            PrinterPlugins.getOnPrinterFlowHandler().connectionError(e);
            return ERROR_10;
        }
        return ERROR_0;
    }

    /**
     * 是否連接
     */
    public boolean isSocketPrepared() {
        return socket != null && out != null;
    }

    /**
     * 發送數據
     *
     * @param data 需要發送的數據
     * @return 發送狀態：是否成功
     */
    public int sendData(List<byte[]> data) {
        onPrinterStateChanged(STATE_3);
        if (data == null || data.size() <= 0) {
            return ERROR_6;
        }
        for (byte[] item : data) {
            try {
                out.write(item);
                out.flush();
            } catch (IOException | NullPointerException e) {
                LoganManager.w_printer(TAG, "打印prj寫入數據异常: " + e.getMessage());
                PrinterPlugins.getOnPrinterFlowHandler().onPrintError(e, ERROR_10);
                closeSocket();
                return ERROR_10;
            }
        }
        closeSocket();//成功後關閉連接
        return ERROR_0;
    }

    public int prepareSocket(String ip, int port) {
        LoganManager.w_printer(TAG, "准备尝试连接打印机" + ip + ":" + port);
        //創建連接
        int create = createSocket(ip, port);
        //判斷連接狀態
        if (create != PrintSocketHolder.ERROR_0) {
            return create;
        }
        //獲取打印機寫入
        int result = getOutputStream();
        if (result == ERROR_0) {
            PrinterPlugins.getOnPrinterFlowHandler().connectionSuccess();
        } else {
            PrinterPlugins.getOnPrinterFlowHandler().connectionError(new Exception("失敗"));
        }
        return result;
    }

    /**
     * 销毁
     */
    public int closeSocket() {
        onPrinterStateChanged(STATE_4);
        boolean error = false;
        try {
            if (out != null) {
                out.close();
                out = null;
                LoganManager.w_printer(TAG, "关闭打印机輸出连接");
            }
        } catch (IOException e) {
            LoganManager.w_printer(TAG, "关闭打印机连接异常");
            out = null;
            error = true;
        }
        try {
            if (socket != null) {
                socket.close();
                socket = null;
                LoganManager.w_printer(TAG, "关闭打印机socket连接");
            }
        } catch (IOException e) {
            LoganManager.w_printer(TAG, "关闭打印机连接异常" + e.getMessage());
            socket = null;
            error = true;
        }
        PrinterPlugins.getOnPrinterFlowHandler().disconnect(null);
        return error ? ERROR_66 : ERROR_0;
    }

    /**
     * 打印状态变化
     *
     * @param state 打印状态
     */
    public void onPrinterStateChanged(int state) {
        try {
            if (mListener != null && mListener.get() != null) {
                mListener.get().onStateChanged(state);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 设置状态监听
     *
     * @param listener 监听
     */
    public void setOnStateChangedListener(OnStateChangedListener listener) {
        mListener = new WeakReference<>(listener);
    }

    public interface OnStateChangedListener {
        void onStateChanged(int state);
    }
}
