using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.IO.Ports;
using System.Threading;
using System.Collections.Concurrent;
using BPASmartClient.Message;

namespace BPASmartClient.SerialPort
{
    public class MCUSerialHelper
    {

        //private volatile static MCUSerialHelper _Instance;
        //public static MCUSerialHelper GetInstance => _Instance ?? (_Instance = new MCUSerialHelper());
        //private MCUSerialHelper() { }

        private System.IO.Ports.SerialPort comPort = new System.IO.Ports.SerialPort();
        public bool IsOpen => comPort.IsOpen;

        public bool Open(string portName, int baudRate)
        {
            while (!System.IO.Ports.SerialPort.GetPortNames().Contains(portName))
            {
                Thread.Sleep(1000);
            }
            while (!comPort.IsOpen)
            {
                comPort.PortName = portName;
                comPort.BaudRate = baudRate;
                comPort.DataBits = 8;
                comPort.Parity = Parity.None;
                comPort.StopBits = StopBits.One;
                comPort.ReadTimeout = 1000;
                comPort.WriteTimeout = 1000;
                //comPort.RtsEnable = true; //设置为 true后会读取不到数据
                //comPort.DtrEnable = true;//获取或设置一个值，该值在串行通信过程中启用数据终端就绪 (DTR) 信号。
                //comPort.RtsEnable = true;//获取或设置一个值，该值指示在串行通信中是否启用请求发送 (RTS) 信号
                try
                {
                    comPort.Open();
                }
                catch (Exception ex)
                {
                    MessageLog.GetInstance.ShowEx(ex.ToString());
                    Thread.Sleep(5000);
                }
            }
            MessageLog.GetInstance.Show($"{portName} 串口打开成功");
            return comPort.IsOpen;
        }

        private static readonly object OutPutLock = new object();
        /// <summary>
        /// 单片机输出端口控制
        /// </summary>
        /// <param name="index">通道号 1 - 8 </param>
        /// <param name="value">控制值</param>
        public void OutputControl(byte index, bool value)
        {
            lock (OutPutLock)
            {
                byte NumValue = (byte)(value ? 0x01 : 0x00);
                byte[] buffers = new byte[6] { 0xCC, 0x01, 0x01, index, NumValue, 0xDD };
                if (IsOpen) comPort.Write(buffers, 0, buffers.Length);
            }
        }

        /// <summary>
        /// 舵机控制
        /// </summary>
        /// <param name="index">通道号 1 - 8</param>
        /// <param name="value">舵机位置 0 - 180</param>
        public void ServoControl(byte index, byte value)
        {
            byte[] buffers = new byte[6] { 0xCC, 0x01, 0x02, index, value, 0xDD };
            if (IsOpen) comPort.Write(buffers, 0, buffers.Length);
        }

        /// <summary>
        /// 获取单片机输入端口状态
        /// </summary>
        /// <param name="index"></param>
        /// <returns>0:无意义 1：有信号 2：无信号 3：信号不正确</returns>
        public int GetInputStatus(byte index)
        {
            if (index <= 0 || index > 8) return 0;
            byte[] buffers = new byte[6] { 0xCC, 0x01, 0x03, index, 0x00, 0xDD };
            if (IsOpen)
            {
                comPort.Write(buffers, 0, buffers.Length);
                DateTime dt = DateTime.Now;
                List<byte> receive = new List<byte>();
                while (true)
                {
                    byte[] re = new byte[comPort.BytesToRead];
                    comPort.Read(re, 0, re.Length);
                    if (re.Contains<byte>(0xcc) && re.Contains<byte>(0xDD)) receive.AddRange(re);
                    comPort.DiscardInBuffer();
                    if (receive.Contains(0xcc) && receive.Contains(0xdd)) break;
                    if (DateTime.Now.Subtract(dt).TotalSeconds >= 2) break;
                    Thread.Sleep(1);
                }
                if (receive != null)
                {
                    int Reindex = Array.FindIndex(receive.ToArray(), p => p == 0xcc);
                    if (Reindex < receive.Count && Reindex >= 0)
                    {
                        var res = receive.GetRange(Array.FindIndex(receive.ToArray(), p => p == 0xcc), 6);
                        if (res.ElementAt(2) == 0x03)
                        {
                            if (res != null && res.Count() == 6 && res.ElementAt(4) == 0x01)
                            {
                                return 1;
                            }
                            else if (res != null && res.Count() == 6 && res.ElementAt(4) == 0x00)
                            {
                                return 2;
                            }

                        }
                        else
                        {
                            return 3;
                        }

                    }
                    else
                    {
                        return 0;
                    }
                }
            }
            return 0;
        }
    }
}
