using ProductionControl.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;

namespace ProductionControl.Device
{
    public class TensionDev : IDisposable
    {
        public double TensionValue { private set; get; }
        public string Unit { get; private set; }

        public Action<WarningEnum, string> WarningEvent;
        /// <summary>
        /// 值<值，单位>
        /// </summary>
        public Action<double,string> TensionEvent;
        /// <summary>
        /// 是否打开设备成功
        /// </summary>
        public bool IsInit { get; private set; } = false;
        private System.Timers.Timer timer = new System.Timers.Timer();

        private SSerialPort sSerialPort;
        private bool _isDebug=false;
        public TensionDev(bool isDebug)
        { 
            _isDebug= isDebug;
        }
        public TensionDev()
        {
        }
        public bool start(int comNum)
        {
            try
            {
                sSerialPort = new SSerialPort("COM" + comNum, 2400, 1);

                IsInit = true;
                if (_isDebug)
                {
                    timer.Elapsed += Timer_Elapsed;
                    timer.Interval = 300;
                    timer.Start();
                }
                return true;
            }
            catch (Exception ex)
            {
                WarningEvent?.Invoke(WarningEnum.High, ex.Message);
                try { sSerialPort.close(); } catch { }
                return false;
            }
        }
        public void stop()
        {
            if (!IsInit) return;

            IsInit = false;
            if (_isDebug)
            {
                timer.Elapsed -= Timer_Elapsed;
                timer.Stop();
            }
            sSerialPort.close();
        }

        private bool reading=false;
        private void Timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            if (!IsInit || reading) return;

            API.OutputDebugString($"Timer_Elapsed:{reading}");
            reading = true;
            getValue();
            reading = false;
        }
        private readonly byte[] HEAD = { 0x10,0x08,0x19 };
        private readonly byte[] EOT = { 0x0D, 0x0A };
        public double getValue()
        {
            try
            {
                if (!IsInit) return -1; 
                //接收 
                int readTimeout = 3000;
                byte[] recv, data=null;
                IEnumerable<long> indexList;
                //找HEAD
                do
                {
                    recv = sSerialPort.getMessage(readTimeout);
                    if (recv == null || recv.Length < 1)
                        throw new Exception("无数据或接收超时(HEAD)！");

                    API.OutputDebugString($"RECV HEAD:{HexUtil.toHexString(recv)}");
                    //合并后的
                    if (data == null || data.Length < 1) 
                        data = recv;
                    else
                        data = HexUtil.joinByteList(new List<byte[]> { data, recv });
                    indexList = Utils.HexUtil.IndexOf(data, 0, HEAD);
                } while (indexList.Count() == 0);
                data = HexUtil.subBytes(data, (int)indexList.Last());
                API.OutputDebugString($"HEAD:{HexUtil.toHexString(data)}");
                //找EOT 
                //indexList = Utils.HexUtil.IndexOf(data, 0, EOT);
                //while (indexList.Count() == 0)
                //{
                //    recv = comPortJDJ.getMessage(readTimeout);
                //    if (recv == null || recv.Length < 1)
                //        throw new Exception("无数据或接收超时(EOT)！");
                //    //AddTextEvent("焦度计", $"读取数据:{HexUtil.toHexString(recv)}");
                //    //合并后的
                //    data = HexUtil.joinByteList(new List<byte[]> { data, recv });
                //    indexList = Utils.HexUtil.IndexOf(data, 0, JDJ_EOT);
                //}
                //data = HexUtil.subBytes(data, 0, (int)indexList.First() + JDJ_EOT.Length); 
                // byte长度 总报文11byte-3head=8
                while (data.Length<11)
                { 
                    recv = sSerialPort.getMessage(readTimeout);
                    if (recv == null || recv.Length < 1)
                        throw new Exception("无数据或接收超时(EOT)！");
                    API.OutputDebugString($"RECV EOT:{HexUtil.toHexString(recv)}");
                    //合并后的
                    data = HexUtil.joinByteList(new List<byte[]> { data, recv }); 
                }
                data = HexUtil.subBytes(data, 0, 11);
                API.OutputDebugString($"RECV DATA:{HexUtil.toHexString(data)}"); 
                var buff = data;

                //if (buff.Length % 11 != 0)
                //    throw new Exception("Tension数据错误！");
                //if (buff.Length > 11)
                //    buff = subBuff(buff, buff.Length - 11, 11);
                //if (buff[0] != 0x10)
                //    throw new Exception("Tension数据0错误！");
                int add = 0;
                for (int i = 1; i < 10; i++)
                    add += (int)buff[i];
                if (add != buff[10])
                    throw new Exception("Tension数据ADD错误！");

                string unit = buff[3] == 0x10 ? "N/cm" : "Kgf/cm";
                string szData = "";
                int zf = 1;
                for (int i = 4; i <= 8; i++)
                {
                    if (buff[i] == 0x0a) continue;
                    if (buff[i] == 0x0b) zf = -1;
                    if (buff[i] < 0x0a)
                        szData += (int)buff[i];
                }
                double ldNum = Convert.ToDouble(szData) * zf;
                if (buff[9] > 0) ldNum /= Math.Pow(10, buff[9]);
                //
                //int add = 0;
                //for (int i = 1; i < HEAD.Length; i++)
                //    add += (int)HEAD[i];
                //for (int i = 0; i < buff.Length-1; i++)
                //    add += (int)buff[i];

                //if (add != buff[buff.Length - 1])
                //    throw new Exception("Tension数据ADD错误！");

                //string unit = buff[0] == 0x10 ? "N/cm" : "Kgf/cm";
                //string szData = "";
                //int zf = 1;
                //for (int i = 1; i <= 5; i++)
                //{
                //    if (buff[i] == 0x0a) continue;
                //    if (buff[i] == 0x0b) zf = -1;
                //    if (buff[i] < 0x0a)
                //        szData += (int)buff[i];
                //}
                //double ldNum = Convert.ToDouble(szData) * zf;
                //if (buff[6] > 0) ldNum /= Math.Pow(10, buff[6]);

                //
                TensionValue = ldNum;
                Unit = unit;
                TensionEvent?.Invoke(ldNum, unit);
                return ldNum;
            }
            catch (Exception ex)
            {
                API.OutputDebugString($"ERR:{ex.Message}");
                WarningEvent?.Invoke(WarningEnum.Low,ex.Message);
                return -1;
            }
        }
        private byte[] subBuff(byte[] buff, int start, int length)
        {
            byte[] res = new byte[length];
            for (int i = start; i < buff.Length && i < start + length; i++)
                res[i - start] = buff[i];
            return res;
        }

        public void Dispose()
        {
            stop();
        }
    }
}
