using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Dispatch;
using System.Net;
using System.Text.RegularExpressions;
using System.Net.Sockets;
using System.Threading;

namespace Dispatch
{
    /// <summary>
    /// UDP通信类
    /// </summary>
   public class UDPCommunication:CommunicationBase
    {
        /// <summary>
        /// 本地IP
        /// </summary>
        private string localIP;
        /// <summary>
        /// 接收字节缓存
        /// </summary>
        public List<byte> receiveBuffer = new List<byte>(2046); 
        /// <summary>
        /// 端口锁定对象
        /// </summary>             
        private static object portLock = new object();
        /// <summary>
        /// 信息检效处理操作
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void MatchedParityHandler(object sender, DataEventArgs e);
        /// <summary>
        /// 信息检效事件
        /// </summary>
        public event MatchedParityHandler MatchedParity;
        /// <summary>
        /// 日志记录
        /// </summary>
        internal static BlackBoxFile.CBlackBoxFile gs_blackBoxFile;
        /// <summary>
        /// 接收IP列表 
        /// </summary>
        List<IPAddress> recieveIPs = new List<IPAddress>();
        AutoResetEvent autoReset = new AutoResetEvent(false);
        /// <summary>
        /// 本地IP获取
        /// </summary>
        public string LocalIP
        {
            get 
            {
                if (string.IsNullOrEmpty(localIP))
                {
                    return Dns.GetHostAddresses(Dns.GetHostName())[0].ToString();
                }
                return localIP; 
            }
            set 
            {
                string str = @"^\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}$";
                if (Regex.IsMatch(value, str))
                {
                    localIP = value; 
                }
                else
                {
                    throw new Exception("IP地址格式错误");
                }
            }
        }
        private int port;
        /// <summary>
        /// 端口
        /// </summary>
        public int Port
        {
            get 
            {
                if (port <= 0)
                    return 10000;
                return port; 
            }
            set { port = value; }
        }
        private int scanTime;

