using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Net;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using VzClientSDKDemo;

namespace NumMachine
{
    /// <summary>
    /// 号牌机通信类
    /// </summary>
    public class NumMachineLinker 
    {
        /// <summary>
        /// 刷新时间间隔与个数
        /// </summary>
        public const int REFRESHINGTIME = 500, FILTERINGNUMBER = 2, NUMBERMACHINE_COUNT = 1, BUFFER_MAX_COUNT = 20;
        ///<summary>通过ip获取设备id；产生ip时创建</summary>
        private Dictionary<string, int> ipIdMap = new Dictionary<string, int>();
        ///<summary>通过ip获取设备句柄；产生句柄时创建</summary>
        private Dictionary<string, int> ipHandleMap = new Dictionary<string, int>();
        /// <summary>句柄到号牌回调映射</summary>
        private Dictionary<int, VzClientSDK.VZLPRC_PLATE_INFO_CALLBACK> handleCallbackMap = new Dictionary<int, VzClientSDK.VZLPRC_PLATE_INFO_CALLBACK>();
        ///<summary>号牌队列</summary>
        private Queue<NumberMachineNode> LicBuffer = new Queue<NumberMachineNode>();
        ///// <summary> 终端编号与当前号牌映射表</summary>
        //private Dictionary<int, string> idLicenseMap = new Dictionary<int, string>();

        /// <summary>筛选计数</summary>
        private int filterCount = 0;
        private double filterRatio = 0.7;
        /// <summary>系统关闭</summary>
        private bool isClosing = false;
        private bool isWorking = false;
        /// <summary>
        /// 当前号牌结构体
        /// </summary>
        private string currentLic;

        private NumberMachineMessage nmMsg = new NumberMachineMessage();
        private bool get_current_license = false;
        private VzClientSDK.VZLPRC_FIND_DEVICE_CALLBACK_EX find_DeviceCB = null;
        private const int MSG_PLATE_INFO = 0x901;
        private const int MSG_DEVICE_INFO = 0x902;

        /// <summary>
        /// 号牌机类构造函数
        /// </summary>
        public NumMachineLinker()
        {
            currentLic = "";
            try
            {
                VzClientSDK.VzLPRClient_Setup();
                filterRatio = Double.Parse(ConfigurationManager.AppSettings.Get("filterRatio"));
            }
            catch (Exception e) { Console.WriteLine(e.Message + ",号牌机配置文件异常"); }
            //m_sAppPath = System.IO.Directory.GetCurrentDirectory();
        }
        ~NumMachineLinker()
        {
            isClosing = true;
        }

        //******************************************************************************************************************
        private void UpdateStatus(NumberMachineNode nmn)
        {
            //提示次数计数
            int count = 0;
            while (!isClosing)
            {
                if (GetStatus(nmn.ip) == 1)
                {
                    nmn.status = EnumNumberMachineStatus.Normal;
                    count = 0;
                    Thread.Sleep(500);
                }
                else
                {
                    count++;
                    //号牌机断线写日志
                    nmn.status = EnumNumberMachineStatus.Offline;
                    if (count == 1)
                    {
                        Console.WriteLine("正在与ip为 " + nmn.ip + " 的号牌机 进行连接。");
                    }
                    else if (count == 30)
                    {
                        nmMsg.data.Remove(nmn);
                    }
                    Thread.Sleep(10000);
                }
            }
        }

        /// <summary>
        /// 工作线程
        /// </summary>
        private void WorkingThreadFunc()
        {
            while(!isClosing)
            {
                if(isWorking)
                {
                    Dictionary<string, int>.Enumerator HandleEnumer = ipHandleMap.GetEnumerator();
                    DateTime t0 = DateTime.Now;
                    while (HandleEnumer.MoveNext())
                    {
                        //get_current_license = false;
                        ActivateSnap(HandleEnumer.Current.Value);
                        //Console.WriteLine(HandleEnumer.Current);
                        Thread.Sleep(10);
                    }
                }
                Thread.Sleep(500);
            }
        }

