using NLog;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Threading;

namespace GeneralGommunication
{
    /// <summary>
    /// 7E 服务端，只用于测试
    /// </summary>
    public abstract class Dev7EServer: IDev7EServer
    {
        protected Logger logger = NLog.LogManager.GetCurrentClassLogger();

        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// 包出错次数
        /// </summary>
        public int ErrCnt { get; protected set; }

        /// <summary>
        /// 通讯速度测量模块
        /// </summary>
        public CommSpeedMeasuring Csm => csm;

        /// <summary>
        /// 有数据需要发送
        /// </summary>
        public event SendMsgEventHander SendMsgEvent;

        /// <summary>
        /// 对于全部 有返回的函数调用，都使用Dispatcher,使线程同步
        /// </summary>
        public Dispatcher Dispatcher;


        List<byte> currPack = new List<byte>();

        /// <summary>
        /// 指令列表, 有数据过来，就会枚举指令列表再去执行
        /// </summary>
        protected List<COMMREQInServer> CommReqs;


        /// <summary>
        /// 发送数据指令列表
        /// </summary>
        List<COMMREQInServer_Transaction> Transactions;


        CommSpeedMeasuring csm = new CommSpeedMeasuring();

        /// <summary>
        /// 指令前序 序号
        /// </summary>
        protected int PrefixIndex { get; set; } = 1;

        
        public Dev7EServer()
        {
            Transactions = new List<COMMREQInServer_Transaction>();
            CommReqs = new List<COMMREQInServer>();
        }


        /// <summary>
        /// 在接收事件中调用；
        /// 全部接收事件 及 超时事件也是在这里触发
        /// </summary>
        /// <param name="recBuf"></param>
        public void RecMsg(byte[] recBuf) 
        {
            if (logger.IsDebugEnabled) {
                logger.Debug($"REQ {recBuf.ToString_Bytes2Hex()}");
            }
            csm.IncRec(recBuf.Count());

            for (int i = 0; i < recBuf.Count(); i++)
            {
                if (recBuf[i] == 0x7e)
                {
                    //找到头了
                    //结束之前的包
                    if (currPack.Count > 0)
                    {
                        var pack = currPack.ToArray();
                        ParsePack(pack);
                        currPack.Clear();
                        csm.IncPack(1);
                    }
                }
                currPack.Add(recBuf[i]);
            }
        }
        /// <summary>
        /// 获取 发送队列 第1条msg
        /// </summary>
        /// <returns></returns>
        public byte[] GetSendMsg()
        {
            //TODO 要处理  TimeOut / ParseFuncPack / GetSendMsg 线性同步问题

            if (Transactions.Count() == 0)//队列没有需要发送的指令
                return null;

            var tran = Transactions.First();

            Transactions.RemoveAt(0);

            
            return GetSendPack(tran);
        }
        protected virtual byte[] GetSendPack(COMMREQInServer_Transaction tran) 
        {
            //找出 COMMREQ
            var commReq = tran.commReq;
            List<byte> pack = new List<byte>();

            //添加前序
            pack.AddRange(commReq.Prefix);

            //添加数据
            if (tran.response != null)
                pack.AddRange(tran.response);

            ////调试: 打印发送信息
            //if (tran.response == null)
            //    logger.Debug($"ACK {commReq.PrefixString}");
            //else
            //    logger.Debug($"ACK {commReq.PrefixString} {Newtonsoft.Json.JsonConvert.SerializeObject(tran.datasObj)}");

            //转为 7E格式 
            var buf = GetSendPack(pack);


            return buf.ToArray();
        }

        /// 包解析
        /// </summary>
        void ParsePack(byte[] pack)
        {
            //第0个肯定是7E
            if (pack.Count() == 1)
            {
                //只有一个 7E
                return;
            }

            //转义数据
            if (!Protocol7ECommon.Pdu2Data(pack, out List<byte> datas))
            {
                //异常
                return;
            }
            //解析后的 datas 没有了 帧包装 7E

            pack = datas.ToArray();

            if (pack.Count() == 1)
            {
                //只有一个字节，异常！！！
                ErrCnt++;
                return;
            }

            //解析后的 datas 没有了 帧包装 7E
            byte crc8 = Misc.CRC.CRC8(pack, 0, pack.Count() - 1);
            if (pack.Last() != crc8)
            {
                //CRC8 出错
                ErrCnt++;
                return;
            }

            ParsePackAfterCheckCRC8(pack);
        }
        protected abstract void ParsePackAfterCheckCRC8(byte[] buf);


