using ProjectManagementSystem.Device.Function;
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;

namespace ProjectManagementSystem.Device.CasunBox
{
    public abstract class BoxCommunicationBase : IBoxCommunication
    {
        
        protected InfoBox m_infoBox = new InfoBox();
        protected ConcurrentDictionary<int, InfoBox> m_boxInfoDict = new ConcurrentDictionary<int, InfoBox>();
        protected ConcurrentQueue<BoxCommandBase> m_boxCommandQueue = new ConcurrentQueue<BoxCommandBase>();

        public ConcurrentDictionary<int, InfoBox> InfoBoxDict { get { return m_boxInfoDict; } }
        public bool IsStart { get; private set; }

        public event Action<string, Exception> OnLogMsg;
        public event Action<InfoBox> OnInfoBox;
        public virtual void Start()
        {
            Task.Factory.StartNew(UserThread);
            IsStart = true;
        }
        public abstract void Stop();
        public abstract void SendCommand(BoxCommandBase command);
        public void CommandEnqueue(BoxCommandBase boxCommand)
        {
            m_boxCommandQueue.Enqueue(boxCommand);
        }
        public void RecivedData(byte[] data, Action<InfoBox> action)
        {
            bool checkXOR = CheckXOR(data);
            if (!checkXOR) return;

            m_infoBox.Deserialize(data);
            InfoBox info = m_boxInfoDict.ContainsKey(m_infoBox.Route) ? m_boxInfoDict[m_infoBox.Route] : new InfoBox();
            info.EBoxDevice = m_infoBox.EBoxDevice;
            info.LastUpdateTime = m_infoBox.LastUpdateTime;
            info.Route = m_infoBox.Route;
            info.Status = m_infoBox.Status;
            info.LightStatus = m_infoBox.LightStatus;
            info.CheckXOR = checkXOR;

            action(info);//执行其他动作
            m_boxInfoDict.AddOrUpdate(m_infoBox.Route, info, (key, value) => info);

            if (info.EBoxDevice == EnumBoxDevice.CallBox
                && (info.Status == 0x41 || info.Status == 0x42))
            {
                CommandReply boxReply = new CommandReply();
                boxReply.Route = info.Route;
                boxReply.CurrentData = data;
                boxReply.Function = (byte)(data[1] + 2);
                m_boxCommandQueue.Enqueue(boxReply);
            }

            OnInfoBox?.Invoke(info);
        }

        protected bool CheckXOR(byte[] array)
        {
            if (array == null || array.Length < 14) return false;

            //0x20回复为报警灯协议，最后一个字节为校验位
            int xorIndex = array[0] == 0x20 ? array.Length - 1 : array.Length - 2;
            if (Tools.XOR_Check(array, xorIndex) == array[xorIndex])
            {
                return true;
            }
            return false;
        }

        protected void LogMsg(string log, Exception ex = null)
        {
            OnLogMsg?.Invoke(log, ex);
        }

        private void UserThread()
        {
            while (true)
            {
                try
                {
                    SendDataProc();
                }
                catch (Exception ex)
                {
                    LogMsg("发送线程异常", ex);
                }
                System.Threading.Thread.Sleep(30);
            }
        }
        private void SendDataProc()
        {
            while (m_boxCommandQueue.TryDequeue(out BoxCommandBase command))
            {
                SendCommand(command);
                break;
            }
        }
    }
}