        ///<summary>寻找设备回调函数</summary>
        private void FIND_DEVICE_CALLBACK_EX(string pStrDevName, string pStrIPAddr, ushort usPort1, ushort usPort2, uint SL, uint SH, string netmask, string gateway, IntPtr pUserData)
        {
            string pStrDev = pStrIPAddr.ToString() + ":" + usPort1.ToString();
            string serialNO = SL.ToString() + ":" + SH.ToString() + ":" + netmask + ":" + gateway;

            Console.WriteLine(pStrDev);
            VzClientSDK.VZ_LPR_DEVICE_INFO device_info = new VzClientSDK.VZ_LPR_DEVICE_INFO();
            device_info.device_ip = pStrDev;
            device_info.serial_no = serialNO;
            DeviceLink(pStrDev, serialNO);
        }

        ///<summary>与设备连接，启动更新设备状态线程，输出视频</summary>
        private void DeviceLink(string pStrDev, string serialNO)
        {
            IPEndPoint ipe;
            GetIpEndPoint(pStrDev, out ipe);
            string ip = ipe.Address.ToString();

            int id = 0;
            //读到设备则添加id映射并初始化号牌计数器
            lock (ipIdMap)
            {
                if (!ipIdMap.ContainsKey(ip))
                {
                    try
                    {
                        //id = Int32.Parse(ConfigurationManager.AppSettings.Get(ip));
                        if(ip== tool.json_file_operation.Instance.read_json_string("numberMachine_ip"))
                            ipIdMap.Add(ip, 0);
                        //idCountMap.Add(id, FILTERINGNUMBER);
                        //GetLicensePlate(id);
                    }
                    catch (Exception) { Console.WriteLine("读取号牌机编号映射失败，配置文件填写有误---" + ip); id = -1; }
                }
            }
            if (id < 0)
                return;

            if (ipHandleMap.ContainsKey(ip))
            {
                //MessageBox.Show("设备已分配句柄");
                return;
            }
            int handle = 0;

            handle = VzClientSDK.VzLPRClient_Open(ip, (ushort)80, "admin", "admin");

            if (handle == 0)
            {
                return;
            }

            //将句柄加入
            lock (ipHandleMap)
            {
                ipHandleMap.Add(ip, handle);
            }

            //找到设备，加入list
            NumberMachineNode node = new NumberMachineNode(ip, id, "", "", 1);
            nmMsg.data.Add(node);
            Task.Factory.StartNew(() =>
            {
                UpdateStatus(node);
            });
            lock (handleCallbackMap)
            {
                handleCallbackMap.Add(handle, null);
                handleCallbackMap[handle] = new VzClientSDK.VZLPRC_PLATE_INFO_CALLBACK(OnPlateResult);
                VzClientSDK.VzLPRClient_SetPlateInfoCallBack(handle, handleCallbackMap[handle], IntPtr.Zero, 1);
            }
        }

        ///<summary>号牌信息回调</summary>
        private int OnPlateResult(int handle, IntPtr pUserData,
                                                IntPtr pResult, uint uNumPlates,
                                                VzClientSDK.VZ_LPRC_RESULT_TYPE eResultType,
                                                IntPtr pImgFull,
                                                IntPtr pImgPlateClip)
        {
            if (eResultType != VzClientSDK.VZ_LPRC_RESULT_TYPE.VZ_LPRC_RESULT_REALTIME)
            {
                VzClientSDK.TH_PlateResult result = (VzClientSDK.TH_PlateResult)Marshal.PtrToStructure(pResult, typeof(VzClientSDK.TH_PlateResult));
                string strLicense = (new string(result.license)).Split('\0')[0];

                VzClientSDK.VZ_LPR_MSG_PLATE_INFO plateInfo = new VzClientSDK.VZ_LPR_MSG_PLATE_INFO();
                plateInfo.plate = strLicense;
                SetDetail(plateInfo, Get_IP(handle));
            }

            return 0;
        }