        /// <summary>
        /// 功能包解析
        /// </summary>
        /// <param name="datas"></param>
        protected virtual void ParseFuncPack(byte[] pack)
        {
            //已经回复
            var commReq = CommReqs.Find(c => IsMatch(c, pack));
            if (commReq == null)
            {
                ErrCnt++;
                logger.Error($"ACK 收到不支持的请求");
                return;
            }
            //还有B0
            var response = commReq.ParseFuncPack(pack, commReq.Prefix.Count() + PrefixIndex);

            if (logger.IsDebugEnabled) {
                if(response!=null)
                    logger.Debug($"ACK {commReq.PrefixString} {response.ToString_Bytes2Hex()}");
                else
                    logger.Debug($"ACK {commReq.PrefixString}");
            }
            AddTran(new COMMREQInServer_Transaction()
            {
                commReq = commReq,
                response = response
            });
        }

        /// <summary>
        /// 与指令前序比较，一定要完全一样
        /// </summary>
        /// <param name="commreq"></param>
        /// <param name="datas"></param>
        /// <returns></returns>
        protected bool IsMatch(COMMREQInServer commreq, byte[] datas)
        {
            int prefix_index = PrefixIndex;
            //datas[0] 是B0, 不应该用于判断

            //与指令前序一个个比较
            for (int i = 0; i < commreq.Prefix.Length; i++)
            {
                if (commreq.Prefix[i] != datas[prefix_index + i])
                {
                    return false;
                }
            }

            return true;
        }

        /// <summary>
        /// 数据发送，输入不需要包含开头的7E； 输出会添加CRC8 和 7E
        /// </summary>
        /// <param name="datas"></param>
        protected virtual List<byte> GetSendPack(List<byte> datas)
        {
            //需要在后面添加CRC8
            byte crc8 = Misc.CRC.CRC8(datas, 0, datas.Count());
            datas.Add(crc8);

            Protocol7ECommon.Data2Pdu(datas, out List<byte> pack);
            pack.Add(0x7E);//一定要加0x7E
            return pack;
        }
        
        protected void AddTran(COMMREQInServer_Transaction tran)
        {
            //放入 交易队列
            Transactions.Add(tran);
            SendMsgEvent?.Invoke(this);
        }

        public void Dispose()
        {

        }
    }
    public interface IDev7EServer : INotifyPropertyChanged,IDisposable
    {
        #region 测量通讯速度
        CommSpeedMeasuring Csm { get; }
        #endregion

        /// <summary>
        /// 包出错次数
        /// </summary>
        int ErrCnt { get; }

        /// <summary>
        /// 有数据需要发送
        /// </summary>
        event SendMsgEventHander SendMsgEvent;

        /// <summary>
        /// 在接收事件中调用；
        /// 全部接收事件 及 超时事件也是在这里触发
        /// </summary>
        /// <param name="recBuf"></param>
        void RecMsg(byte[] recBuf);

        byte[] GetSendMsg();


    }

    /// <summary>
    /// 通知指令
    /// </summary>
    public class COMMREQInServer
    {
        private byte[] prefix;
        /// <summary>
        /// 指令 前缀
        /// </summary>
        public byte[] Prefix
        {
            get { return prefix; }
            set
            {
                prefix = value;
                updatePrefixString();
            }
        }
        public string PrefixString { get; private set; }
        void updatePrefixString()
        {
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < Prefix.Count(); i++)
            {
                if (Prefix[i] >= 33 && Prefix[i] <= 126)
                    stringBuilder.Append((char)Prefix[i]);
                else
                    stringBuilder.Append($" 0x{Prefix[i]:X2} ");
            }
            PrefixString = stringBuilder.ToString();
        }
        
        /// <summary>
        /// 请求数据 长度, 不含前序
        /// </summary>
        public int RequestLen;

        /// <summary>
        /// 回复数据 总长度, 含前序
        /// </summary>
        public int RequestTotalLen => Prefix.Length + RequestLen;

        public delegate byte[] ParseFuncPackHandler(byte[] pack, int dataIdx);

        public ParseFuncPackHandler ParseFuncPack;
        public delegate bool IsMatchHandler(COMMREQ commReq, byte[] pack, int dataIdx, object context, ref object retData);
        public IsMatchHandler IsMatch;
        public object IsMatchContext;
        public static byte[] ToPrefix(params object[] commands)
        {
            List<byte> bytes = new List<byte>();
            foreach (var command in commands)
            {
                if (command is string)
                {
                    var c = (string)command;
                    foreach (var _c in c)
                    {
                        bytes.Add((byte)_c);
                    }
                }
                else if (command is char)
                {
                    var c = (char)command;
                    bytes.Add((byte)c);
                }
                else if (command is byte)
                {
                    var c = (byte)command;
                    bytes.Add(c);
                }
                else if (command is int)
                {
                    var c = (int)command;
                    bytes.Add((byte)c);
                }
                else
                {
                    throw new Exception("不支持该类型");
                }
            }
            if (bytes.Count < 2)
                throw new Exception("指令少于 2bytes");
            return bytes.ToArray();
        }
    }

    public class COMMREQInServer_Transaction
    {
        /// <summary>
        /// 请求
        /// </summary>
        public COMMREQInServer commReq;
        /// <summary>
        /// 数据回复
        /// </summary>
        public byte[] response;
    }
}
