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

namespace TCPManager
{
    /// <summary>
    /// 处理接收回来的数据，返回处理完的总字节数。 
    /// </summary>
    /// <param name="conn"></param>
    /// <param name="inBuf">从[0] 开始处理</param>
    /// <returns></returns>
    public delegate int ParsePacketHandler(TCPConn conn, byte[] inBuf);

    public class TCPConn
    {
        TimeSpan Heartbeat_Interval = TimeSpan.FromSeconds(5);         // heartbeat包发送间隔时间，5秒
        TimeSpan Silent_Time = TimeSpan.FromSeconds(30);                // 单位ms没有收到任何东西的时间，1分钟
        const int MAX_BUFFER = 20 * 0x4000;//20个大包， 大包的尺寸在FObjSys 定义
        const int Send_Error_timer = 5000;           // 5000ms
        protected List<byte> in_buffer = new List<byte>(MAX_BUFFER);
        protected int packet_start;
        protected int packet_len;

        protected List<byte> out_buffer = new List<byte>(MAX_BUFFER);
        protected DateTime comm_time;
        protected DateTime heartbeat_time = DateTime.Now;

        /// <summary>
        /// 长时间没发东西事件
        /// </summary>
        public event Action<TCPConn> OutputIsEmptyWithLongTimeEvent;
        /// <summary>
        /// 数据接收处理
        /// </summary>
        public ParsePacketHandler ParsePacket = null;

        public Socket sock;

        protected bool first_poll = true;

        public TCPConn()
        {

        }
        public TCPConn(Socket sock)
        {
            this.sock = sock;
        }

        public virtual int SendPacket(byte[] buffer)
        {
            int len = buffer.Length;
            out_buffer.AddRange(buffer);
            return len;
        }


        protected virtual int Clear_Packet()
        {
            if (packet_start > 0)
            {
                in_buffer.RemoveRange(0, packet_start);
            }
            return in_buffer.Count();
        }

        int Send_Poll2()
        {
            if (out_buffer.Count() == 0)
            {
                if ((DateTime.Now - heartbeat_time) > Heartbeat_Interval)
                {
                    if (OutputIsEmptyWithLongTimeEvent != null)
                        OutputIsEmptyWithLongTimeEvent(this);
                }
                else
                    return 0;
            }

            heartbeat_time = DateTime.Now;
            return Send_Poll();
        }
        int Send_Poll()
        {
            int cnt_total = 0;
            if (out_buffer.Count() == 0)
                return 0;

            while (out_buffer.Count() > 0)
            {
                int cnt;
                try
                {
                    cnt = sock.Send(out_buffer.ToArray());
                }
                catch (System.Net.Sockets.SocketException e)
                {
                    if (e.SocketErrorCode == SocketError.WouldBlock)
                        break;
                    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)
                        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)
                        return -1;
                    else
                        return reclen_total;
                }
                if (reclen > 0)
                {
                    in_buffer.AddRange(buf);
                    reclen_total += reclen;

                    comm_time = DateTime.Now;
                }
            }
        }
        protected void Init()
        {
            if (first_poll)
            {
                comm_time = DateTime.Now;
                heartbeat_time = DateTime.Now;
                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 ((DateTime.Now - comm_time) > Silent_Time)//长时间没收到东西
                {
                    //FDEBUG.Debug.LogMessage(this, 10, "ERROR 超时出错!");
                    ret = -2;
                    goto end;
                }
            }
            else
            {
                int len=ParsePacket(this,in_buffer.ToArray());
                if (len > 0)
                {
                    in_buffer.RemoveRange(0, len);
                }
            }


            int sendlen = Send_Poll2();

            if (sendlen < 0)
            {

                ret = -1;
                goto end;
            }
        end:

            if (ret != 0)
            {
                //连接断开
                Enable = false;
            }
            return ret;
        }

        #region IFConn 成员

        public event Action<TCPConn> ConnectEvent;
        
        protected bool isconnected = false;
        public virtual bool IsConnected
        {
            get
            {
                return isconnected;
            }
            set
            {
                if (isconnected != value)
                {
                    isconnected = value;
                    if (ConnectEvent != null)
                        ConnectEvent(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
    }
}
