using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Diagnostics;

namespace FObjBase
{
    /// <summary>
    /// 解码
    /// </summary>
    /// <param name="packet"></param>
    /// <param name="conn"></param>
    /// <returns></returns>
    public delegate bool ParsePacketHandler(byte[] packet, IFConn conn);

    /// <summary>
    /// 
    /// </summary>
    public class TCPConn:IFConn
    {
        static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
        /// <summary>
        /// 需要CRC校验
        /// </summary>
        public bool HasCRC = false;

        TimeSpan Heartbeat_Interval = TimeSpan.FromSeconds(3);         // heartbeat包发送间隔时间，3秒
        TimeSpan Silent_Time = TimeSpan.FromSeconds(10);                // 单位ms没有收到任何东西的时间，10秒
        const int MAX_BUFFER = 20 * 0x4000;//20个大包， 大包的尺寸在FObjSys 定义
        List<byte> in_buffer = new List<byte>(MAX_BUFFER);
        List<byte> out_buffer = new List<byte>(MAX_BUFFER);

        /// <summary>
        /// 通信超时判断
        /// </summary>
        Stopwatch stopwatch_comm = new Stopwatch();

        /// <summary>
        /// 心跳包判断
        /// </summary>
        Stopwatch stopwatch_heatbeat = new Stopwatch();


        /// <summary>
        /// 
        /// </summary>
        public ParsePacketHandler ParsePacket = null;

        /// <summary>
        /// 
        /// </summary>
        public Socket sock;
      
        /// <summary>
        /// 
        /// </summary>
        protected bool first_poll=true;