        /// <summary>
        /// 扫描时间
        /// </summary>
        public int ScanTime
        {
            get 
            {
                if (scanTime <= 0)
                    return 10;
                return scanTime; 
            }
            set { scanTime = value; }
        }
        /// <summary>
        /// 对象标识
        /// </summary>
        /// <returns></returns>
        public override object GetTag()
        {
            return this;
        }
        private UdpClient udpServer;
        private Thread thread;
        private Thread thread1;
        /// <summary>
        /// UDP通信
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <param name="scanTime"></param>
        public  UDPCommunication(string ip, int port, int scanTime = 0)
        {
            LocalIP = ip;
            Port = port;
            ScanTime = scanTime;          
            IsOpen = false;
            gs_blackBoxFile = new BlackBoxFile.CBlackBoxFile();
        }
        AutoResetEvent done = new AutoResetEvent(true);
        /// <summary>
        /// 字符数据转十六进制字符串
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        public static string ByteToHexString(byte[] buffer)
        {
            StringBuilder builder = new StringBuilder(buffer.Length * 3);
            foreach (byte data in buffer)
            {
                builder.Append(Convert.ToString(data, 16).PadLeft(2, '0').PadRight(3, ' '));
            }
            return builder.ToString().ToUpper();
        }
        /// <summary>
        /// 接收线程
        /// </summary>
        private void ReceiveThread()
        {
            IPEndPoint remotePoint = new IPEndPoint(IPAddress.Any,0);
            while (true)
            {
                if(IsOpen && udpServer != null)
                {             
                    ReceivedEventArgs e1 = new ReceivedEventArgs();
                    try
                    {
                        e1.buffer = udpServer.Receive(ref remotePoint);
                     
                        if (remotePoint.Address != IPAddress.Parse(LocalIP) && !recieveIPs.Contains(remotePoint.Address))
                        {
                            recieveIPs.Add(remotePoint.Address);
                        }
                        receiveBuffer.AddRange(e1.buffer);
                    }
                    catch (System.Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                        
                    }
                    
                    Thread.Sleep(ScanTime);
                    done.Set();
                }
            }
        }
        /// <summary>
        /// 第二接收线程
        /// </summary>
        private void ReceiveThread2()
        {
            IPEndPoint remotePoint = new IPEndPoint(IPAddress.Any, 0);
            while (true)
            {
                if (receiveBuffer.Count > 0)
                {
                    done.Reset();
                    byte[] buffer;
                    int type;
                    buffer = DataHander(out type);
                    DataEventArgs e = new DataEventArgs();
                    e.type = type;
                    e.data = buffer;
                    if (type != -1)
                    {
                        MyData data = new MyData();
                        data.sender = this;
                        data.e = e;
                        Thread t = new Thread(OnMatchParity);
                        t.Start(data);
                    }
                }
                Thread.Sleep(100);
            }
        }
        /// <summary>
        /// 读取数据
        /// </summary>
        public event EventHandler ReadingData;
        /// <summary>
        /// 写入数据
        /// </summary>
        public event EventHandler WritingData;
        void OnReadingData(EventArgs e)
        {
            if (ReadingData != null)
            {
                ReadingData(this, e);
            }
        }
        void OnWritingData(EventArgs e)
        {
            if (WritingData != null)
            {
                WritingData(this, e);
            }
        }
        /// <summary>
        /// 事件监听处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void OnMatchedParity(object sender, DataEventArgs e)
        {
            if (MatchedParity != null)
            {
                MatchedParity(sender, e);
            }
        }
        /// <summary>
        /// 事件监听处理
        /// </summary>
        /// <param name="o"></param>
        public void OnMatchParity(object o)
        {
            MyData data = o as MyData;
            Console.ForegroundColor = ConsoleColor.Yellow;
            //Console.WriteLine("所在线程ID:" + Thread.CurrentThread.ManagedThreadId.ToString() + "类型:" + data.e.type + "  " + Byte2HexString(data.e.data));
            Console.ResetColor();

            OnMatchedParity(data.sender, data.e);
            Thread.Sleep(500);//加延时是为了避免解析后有过长的操作占用系统资源
        }
        private class MyData
        {
            public object sender;
            public DataEventArgs e;
        }
        /// <summary>
        /// 异或操作
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="count"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        public static byte XOR_Check(byte[] buffer, int count, int index = 0)
        {
            byte b = 0;
            for (int i = 0; i < count; i++)
            {
                b ^= buffer[index + i];
            }
            return b;
        }
        /// <summary>
        /// 整理数据缓存表
        /// </summary>
        /// <param name="bufferList">数据缓存表</param>
        /// <param name="targetByte">目标字节</param>
        private static void ArrangeBuffer(List<byte> bufferList, byte targetByte)
        {
            int delBytes = 1;

            for (int i = 1; i < bufferList.Count; i++)
            {
                if (bufferList[i] == targetByte)
                {
                    break;
                }
                else
                {
                    delBytes++;
                }
            }

            try
            {
                lock (portLock)
                {
                    bufferList.RemoveRange(0, delBytes);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        ///  数据操作
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private byte[] DataHander(out int type)
        {
            type = -1;
            int framelength = 10;           // 帧长度
            byte frameHead = 0x10;          // 帧头
            byte frameTaig = 0x03;
            List<byte> frameFuncList = new List<byte> { 0x41, 0x42, 0x46, 0x32, 0x33, 0x35, 0x38 };

            if (receiveBuffer.Count >= framelength)
            {
                #region MyRegion
                if ((receiveBuffer[0] == frameHead) && (receiveBuffer.Count >= 14) && frameFuncList.Contains(receiveBuffer[1]))
                {
                    // 二代协议
                    byte checkSum = 0x00;
                    for (int i = 0; i < 12; i++)
                    {
                        checkSum ^= receiveBuffer[i];
                    }
                    if (checkSum == receiveBuffer[12] && frameTaig == receiveBuffer[13])
                    {
                        byte[] data = new byte[14];
                        for (int i = 0; i < 14; i++)
                        {
                            data[i] = receiveBuffer[i];
                        }
                        lock (portLock)
                        {
                            receiveBuffer.RemoveRange(0, 14);
                        }
                        type = 3;
                        return data;
                    }
                    else
                    {
                        ArrangeBuffer(receiveBuffer, frameHead);
                    }
                }
                else if ((receiveBuffer[0] == frameHead) && (receiveBuffer.Count >= 10) && receiveBuffer[1] == 0x62)
                {
                    byte checkSum = 0x00;
                    for (int i = 0; i < 8; i++)
                    {
                        checkSum ^= receiveBuffer[i];
                    }
                    if (checkSum == receiveBuffer[8] && frameTaig == receiveBuffer[9])
                    {
                        byte[] data = new byte[10];
                        for (int i = 0; i < 10; i++)
                        {
                            data[i] = receiveBuffer[i];
                        }
                        lock (portLock)
                        {
                            receiveBuffer.RemoveRange(0, 10);
                        }
                        type = 3;
                        return data;
                    }
                    else
                    {
                        ArrangeBuffer(receiveBuffer, frameHead);
                    }
                }
                else
                {
                    ArrangeBuffer(receiveBuffer, frameHead);
                }
                #endregion
            }
            return new byte[1] { 0 };
        }
        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="o"></param>
        public override void SendData(byte[] buffer,object o)
        {
            IPEndPoint ip = o as IPEndPoint;
            if (ip == null)
            {
                string ipStr = LocalIP.Substring(0, LocalIP.LastIndexOf('.') + 1);
                try
                {
                    if (IsOpen)
                    {
                        Console.WriteLine(string.Format("[{0,-15}:{1} {2}]发送:{3}", LocalIP,Port,DateTime.Now.ToString("HH:mm:ss"), ByteToHexString(buffer)));
                    
                        if (recieveIPs.Count < 0)
                        {
                            udpServer.Send(buffer, buffer.Length, new IPEndPoint(IPAddress.Parse("255.255.255.255"), Port));
                        }
                        else
                        {
                            foreach (IPAddress ipa in recieveIPs)
                            {
                                udpServer.Send(buffer, buffer.Length, new IPEndPoint(ipa, Port));
                            }
                        }
               
                    }
                }
                catch (System.Exception ex)
                {
                	throw new Exception(ex.Message);
                }
                
            }
            else
            {
                try
                {
                    if (IsOpen)
                    {
                        Console.WriteLine(string.Format("[{0,-15}:{1} {2}]发送:{3}", LocalIP, Port, DateTime.Now.ToString("HH:mm:ss"), ByteToHexString(buffer)));
                        udpServer.Send(buffer, buffer.Length, new IPEndPoint(ip.Address,Port));
                    }
                    
                }
                catch (System.Exception ex)
                {
                    throw new Exception(ex.Message);
                }
            }
        }
        /// <summary>
        /// 关闭联接
        /// </summary>
        public override void Close()
        {
            if(udpServer != null)
            {
                udpServer.Close();
                udpServer = null;
            }
            if (thread != null && thread.ThreadState != ThreadState.Stopped)
            {
                if (done.WaitOne(500))
                {
                    thread.Abort();
                }
                thread = null;
            }
            
            IsOpen = false;
        }
        /// <summary>
        /// 释放联接
        /// </summary>
        public override void Dispose()
        {
            if(udpServer != null)
                udpServer.Close();
            if(thread != null && thread.ThreadState != ThreadState.Stopped)
            {
                if (done.WaitOne(500))
                {
                    thread.Abort();
                }
                thread.Abort();
                thread = null;
            }
            base.Dispose();
            
        }

        /// <summary>
        /// 打开联接
        /// </summary>
        public override void Open()
        {  
            if (thread != null&&udpServer!=null)
            {
                if (thread.ThreadState == ThreadState.Suspended)
                {
                    autoReset.Set();//thread.Resume();
                }
                else if (thread.ThreadState == ThreadState.Unstarted)
                {
                    thread.Start();
                }
            }
            else
            {
                IPAddress[] address = Dns.GetHostAddresses(Dns.GetHostName());
                for (int i = 0; i < address.Count(); i++)
                {

                    if (address[i].AddressFamily.ToString().ToLower() == "internetwork" && address[i].ToString() == LocalIP)
                    {
                        udpServer = new UdpClient(new IPEndPoint(IPAddress.Any, Port));
                        thread = new Thread(ReceiveThread);
                        thread.Start();
                        thread1 = new Thread(ReceiveThread2);
                        thread1.Start();
                        break;
                    }
                    else if (i == address.Count() - 1)
                    {
                        Console.WriteLine("UDP中IP地址不存在");
                        return;
                    }
                }
                
            }
            IsOpen = true;
        }
    }
}