        ///<summary>记录车牌，时间，状态信息；刷新本地entity，并且入buffer</summary>
        private void SetDetail(VzClientSDK.VZ_LPR_MSG_PLATE_INFO plateInformation, string strIP)
        {
            get_current_license = true;
            int stat = GetStatus(strIP);
            bool found = false;
            int id = 0;

            // 控制队列大小
            lock (LicBuffer)
            {
                while (LicBuffer.Count > BUFFER_MAX_COUNT)
                {
                    LicBuffer.Dequeue();
                }
            }

            //检查设备是否存在
            //foreach (NumberMachineNode nmn in nmMsg.data)
            for (int i = 0; i < nmMsg.data.Count; i++)
            {
                NumberMachineNode nmn = nmMsg.data[i];
                //相同设备
                if (nmn.ip == strIP)
                {
                    found = true;
                    //号牌不为空
                    if (!(plateInformation.plate.Contains("_无_")))
                    {
                        //Log.WriteLog(LogType.process, LogFile.INFO, nmn.id + "收到号牌回调信息: [" + plateInformation.plate + "]");
                        //nmn.SetLic(strIP, nmn.id, plateInformation.plate, DateTime.Now.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss"), GetStatus(strIP));
                        //FilterLic(strIP, (NumberMachineNode)nmn.Clone());
                        lock (LicBuffer)
                        {
                            for (int j = 0; j < nmMsg.data.Count; j++)
                            {
                                if(nmMsg.data[j].id == nmn.id)
                                {
                                    nmMsg.data[j].LicenseNum = plateInformation.plate;
                                    break;
                                }
                            }
                            LicBuffer.Enqueue(new NumberMachineNode(strIP, nmn.id, plateInformation.plate, DateTime.Now.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss"), GetStatus(strIP)));
                        }
                    }
                    //号牌为空
                    else
                    {
                        //NumberMachineNode nmn_temp = new NumberMachineNode(strIP, nmn.id, "", "", GetStatus(strIP));
                        //nmn.SetLic(strIP, nmn.id, "", "", GetStatus(strIP));
                        //FilterLic(strIP, nmn_temp);
                        lock (LicBuffer)
                        {
                            for (int j = 0; j < nmMsg.data.Count; j++)
                            {
                                if (nmMsg.data[j].id == nmn.id)
                                {
                                    nmMsg.data[j].LicenseNum = "";
                                    break;
                                }
                            }
                            LicBuffer.Enqueue(new NumberMachineNode(strIP, nmn.id, "", "", GetStatus(strIP)));
                        }
                    }
                }
            }
            //新设备
            if (!found)
            {
                lock (ipIdMap)
                {
                    if (!(plateInformation.plate.Contains("_无_")) && ipIdMap.TryGetValue(strIP, out id))
                    {
                        NumberMachineNode nmn = new NumberMachineNode(/*strIP, id, plateInformation.plate, DateTime.Now.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss"), GetStatus(strIP)*/);
                        //NumberMachineNode nmnc = (NumberMachineNode)nmn.Clone();
                        //nmMsg.data.Add(nmn);
                        //FilterLic(strIP, nmn);
                        lock (LicBuffer)
                        {
                            for (int j = 0; j < nmMsg.data.Count; j++)
                            {
                                if (nmMsg.data[j].id == id)
                                {
                                    nmMsg.data[j].LicenseNum = plateInformation.plate;
                                    break;
                                }
                            }
                            LicBuffer.Enqueue(new NumberMachineNode(strIP, id, plateInformation.plate, DateTime.Now.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss"), GetStatus(strIP)));
                        }
                    }
                    else
                    {
                        //NumberMachineNode nmn = new NumberMachineNode(strIP, id, "", "", GetStatus(strIP));
                        //nmMsg.data.Add(nmn);
                        //FilterLic(strIP, nmn);
                        Console.WriteLine("异常的号牌回调:"+strIP);
                        //lock (LicBuffer)
                        //{
                        //    LicBuffer.Enqueue(new NumberMachineNode(strIP, id, "", "", GetStatus(strIP)));
                        //}
                    }
                }
            }
        }

        ///<summary>强制获取号牌</summary>
        private void ActivateSnap(int handle)
        {
            if (handle > 0)
            {
                VzClientSDK.VzLPRClient_ForceTrigger(handle);
            }
        }

        ///<summary>ip+port字符串转ipe</summary>
        private void GetIpEndPoint(string ipp, out IPEndPoint ipe)
        {
            IPAddress myIP = IPAddress.Parse(ipp.Remove(ipp.LastIndexOf(':')) + "");
            string myPort = ipp.Substring(ipp.IndexOf(':') + 1);
            ipe = new IPEndPoint(myIP, int.Parse(myPort));
        }

        ///<summary>更新设备状态</summary>
        private int GetStatus(string devIP)
        {
            int myHandle;
            byte stat = 0;
            try
            {
                if (ipHandleMap.TryGetValue(devIP, out myHandle))
                {
                    VzClientSDK.VzLPRClient_IsConnected(myHandle, ref stat);
                    return stat;
                }
            }
            catch { Console.WriteLine("获取设备状态异常"); }
            return -1;
        }

        private string Get_IP(int lprHandle)
        {
            byte[] strDecIP = new byte[32];
            int max_count = 32;
            int ret = VzClientSDK.VzLPRClient_GetDeviceIP(lprHandle, ref strDecIP[0], max_count);
            string strIP = System.Text.Encoding.Default.GetString(strDecIP);
            strIP = strIP.TrimEnd('\0');
            return strIP;
        }

        private bool NodeValidation(NumberMachineNode node)
        {
            return (node != null && node.ip != null && node.ip != "" && node.ip != "used" && node.LicenseNum != null && node.LicenseNum != "") ? true : false;
        }

        ///// <summary>
        ///// 更新终端编号与号牌映射表
        ///// </summary>
        ///// <param name="license"></param>
        ///// <param name="clearBuffer"></param>
        //private void UpdateIdLicenseMap(bool clearBuffer)
        //{
        //    NumberMachineNode node = null;
        //    lock (LicBuffer)
        //    {
        //        idLicenseMap.Clear();
        //        for (int i = 0; i < LicBuffer.Count; i++)
        //        {
        //            node = LicBuffer.Dequeue();
        //            if (node != null)
        //            {
        //                if (!idLicenseMap.ContainsKey(node.id))
        //                {
        //                    idLicenseMap.Add(node.id, node.LicenseNum);
        //                }
        //                else
        //                {
        //                    idLicenseMap[node.id] = node.LicenseNum;
        //                }
        //            }
        //            if (!clearBuffer)
        //                LicBuffer.Enqueue(node);
        //        }
        //    }
        //}

        /// <summary>
        /// 系统启动
        /// </summary>
        public void Start()
        {
            Task.Factory.StartNew(() =>
            {
                isClosing = false;

                VzClientSDK.VZLPRClient_StopFindDevice();

                find_DeviceCB = new VzClientSDK.VZLPRC_FIND_DEVICE_CALLBACK_EX(FIND_DEVICE_CALLBACK_EX);
                int ret = VzClientSDK.VZLPRClient_StartFindDeviceEx(find_DeviceCB, IntPtr.Zero);

                int stopCountdown = 180;
                while (stopCountdown-- > 0 && NUMBERMACHINE_COUNT > ipIdMap.Count)
                {
                    Thread.Sleep(1000);
                }
                VzClientSDK.VZLPRClient_StopFindDevice();

            });

            Task.Factory.StartNew(() =>
            {
                WorkingThreadFunc();
            });

            //应答模式下号牌机不需要清除号牌
            //Task.Factory.StartNew(() =>
            //{
            //    Run();
            //});
        }

        /// <summary>
        /// 系统关闭
        /// </summary>
        public void Stop()
        {
            isClosing = true;
            try
            {
                VzClientSDK.VZLPRClient_StopFindDevice();
            }
            catch (Exception e)
            {

            }
            lock (ipIdMap) { ipIdMap.Clear(); }
            lock (ipHandleMap) { ipHandleMap.Clear(); }
            //this.Close();
        }

        /// <summary>
        /// 设置开始与结束拍摄号牌指令
        /// </summary>
        /// <param name="cmd"></param>
        public bool SetCmd(EnumNumberMachineCmd cmd)
        {
            switch (cmd)
            {
                case EnumNumberMachineCmd.StartWork:
                    if (isWorking)
                        return false;
                    lock (LicBuffer)
                    {
                        LicBuffer.Clear();
                    }
                    isWorking = true;
                    return true;
                case EnumNumberMachineCmd.StopWork:
                    if (!isWorking)
                        return false;
                    isWorking = false;
                    int id = -1;
                    lock (LicBuffer)
                    {
                        Dictionary<string, int> LicCountMap = new Dictionary<string, int>();
                        for (int i = 0; i < LicBuffer.Count; i++)
                        {
                            var node = LicBuffer.Dequeue();
                            if (id < 0)
                                id = node.id;
                            if (LicCountMap.ContainsKey(node.LicenseNum))
                            {
                                LicCountMap[node.LicenseNum]++;
                            }
                            else
                            {
                                LicCountMap.Add(node.LicenseNum, 0);
                            }
                        }
                        Dictionary<string, int>.Enumerator enumer = LicCountMap.GetEnumerator();
                        int maxCount = -1;
                        string filteredLic = "";
                        while (enumer.MoveNext())
                        {
                            if (maxCount < enumer.Current.Value)
                            {
                                maxCount = enumer.Current.Value;
                                filteredLic = enumer.Current.Key;
                            }
                        }
                        currentLic = filteredLic;
                    }
                    return true;
            }
            return false;
        }

        public bool GetLicense(out string lic)
        {
            lic = currentLic;
            if (isWorking)
                return false;
            else
                return true;
        }

        /// <summary>
        /// 监控线程获取号牌机信息，核心线程获取号牌信息
        /// </summary>
        public NumberMachineMessage GetMessage()
        {
            return nmMsg;
        }

        /// <summary>
        /// 暂未使用！！！一次停车流程完成时调用该方法，发送已完成车辆号牌信息
        /// </summary>
        /// <param name="message">已完成车辆的号牌相关信息存于message的aNode中,用于标记需清空的号牌</param>
        public void SetMessage(NumberMachineMessage message)
        {
            //NumberMachineNode n = ((NumberMachineMessage)message).aNode;
            //lock (LicBuffer)
            //{
            //    //输入号牌格式无误
            //    if (n != null && n.ip != null && n.ip == "")
            //    {
            //        //与类成员变量中aNode号牌相同，将其ip复位表示已使用，重新入队等待清除
            //        if (nmMsg != null && nmMsg.aNode != null && nmMsg.aNode.LicenseNum == n.LicenseNum)
            //        {
            //            nmMsg.aNode.ip = "";
            //            LicBuffer.Enqueue((NumberMachineNode)nmMsg.aNode.Clone());
            //            nmMsg.aNode = null;
            //        }
            //        //搜索号牌队列，将相应号牌置空，准备清除
            //        else
            //        {
            //            for (int i = 0; i < LicBuffer.Count; i++)
            //            {
            //                NumberMachineNode temp = LicBuffer.Dequeue();
            //                //已匹配上，ip置空
            //                if (temp.LicenseNum == n.LicenseNum)
            //                {
            //                    temp.ip = "";
            //                    LicBuffer.Enqueue(temp);
            //                    break;
            //                }
            //                LicBuffer.Enqueue(temp);
            //            }
            //        }
            //    }
            //}
        }

        /// <summary>
        /// 根据id获取号牌
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public string GetLicensePlate(int id)
        {
            Dictionary<string, int>.Enumerator HandleEnumer = ipHandleMap.GetEnumerator();
            DateTime t0 = DateTime.Now;
            while (HandleEnumer.MoveNext())
            {
                if(ipIdMap.TryGetValue(HandleEnumer.Current.Key, out int handle_id) && handle_id == id)
                {
                    //get_current_license = false;
                    ActivateSnap(HandleEnumer.Current.Value);
                    //Console.WriteLine(HandleEnumer.Current);
                }
            }

            // 避免阻塞
            //DateTime t1 = DateTime.Now;
            //while (!get_current_license && (t1-t0).Milliseconds < 1000)
            //{
            //    t1 = DateTime.Now;
            //}
            //if (!get_current_license)
            //return "";

            foreach (NumberMachineNode nmn in nmMsg.data)
            {
                if(nmn.id == id)
                {
                    return nmn.LicenseNum;
                }
            }
            return "";

            //string license = "空";
            //NumberMachineNode node = null;
            ////Task.Factory.StartNew(() =>
            ////{
            ////清除同终端号过期号牌
            //lock (LicBuffer)
            //{
            //    for (int i = 0; i < LicBuffer.Count; i++)
            //    {
            //        node = LicBuffer.Dequeue();
            //        if (node != null)
            //        {
            //            if (node.id != id)
            //            {
            //                LicBuffer.Enqueue(node);
            //            }
            //        }
            //    }
            //}
            ////将相应计数器归零,启动号牌记录
            //int handle = 0;
            //lock (idCountMap)
            //{
            //    if (idCountMap.ContainsKey(id))
            //    {
            //        Dictionary<string, int>.Enumerator ipidEnumer = ipIdMap.GetEnumerator();
            //        while (ipidEnumer.MoveNext())
            //        {
            //            if (ipidEnumer.Current.Value == id)
            //            {
            //                ipHandleMap.TryGetValue(ipidEnumer.Current.Key, out handle);
            //                break;
            //            }
            //        }
            //        idCountMap[id] = 0;
            //        int count = 0;
            //        while (count <= FILTERINGNUMBER)
            //        {
            //            //Console.WriteLine(handle);
            //            ActivateSnap(handle);
            //            count++;
            //            Thread.Sleep((int)(REFRESHINGTIME));
            //        }
            //    }
            //}
            //node = null;
            //int timeLimit = FILTERINGNUMBER * 2;
            //while (node == null && timeLimit-- > 0)
            //{
            //    lock (LicBuffer)
            //    {
            //        //Log.WriteLog(LogType.process, LogFile.INFO, "licBuffer 元素个数：" + LicBuffer.Count);
            //        for (int i = 0; i < LicBuffer.Count; i++)
            //        {
            //            node = LicBuffer.Dequeue();
            //            if (node != null)
            //            {
            //                if (node.id == id && node.LicenseNum != "")
            //                {
            //                    license = node.LicenseNum;
            //                    //Log.WriteLog(LogType.process, LogFile.INFO, "license: " + license + ", id: " + id);
            //                    break;
            //                }
            //                else
            //                {
            //                    //Log.WriteLog(LogType.process, LogFile.INFO, "other license: " + node.LicenseNum + ", id: " + node.id);
            //                    LicBuffer.Enqueue(node);
            //                }
            //            }
            //        }
            //    }
            //    Thread.Sleep(REFRESHINGTIME);
            //}
            //if (timeLimit <= 0) { Console.WriteLine("本次未找到号牌"); /*Log.WriteLog(LogType.process, LogFile.INFO, id + "号号牌机未找到号牌");*/ }
            //else {
            //    //Log.WriteLog(LogType.process, LogFile.INFO, id + "号号牌机本次号牌: [" + license + "]");
            //}
            ////}).Wait();

            //return license == "空" ? "" : license;
        }

        ///// <summary>
        ///// 获取号牌对应ID，以在手机停取时确定终端编号
        ///// </summary>
        ///// <param name="license"></param>
        ///// <returns></returns>
        //public int GetLicenseID(string license)
        //{
        //    int id = 0;
        //    //启动所有号牌记录
        //    lock (ipHandleMap)
        //    {
        //        for (int i = 0; i < FILTERINGNUMBER; i++)
        //        {
        //            Dictionary<string, int>.Enumerator HandleEnumer = ipHandleMap.GetEnumerator();
        //            while (HandleEnumer.MoveNext())
        //            {
        //                ActivateSnap(HandleEnumer.Current.Value);
        //                Thread.Sleep(50);
        //            }
        //            Thread.Sleep((int)(REFRESHINGTIME * 0.8));
        //        }
        //    }
        //    Thread.Sleep(REFRESHINGTIME);
        //    UpdateIdLicenseMap(true);
        //    Dictionary<int, string>.Enumerator idEnumer = idLicenseMap.GetEnumerator();
        //    while (idEnumer.MoveNext())
        //    {
        //        if (idEnumer.Current.Value == license)
        //        {
        //            id = idEnumer.Current.Key;
        //            break;
        //        }
        //    }
        //    return id;
        //}

        public Dictionary<string, int> GetIpIdMap()
        {
            return ipIdMap;
        }

        public void SetRatio(double ratio)
        {
            filterRatio = ratio;
        }
    }



    //******************************************* NumMachine *********************************************
    
    public enum EnumNumberMachineCmd
    {
        StartWork,
        StopWork
    }
        
    /// <summary>
    /// 号牌机状态枚举
    /// </summary>
    public enum EnumNumberMachineStatus
    {
        Offline, Normal
    }

    /// <summary>
    /// 号牌机节点类
    /// </summary>
    public class NumberMachineNode : ICloneable
    {
        public string ip { get; set; }
        public string LicenseNum { get; set; }
        public string TimeRecord { get; set; }
        public int id;
        public EnumNumberMachineStatus status;
        public NumberMachineNode() { }
        public NumberMachineNode(string ipAddr, int id, string license, string time, int stat)
        {
            SetLic(ipAddr, id, license, time, stat);
        }
        public void SetLic(string ipAddr, int id, string license, string time, int stat)
        {
            ip = ipAddr;
            this.id = id;
            LicenseNum = license;
            TimeRecord = time;
            if (stat == 1)
                status = EnumNumberMachineStatus.Normal;
            else
                status = EnumNumberMachineStatus.Offline;
        }
        public override bool Equals(object obj)
        {
            if (obj == null || obj.GetType() != this.GetType())
                return false;
            if (this == obj)
                return true;
            NumberMachineNode l = (NumberMachineNode)obj;
            return (l.LicenseNum == LicenseNum);
        }
        public override int GetHashCode()
        {
            return ip.GetHashCode() + LicenseNum.GetHashCode();
        }

        public object Clone()
        {
            if (status == EnumNumberMachineStatus.Normal)
                return new NumberMachineNode(ip, id, LicenseNum, TimeRecord, 1);
            else
                return new NumberMachineNode(ip, id, LicenseNum, TimeRecord, 0);
        }
    }

    /// <summary>
    /// 号牌机消息类
    /// </summary>
    public class NumberMachineMessage
    {
        public List<NumberMachineNode> data { get; set; }
        public NumberMachineNode aNode;

        public NumberMachineMessage()
        {
            data = new List<NumberMachineNode>();
            aNode = new NumberMachineNode();
        }

        public override bool Equals(System.Object obj)
        {
            if (this == obj)
                return true;
            if (obj == null || obj.GetType() != this.GetType())
                return false;
            NumberMachineMessage n = obj as NumberMachineMessage;
            return (data.Equals(n.data));
        }
        public override int GetHashCode()
        {
            int hash = 7;
            return 31 * hash + data.GetHashCode();
        }
    }
}
