/*
 * Copyright (C) 2015 AlexMofer
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.gingersoft.gsa.cloud.print;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;

import com.elvishew.xlog.XLog;
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.database.bean.PrinterDeviceBean;

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

/**
 * 打印Socket
 * Created by Alex on 2016/11/10.
 */
@SuppressWarnings({"WeakerAccess", "unused"})
public class PrintSocketHolder {

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

    public static final int STATE_0 = 10;// 生成测试页面数据
    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 = 0;// 成功
    public static final int ERROR_1 = -1;// 生成测试页面数据失败
    public static final int ERROR_2 = -2;// 创建Socket失败，未連接到打印機
    public static final int ERROR_3 = -3;// 获取输出流失败
    public static final int ERROR_4 = -4;// 写入测试页面数据失败
    public static final int ERROR_5 = -5;// 必要参数不能为空
    public static final int ERROR_6 = -6;// 关闭Socket出错
    public static final int ERROR_100 = -100;// 失败

    private static final UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");//蓝牙打印UUID
    //    private String ip;
//    private int port = 9100;
    private PrinterDeviceBean printerDeviceBean;
    private BluetoothDevice mDevice;
    private Socket socket;
    private BluetoothSocket bluetoothSocket;
    private OutputStream out;
    private WeakReference<OnStateChangedListener> mListener;

    public PrintSocketHolder(BluetoothDevice device) {
        setDevice(device);
    }

    public PrintSocketHolder(PrinterDeviceBean printerDeviceBean) {
        setIp(printerDeviceBean);
    }

    public int createSocket() {
        onPrinterStateChanged(STATE_1);
        if (mDevice == null && (printerDeviceBean == null || printerDeviceBean.getIp() == null))
            return ERROR_5;
        try {
            if (mDevice != null) {
                PrinterPlugins.getOnPrinterFlowHandler().connectionBefore("藍牙打印機", printerDeviceBean.getIp(), printerDeviceBean.getPort(), 0, 0);
                bluetoothSocket = mDevice.createRfcommSocketToServiceRecord(uuid);
                bluetoothSocket.connect();
            } else {
                PrinterPlugins.getOnPrinterFlowHandler().connectionBefore("網絡打印機", printerDeviceBean.getIp(), printerDeviceBean.getPort(), PrintConstans.SO_TIMEOUT, PrintConstans.PRINT_TIMEOUT);
                socket = new Socket();
                InetSocketAddress socketAddress = new InetSocketAddress(printerDeviceBean.getIp(), printerDeviceBean.getPort());
                //设置超时时间
                socket.setSoTimeout(PrintConstans.SO_TIMEOUT);
                socket.connect(socketAddress, PrintConstans.PRINT_TIMEOUT);//开始连接ip
            }
        } catch (Exception e) {
            closeSocket();
            e.printStackTrace();
            return ERROR_2;
        }
        return ERROR_0;
    }

    public int getOutputStream() {
        onPrinterStateChanged(STATE_2);
        try {
            if (mDevice != null) {
                out = bluetoothSocket.getOutputStream();
            } else {
                out = socket.getOutputStream();
            }
        } catch (IOException e) {
            closeSocket();
            return ERROR_3;
        }
        return ERROR_0;
    }

    public boolean isSocketPrepared() {
        boolean isPrepared = (bluetoothSocket != null || socket != null) && out != null;
        return isPrepared;
    }

    public int sendData(List<byte[]> data) {
        onPrinterStateChanged(STATE_3);
        if (data == null || data.size() <= 0) {
            return ERROR_0;
        }
        for (byte[] item : data) {
            try {
                out.write(item);
                out.flush();
            } catch (IOException e) {
                LoganManager.w_printer(TAG, "打印异常: " + e.getMessage());
                closeSocket();
                return ERROR_4;
            }
        }
        closeSocket();//成功後關閉連接
        return ERROR_0;
    }

    public int sendData(byte[] data) {
        onPrinterStateChanged(STATE_3);
        try {
            out.write(data);
            out.flush();
        } catch (IOException e) {
            closeSocket();
            return ERROR_4;
        }
        return ERROR_0;
    }

    public int sendData(byte[]... data) {
        onPrinterStateChanged(STATE_3);
        for (byte[] item : data) {
            try {
                out.write(item);
                out.flush();
            } catch (IOException e) {
                closeSocket();
                return ERROR_4;
            }
        }
        return ERROR_0;
    }

    public int prepareSocket() {
        LoganManager.w_printer(TAG, "准备尝试连接打印机");
        int create = createSocket();
        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() {
        LoganManager.w_printer(TAG, "準備关闭打印机连接");
        onPrinterStateChanged(STATE_4);
        boolean error = false;
        try {
            if (out != null) {
                out.close();
                out = null;
            }
        } catch (IOException e) {
            LoganManager.w_printer(TAG, "关闭打印机连接异常");
            out = null;
            error = true;
        }
        try {
            if (socket != null) {
                socket.close();
                socket = null;
            }
        } catch (IOException e) {
            LoganManager.w_printer(TAG, "关闭打印机连接异常");
            socket = null;
            error = true;
        }
        try {
            if (bluetoothSocket != null) {
                bluetoothSocket.close();
                bluetoothSocket = null;
            }
        } catch (IOException e) {
            LoganManager.w_printer(TAG, "关闭打印机连接异常");
            bluetoothSocket = null;
            error = true;
        }
        PrinterPlugins.getOnPrinterFlowHandler().disconnect();
        return error ? ERROR_6 : ERROR_0;
    }

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

    /**
     * 设置IP及端口
     */
    public void setIp(PrinterDeviceBean printerDeviceBean) {
        this.printerDeviceBean = printerDeviceBean;
    }

//    public String getIp() {
//        return ip;
//    }
//
//    public int getPort() {
//        return port;
//    }

    public PrinterDeviceBean getPrinterDeviceBean() {
        return printerDeviceBean;
    }

    public void setPrinterDeviceBean(PrinterDeviceBean printerDeviceBean) {
        this.printerDeviceBean = printerDeviceBean;
    }

    /**
     * 设置蓝牙
     *
     * @param device 设备
     */
    public void setDevice(BluetoothDevice device) {
        this.mDevice = device;
    }

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

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