package com.hboxs.serialport;

import android.serialport.SerialPort;
import android.util.Log;

import com.hboxs.serialport.frame.CommandFrame;
import com.hboxs.serialport.message.Message;
import com.hboxs.serialport.util.ByteUtils;

import org.greenrobot.eventbus.EventBus;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;

import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;

/**
 * 串口设备管理器
 */
public final class SerialPortManager {
    private final static String TAG = "SerialPortManager";

    /**
     * 串口设备
     */
    private SerialPort mSerialPort;
    /**
     * 输出流
     */
    private OutputStream mOutputStream;
    /**
     * 读线程
     */
    private SerialPortReadThread mReadThread;

    /**
     * 不允许生成对象
     */
    private SerialPortManager() {
    }

    /**
     * 静态内部类控制单例
     */
    private static class SerialPortManagerHolder {
        final static SerialPortManager instance = new SerialPortManager();
    }

    /**
     * 获取串口设备管理器单例
     *
     * @return 串口设备管理器
     */
    public static SerialPortManager getInstance() {
        return SerialPortManagerHolder.instance;
    }

    /**
     * 打开串口
     *
     * @param device 串口设备
     * @return 串口
     */
    public SerialPort open(SerialPortDevice device) {
        SerialPortSendQueue.start();
        return open(device.getPath(), device.getBaudRate());
    }

    /**
     * 打开串口
     *
     * @param devicePath 设备路径
     * @param baudRate   波特率
     * @return
     */
    private SerialPort open(String devicePath, String baudRate) {
        if (mSerialPort != null) {
            close();
        }

        try {
            File device = new File(devicePath);
            int bauRate = Integer.parseInt(baudRate);
            // 打开串口
            mSerialPort = new SerialPort(device, bauRate, 0);
            // 开启读线程
            mReadThread = new SerialPortReadThread(mSerialPort.getInputStream());
            mReadThread.start();
            // 获取输出流
            mOutputStream = mSerialPort.getOutputStream();
            EventBus.getDefault().post(new Message("打开串口成功", Message.Type.connected,"open success"));
            return mSerialPort;
        } catch (Throwable tr) {
            Log.e(TAG, "打开串口失败", tr);
            EventBus.getDefault().post(new Message("打开串口失败", Message.Type.disconnected,"open failed"));
            close();
            return null;
        }
    }

    /**
     * 发送数据
     *
     * @param data 数据
     */
    private void sendData(byte[] data) throws IOException {
        mOutputStream.write(data);
    }

    /**
     * 关闭串口
     */
    public void close() {
        if (mReadThread != null) {
            mReadThread.close();
        }

        SerialPortSendQueue.stop();
        if (mOutputStream != null) {
            try {
                mOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        if (mSerialPort != null) {
            mSerialPort.close();
            mSerialPort = null;
        }
    }

    /**
     * 发送数据 (rx包裹)
     *
     * @param data 数据
     * @return 被观察者
     */
    private Observable<Object> rxSendData(final byte[] data, final String name) {

        return Observable.create(new ObservableOnSubscribe<Object>() {
            @Override
            public void subscribe(ObservableEmitter<Object> emitter) throws Exception {
                try {
                    mReadThread.setmName(name);
                    sendData(data);
                    emitter.onComplete();
                } catch (IOException e) {
                    Log.e(TAG, "发送：" + ByteUtils.bytes2HexStr(data) + " 失败", e);
                    if (!emitter.isDisposed()) {
                        emitter.onError(e);
                        return;
                    }
                }
                emitter.onComplete();
            }
        });
    }

    /**
     * 发送命令包
     * @param name 指令名称
     */
    public void sendCommandFrame(final CommandFrame commandFrame, final String name) {
//        Log.i(TAG, "发送命令(raw)：" + Arrays.toString(commandFrame.getFrameData()));
        Log.i(TAG, name+"发送命令：" + commandFrame);
        //已经从我们的去读取出来转换成了字节数了。
        byte[] bytes = commandFrame.getFrameData();
        Log.d("log",new String(bytes).toString());
        rxSendData(bytes,name).subscribeOn(Schedulers.io()).subscribe(new Observer<Object>() {
            @Override
            public void onSubscribe(Disposable d) {
            }

            @Override
            public void onNext(Object o) {
//                Log.i(TAG, o.toString());
            }

            @Override
            public void onError(Throwable e) {
                Log.e(TAG, "发送失败", e);
                EventBus.getDefault().post(new Message("消息发送失败", Message.Type.sendError,name));
            }

            @Override
            public void onComplete() {

            }
        });
    }
}
