using NLog;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;

namespace GeneralGommunication
{
    //public class GComm_TcpClient : IGeneralComm
    //{
    //    public Logger logger = NLog.LogManager.GetCurrentClassLogger();
    //    /// <summary>
    //    /// IP 地址 and 端口号
    //    /// </summary>
    //    public string Addr { get; set; }

    //    IPEndPoint RemoteEp => Misc.StringConverter.ToIPEndPoint(Addr);

    //    /// <summary>
    //    /// 是否异常
    //    /// </summary>
    //    public bool IsError => !string.IsNullOrEmpty(ErrMsg);

    //    /// <summary>
    //    /// 异常信息
    //    /// </summary>
    //    public string ErrMsg { get; private set; }

    //    /// <summary>
    //    /// 运行中
    //    /// </summary>
    //    public bool IsRunning { get; private set; }

    //    /// <summary>
    //    /// 连接成功
    //    /// </summary>
    //    public bool IsConnected { get; private set; }

    //    /// <summary>
    //    /// 接收task调用
    //    /// </summary>
    //    public event IGeneralCommDataReceivedHandler DataReceived;



    //    public event PropertyChangedEventHandler PropertyChanged;

    //    Socket sock;
    //    CancellationTokenSource cts_readTask;
    //    CancellationTokenSource cts_waitForSend;
    //    CancellationTokenSource cts_sendTask;

    //    public GComm_TcpClient()
    //    {

    //    }
    //    /// <summary>
    //    /// 开始
    //    /// </summary>
    //    public void Start()
    //    {
    //        if (IsRunning)
    //            return;
    //        IsRunning = true;
    //        cts_readTask = new CancellationTokenSource();

    //        Task.Factory.StartNew(OnTask, cts_readTask.Token);
    //    }

    //    /// <summary>
    //    /// 接收
    //    /// </summary>
    //    public void Stop()
    //    {
    //        if (!IsRunning)
    //            return;
    //        IsRunning = false;
    //        IsConnected = false;
    //        cts_readTask.Cancel();
    //        if (sock != null && sock.Connected)
    //        {
    //            sock.Close();
    //            sock = null;
    //        }
    //    }

    //    void OnTask()
    //    {
    //        while (!cts_readTask.IsCancellationRequested)
    //        {
    //            ConnectTask();

    //            if (IsConnected)
    //            {
    //                sendBuf.Clear();
    //                //启动发送task
    //                cts_sendTask = new CancellationTokenSource();
    //                var sendtask = Task.Factory.StartNew(SendTask, cts_sendTask.Token);

    //                //进入接收task
    //                ReceiveTask();

    //                //退出了，肯定连接断开了
    //                //需要等待 SendTask 也退出了
    //                cts_sendTask.Cancel();
    //                sendtask.Wait();

    //                if (sock != null)
    //                {
    //                    sock.Close();
    //                }
    //            }

    //            //休息一会儿，在重连
    //            try
    //            {
    //                Task.Delay(2000, cts_readTask.Token).Wait();
    //            }
    //            catch (Exception e)
    //            {
    //                //被打断了
    //                break;
    //            }
    //        }

    //        IsConnected = false;
    //    }

    //    /// <summary>
    //    /// 连接任务
    //    /// </summary>
    //    void ConnectTask()
    //    {
    //        sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    //        sock.Blocking = true;

    //        //1秒内，需要收到信息
    //        sock.ReceiveTimeout = 1000;
    //        //1秒内，必须发送完
    //        sock.SendTimeout = 1000;

    //        while (!cts_readTask.IsCancellationRequested)
    //        {
    //            try
    //            {
    //                sock.Connect(RemoteEp);
    //                IsConnected = true;
    //                ErrMsg = null;
    //                return;
    //            }
    //            catch (SocketException e)
    //            {
    //                //连接出错
    //                //等待重试
    //                ErrMsg = e.Message;
    //            }
    //            try
    //            {
    //                Task.Delay(2000, cts_readTask.Token).Wait();
    //            }
    //            catch (Exception e)
    //            {
    //                //被打断
    //                return;
    //            }
    //        }
    //    }

    //    /// <summary>
    //    /// 接收任务
    //    /// </summary>
    //    void ReceiveTask()
    //    {
    //        byte[] buf = new byte[sock.ReceiveBufferSize];
    //        while (!cts_readTask.IsCancellationRequested)
    //        {
    //            int len;
    //            try
    //            {
    //                len = sock.Receive(buf);
    //                if (len == 0)
    //                {
    //                    continue;//没收到数据，继续等
    //                }
    //            }
    //            catch (SocketException e)
    //            {
    //                if (e.SocketErrorCode == SocketError.TimedOut)
    //                    continue;//超时而已
    //                else if ((e.SocketErrorCode == SocketError.ConnectionAborted)
    //                    || (e.SocketErrorCode == SocketError.ConnectionRefused)
    //                    || (e.SocketErrorCode == SocketError.ConnectionReset))
    //                {
    //                    IsConnected = false;
    //                    return;
    //                }
    //                //Console.WriteLine($"ReceiveTask() {e}");
    //                //肯定断开连接了
    //                IsConnected = false;
    //                break;
    //            }
    //            logger.Debug($"ReceiveTask len={len}");
    //            DataReceived?.Invoke(this, buf.Take(len).ToArray());
    //        }

