package com.grkj.iscs.modbus

import android.content.Context
import androidx.annotation.WorkerThread
import com.epton.sdk.SerialPort
import com.grkj.iscs.util.Executor
import com.grkj.iscs.util.SPUtils
import com.grkj.iscs.util.ToastUtils
import com.grkj.iscs.util.log.LogUtil
import java.io.File
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream

/**
 * 串口通信管理器
 */
class PortManager private constructor(
    private val input: InputStream,
    private val output: OutputStream
) {

    // 是否正在监听
    @Volatile
    private var listening = false

    /**
     * 向串口发送数据
     */
    fun send(data: ByteArray) : Boolean {
        try {
            output.write(data)
            output.flush()
            return true
        } catch (e: IOException) {
            LogUtil.e("串口写数据失败 : ${e.message}")
            return false
        }
    }

    var t : Thread ? = null

    /**
     * 监听串口数据
     */
    fun listen(listener: (ByteArray) -> Unit) {
        if (listening) {
            throw IllegalStateException("已经被监听")
        }
        listening = true
        t = Thread {
            val buffer = ByteArray(BUFFER_SIZE)
            while (listening) {
                try {
                    val data = ByteArray(input.read(buffer))
                    System.arraycopy(buffer, 0, data, 0, data.size)
                    if (data.isNotEmpty()) {
                        listener(data)
                    }
                } catch (e: Exception) {
                    LogUtil.e("串口读取或处理异常 : ${e.message}")
                }
            }
        }
        t?.isDaemon = true
        t?.start()
    }

    /**
     * 关闭
     */
    fun close() {
        t = null
        listening = false
        try {
            input.close()
            output.close()
        } catch (e: Exception) { }
    }

    companion object {

        private const val BUFFER_SIZE = 256

        /**
         * 打开串口
         * @param port 串口号，从 0 开始
         * @param bps 波特率，正整数
         */
        @WorkerThread
        fun open(port: Int, bps: Int, usb: Boolean) : PortManager? {
            var blocked = true
            val thread = Thread.currentThread()
            Executor.delayOnMain(500) {
                // 如果线程被阻塞达到 1 秒，则打断唤醒
                if (blocked) {
                    LogUtil.w("超 0.5 秒未打开串口，打断唤醒")
                    thread.interrupt()
                }
            }
            try {
                val file = File(if(usb) "/dev/ttyUSB${port}" else "/dev/ttyS${port}")
                LogUtil.i("连接 port file")
                SerialPort(file, bps, 0).run {
                    blocked = false
                    LogUtil.i("建立 SerialPort")
                    return PortManager(inputStream, outputStream)
                }
            } catch (e: Exception) {
                blocked = false
                LogUtil.e("异常 : ${e.message}")
//                Tip.toast("串口[${port}, ${bps}, ${usb}]打开失败[${e.javaClass.simpleName}]${e.message}")
//                synchronized(Tip) {
//                    Tip.audioNum(port)
//                    Tip.audio(R.raw.unconnect_port)
//                }
                return null
            }
        }

        /**
         * 打开串口
         * @param port 串口号，从 0 开始
         * @param bps 波特率，正整数
         */
        @WorkerThread
        fun open(port: String?, bps: Int) : PortManager? {
            var blocked = true
            val thread = Thread.currentThread()
            Executor.delayOnMain(500) {
                // 如果线程被阻塞达到 1 秒，则打断唤醒
                if (blocked) {
                    LogUtil.w("超 0.5 秒未打开串口，打断唤醒")
                    thread.interrupt()
                }
            }
            try {
                val file = File(port)
                LogUtil.i("连接 port file")
                SerialPort(file, bps, 0).run {
                    blocked = false
                    LogUtil.i("建立 SerialPort")
                    return PortManager(inputStream, outputStream)
                }
            } catch (e: Exception) {
                blocked = false
                LogUtil.e("异常 : ${e.message}")
                ToastUtils.tip("串口[${port}, ${bps}]打开失败[${e.javaClass.simpleName}]${e.message}")
                return null
            }
        }


        /**
         * 打开主控板
         */
        @WorkerThread
        fun openCtrlBord(ctx: Context) : PortManager? {
            // TODO 端口号待定：大屏调试设备-1，小屏调试设备-0
//            val port = 4
//            val bps = 115200
//            val usb = true
//            LogUtil.i("主控板 port = ${port}, bps = ${bps}, usb = $usb")
//            return open(port, bps, usb)


            val port = SPUtils.getPortConfig(ctx)
            val bps = 115200
            LogUtil.i("主控板 port = $port, bps = $bps")
            return open(port, bps)
        }
    }

}