        /// <summary>
        /// 
        /// </summary>
        public TCPConn() 
        {
        
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sock"></param>
        public TCPConn(Socket sock) 
        {
            this.sock = sock;
        }

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        public virtual int SendPacket(byte[] buffer)
        {
            lock (out_buffer)
            {
                int len = buffer.Length;

                out_buffer.AddRange(buffer);

                return len;
            }
        }

        /// <summary>
        /// 从包提取数据
        /// </summary>
        /// <returns></returns>
        protected virtual int GetRecvInfoPacket()   // return length of the packet
        {
            int len = in_buffer.Count();
            if (len < 2) return 0;
            byte[] bs = new byte[2];

            int plen = BitConverter.ToUInt16(in_buffer.GetRange(0, 2).ToArray(), 0);

            if (plen > 0x4000 * 2)
            {
                //包太大，不正常！！！！！！
                //断开重新连接
                logger.Error("TCPConn GetRecvInfoPacket 包太大，不正常, 断开重新连接");
                sock.Close();

                return -1;
            }
            else if (plen < 2) {
                //异常，包最短也有2个byte
                logger.Error($"TCPConn GetRecvInfoPacket 包.Size = {plen}，太小，不正常, 断开重新连接");
                sock.Close();

                return -1;
            }
            if (len < plen)
            {
                return 0;
            }

            if (HasCRC) //TODO
            {
                
                if (plen < 4) {
                    //
                    logger.Error("TCPConn GetRecvInfoPacket 包.Size < 4, 无法 CRC 校验。  断开重新连接");
                    sock.Close();
                    return -1;
                }

                UInt16 crc = Misc.CRC.CRC16(in_buffer, 0, plen - 2);
                int packet_crc_idx = plen - 2;
                UInt16 packet_crc = BitConverter.ToUInt16(in_buffer.GetRange(packet_crc_idx, 2).ToArray(), 0);
                if (crc != packet_crc)
                {
                    logger.Error("TCPConn GetRecvInfoPacket CRC != packet_crc 断开重新连接");
                    //断开重新连接
                    sock.Close();
                    return -1;
                }
            }



            if (len >= plen)
            {
                return plen;
            }
            return 0;
        }
 
        /// <summary>
        /// 解包
        /// </summary>
        /// <param name="len"></param>
        /// <returns></returns>
        protected virtual bool Parse_Packet(int len)
        {
            byte[] packet = in_buffer.GetRange(0, len).ToArray();
            in_buffer.RemoveRange(0, len);
            return ParsePacket(packet, this);
        }
        
        /// <summary>
        /// 发送心跳包
        /// </summary>
        void Send_HeartBeat()
        {
            byte[] buf = new byte[2];
            buf[0] = 0x02;
            buf[1] = 0x00;
            SendPacket(buf);
            return;
        }
        int Send_Poll2() 
        {
            if (out_buffer.Count() == 0)
            {
                if (stopwatch_heatbeat.Elapsed > Heartbeat_Interval)
                {
                    Send_HeartBeat();//是时候把心跳包放入发送缓存！！！
                }
                else
                    return 0;
            }
            stopwatch_heatbeat.Restart();
            return Send_Poll();
        }
        int Send_Poll()
        {
            
            if (out_buffer.Count() == 0)//没数据，直接返回
                return 0;
            lock (out_buffer) {
                int cnt_total = 0;
                while (out_buffer.Count() > 0)//只有有数据发送，且能发送，没有 block， 就会一直循环
                {
                    int cnt;
                    try
                    {
                        cnt = sock.Send(out_buffer.ToArray());
                    }
                    catch (System.Net.Sockets.SocketException e)
                    {
                        if (e.SocketErrorCode == SocketError.WouldBlock)//当前发不了，退出循环，等下次！！！！
                            break;
                        logger.Error(e, "TCPConn Send_Poll 发送异常");
                        return -1;//异常，断开连接！！！
                    }

                    if (cnt > 0)
                    {
                        out_buffer.RemoveRange(0, cnt);//发送成功，删除！！！
                        cnt_total+=cnt;
                    }
                    else
                    {
                        break;
                    }
                }
                return cnt_total;//返回总发送量
            }
        }
        
        int Receive_Poll()
        {
            int reclen_total = 0;
            while (true)
            {
                int reclen;
                try
                {
                    reclen = sock.Available;
                }
                catch (System.Net.Sockets.SocketException e)
                {
                    //FDEBUG.Debug.LogMessage(this, 10, "Receive_Poll e=" + e.ToString());
                    if (reclen_total == 0)
                    {
                        logger.Error(e,"TCPConn Receive_Poll 什么都收不到");
                        return -1;
                    }
                    else
                        return reclen_total;
                }

                if (reclen == 0)
                    return reclen_total;

                byte[] buf = new byte[reclen];
                try
                {
                    reclen = sock.Receive(buf);
                }
                catch (System.Net.Sockets.SocketException e)
                {
                    //FDEBUG.Debug.LogMessage(this, 10, "Receive_Poll e=" + e.ToString());
                    if (reclen_total == 0)
                    {
                        logger.Error(e, "TCPConn Receive_Poll 什么都收不到");
                        return -1;
                    }
                    else
                        return reclen_total;
                }
                if (reclen > 0)
                {
                    in_buffer.AddRange(buf);
                    reclen_total += reclen;

                    stopwatch_comm.Restart();
                }
            }
        }
        protected void Init() 
        {
            if (first_poll)
            {
                stopwatch_comm.Restart();
                stopwatch_heatbeat.Restart();
                first_poll = false;
            }
        }
        public virtual int OnPoll()
        {
            int ret=0;
            Init();

            int reclen = Receive_Poll();
            if (reclen < 0)
            {
                ret = -1;
                goto end;
            }
            else if (reclen == 0)
            {
                if (stopwatch_comm.Elapsed > Silent_Time)
                {
                    logger.Error("TCPConn OnPoll 长时间没收到任何数据 断开连接");

                    ret = -2;
                    goto end;
                }
            }
            else
            {
                while (true)
                {
                    int packet_len = GetRecvInfoPacket();
                    if (packet_len > 0)
                    {
                        Parse_Packet(packet_len);
                    }
                    else if (packet_len == 0)
                    {
                        break;
                    }
                    else 
                    {
                        //异常
                        ret = -1;
                        goto end;
                    }
                }
            }
            int sendlen = Send_Poll2();

            if (sendlen < 0)
            {
                ret = -1;
                goto end;
            }
        end:
            if (ret != 0)
            {
                //连接断开,清空接收缓存区
                logger.Error("TCPConn OnPoll 连接断开,清空接收缓存区");

                in_buffer.Clear();
                lock(out_buffer)
                {
                    out_buffer.Clear();
                }
                Enable = false;
            }
            return ret;
        }

        #region IFConn 成员

        public ConnectHandler ConnectAction
        {
            get;
            set;
        }
        protected bool isconnected = false;
        public virtual bool IsConnected
        {
            get {
                return isconnected;
            }
            set {
                if (isconnected != value) 
                {
                    isconnected = value;
                    ConnectAction(this);
                }
            }
        }


        protected bool enable=false;
        public bool Enable
        {
            get
            {
                return enable;
            }
            set
            {
                enable = value;
                if (enable == false) 
                {
                    Stop();
                }
            }
        }
        protected virtual void Stop() 
        {
            if (sock != null)
                sock.Close();
            IsConnected = false;
        } 
        #endregion

        #region IFConn 成员


        public uint TranID
        {
            get;
            set;
        }

        #endregion
    }
}