    //        IsConnected = false;
    //    }

    //    /// <summary>
    //    /// 发送任务
    //    /// </summary>
    //    void SendTask()
    //    {
    //        while (!cts_sendTask.IsCancellationRequested)
    //        {
    //            CancellationTokenSource cts3;



    //            while (true)
    //            {
    //                byte[] buffer;
    //                lock (sendBuf)
    //                {
    //                    if (sendBuf.Count <= 0)
    //                        break;
    //                    buffer = sendBuf.ToArray();
    //                }

    //                int slen;
    //                try
    //                {
    //                    slen = sock.Send(buffer);
    //                    logger.Debug($"SendTask len={slen}");
    //                }
    //                catch (Exception e)
    //                {
    //                    //连接断开了
    //                    IsConnected = false;
    //                    break;
    //                }

    //                if (slen <= 0)
    //                {
    //                    //连接断开了
    //                    IsConnected = false;
    //                    break;
    //                }
    //                else
    //                {
    //                    lock (sendBuf)
    //                    {
    //                        if (slen == sendBuf.Count())
    //                        {
    //                            sendBuf.Clear();
    //                            break;
    //                        }
    //                        else
    //                        {
    //                            sendBuf.RemoveRange(0, slen);
    //                        }
                            
    //                    }
    //                }
    //            }

    //            //重新等 下次被呼醒
    //            lock (sendBuf)
    //            {
    //                // 呼醒 发送task
    //                if (cts_waitForSend == null)
    //                {
    //                    cts_waitForSend = new CancellationTokenSource();
    //                }
    //                //cts_waitForSend 与 cts_sendTask 合体, 任意一个都会呼醒 delay
    //                cts3 = CancellationTokenSource.CreateLinkedTokenSource(cts_waitForSend.Token, cts_sendTask.Token);
    //            }
    //            try
    //            {
    //                Task.Delay(-1, cts3.Token).Wait();
    //            }
    //            catch (Exception e)
    //            {
    //                //被打断， 有数据需要发送
    //            }
    //            cts_waitForSend = null;
    //        }
    //    }
    //    /// <summary>
    //    /// 无限大，发送缓存
    //    /// </summary>
    //    List<byte> sendBuf = new List<byte>();

    //    ///// <summary>
    //    ///// 发送数据
    //    ///// </summary>
    //    ///// <param name="buf"></param>
    //    //public void Write(IEnumerable<byte> buf)
    //    //{
    //    //    if (!IsConnected)
    //    //        return;

    //    //    lock (sendBuf)
    //    //    {
    //    //        //放入，发送缓存区
    //    //        sendBuf.AddRange(buf);

    //    //        //呼醒 发送task
    //    //        if (cts_waitForSend == null)
    //    //        {
    //    //            cts_waitForSend = new CancellationTokenSource();
    //    //        }
    //    //        cts_waitForSend.Cancel();
                
    //    //    }
    //    //}

    //    /// <summary>
    //    /// 发送数据
    //    /// </summary>
    //    /// <param name="buf"></param>
    //    public void Write(IEnumerable<byte> buf)
    //    {
    //        if (!IsConnected)
    //            return;

    //        int slen;
    //        try
    //        {
    //            slen = sock.Send(buf.ToArray());
    //            logger.Debug($"SendTask len={slen}");
    //        }
    //        catch (Exception e)
    //        {
    //            //连接断开了
    //            IsConnected = false;
    //            return;
    //        }

    //        if (slen <= 0)
    //        {
    //            //连接断开了
    //            IsConnected = false;
    //            return;
    //        }
    //    }

    //    /// <summary>
    //    /// 清空输入缓存
    //    /// </summary>
    //    public void DiscardInBuffer()
    //    {
    //        //TODO
    //    }
    //}

    public class GComm_TcpClient : IGeneralComm
    {
        public Logger logger;// = NLog.LogManager.GetCurrentClassLogger();
        /// <summary>
        /// IP 地址 and 端口号
        /// </summary>
        public string Addr { get; set; }

        IPEndPoint RemoteEp => Misc.StringConverter.ToIPEndPoint(Addr);

        /// <summary>
        /// 是否异常
        /// </summary>
        public bool IsError => !string.IsNullOrEmpty(ErrMsg);

        /// <summary>
        /// 异常信息
        /// </summary>
        public string ErrMsg { get; private set; }

        /// <summary>
        /// 运行中
        /// </summary>
        public bool IsRunning { get; private set; }

        /// <summary>
        /// 连接成功
        /// </summary>
        public bool IsConnected { get; private set; }

        /// <summary>
        /// 接收task调用
        /// </summary>
        public event IGeneralCommDataReceivedHandler DataReceived;



        public event PropertyChangedEventHandler PropertyChanged;

        Socket sock;
        CancellationTokenSource cts_readTask;

        public GComm_TcpClient()
        {

        }
        /// <summary>
        /// 开始
        /// </summary>
        public void Start()
        {
            if (IsRunning)
                return;
            IsRunning = true;
            cts_readTask = new CancellationTokenSource();

            Task.Factory.StartNew(OnTask, cts_readTask.Token);
        }

        /// <summary>
        /// 接收
        /// </summary>
        public void Stop()
        {
            if (!IsRunning)
                return;
            IsRunning = false;
            IsConnected = false;
            cts_readTask.Cancel();
            if (sock != null && sock.Connected)
            {
                sock.Close();
                sock = null;
            }
        }

        void OnTask()
        {
            while (!cts_readTask.IsCancellationRequested)
            {
                ConnectTask();

                if (IsConnected)
                {
                    //进入接收task
                    ReceiveTask();

                    //退出了，肯定连接断开了

                    if (sock != null)
                    {
                        sock.Close();
                    }
                }

                //休息一会儿，在重连
                try
                {
                    Task.Delay(2000, cts_readTask.Token).Wait();
                }
                catch (Exception e)
                {
                    //被打断了
                    break;
                }
            }

            IsConnected = false;
        }

        /// <summary>
        /// 连接任务
        /// </summary>
        void ConnectTask()
        {


            while (!cts_readTask.IsCancellationRequested)
            {
                try
                {
                    sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    sock.Blocking = true;

                    //1秒内，需要收到信息
                    sock.ReceiveTimeout = 1000;
                    //1秒内，必须发送完
                    sock.SendTimeout = 1000;

                    //sock.Connect(RemoteEp);
                    //Connect(sock, RemoteEp, 2000);
                    var result = sock.BeginConnect(RemoteEp, null, null);
                    var sucess = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(2));
                    if (sucess)
                    {
                        sock.EndConnect(result);
                        IsConnected = true;
                        ErrMsg = null;
                        return;
                    }
                    else
                    {
                        sock.Close();
                        ErrMsg = "连接超时";
                    }
                }
                catch (Exception e)
                {
                    //连接出错
                    //等待重试
                    ErrMsg = e.Message;
                }
                try
                {
                    Task.Delay(2000, cts_readTask.Token).Wait();
                }
                catch (Exception e)
                {
                    //被打断
                    return;
                }
            }
        }

        /// <summary>
        /// 接收任务
        /// </summary>
        void ReceiveTask()
        {
            byte[] buf = new byte[sock.ReceiveBufferSize];
            while (!cts_readTask.IsCancellationRequested)
            {
                int len;
                try
                {
                    len = sock.Receive(buf);
                    if (len == 0)
                    {
                        continue;//没收到数据，继续等
                    }
                }
                catch (SocketException e)
                {
                    if (e.SocketErrorCode == SocketError.TimedOut)
                        continue;//超时而已
                    else if ((e.SocketErrorCode == SocketError.ConnectionAborted)
                        || (e.SocketErrorCode == SocketError.ConnectionRefused)
                        || (e.SocketErrorCode == SocketError.ConnectionReset))
                    {
                        IsConnected = false;
                        ErrMsg = e.Message;
                        return;
                    }
                    //Console.WriteLine($"ReceiveTask() {e}");
                    //肯定断开连接了
                    IsConnected = false;
                    ErrMsg = e.Message;
                    return;
                }
                logger?.Debug($"tcp R len={len}");
                DataReceived?.Invoke(this, buf.Take(len).ToArray());
            }

            IsConnected = false;
        }


        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="buf"></param>
        public void Write(IEnumerable<byte> buf)
        {
            if (!IsConnected)
                return;

            int slen;
            try
            {
                slen = sock.Send(buf.ToArray());
                logger?.Debug($"tcp W len={slen}");
            }
            catch (Exception e)
            {
                //连接断开了
                IsConnected = false;
                ErrMsg = e.Message;
                return;
            }

            if (slen <= 0)
            {
                //连接断开了
                IsConnected = false;
                ErrMsg = "发送数量小于0";
                return;
            }
        }

        /// <summary>
        /// 清空输入缓存
        /// </summary>
        public void DiscardInBuffer()
        {
            //TODO
        }



    }
}
