using Aitex.Core.RT.Log;
using Aitex.Core.Utilities;
using DocumentFormat.OpenXml.ExtendedProperties;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace MECF.Framework.Common.Net
{
    public class JetTcpClient
    {
        #region 内部变量
        private string _ip="127.0.0.1";
        private int _port = 9600;
        private bool _connected = false;
        protected int _reconnectInterval = 500;
        protected DateTime _connectTime = DateTime.Now;
        private int _connectTimeout = 2000;
        private int _receiveTimeout = 1000;
        private int _sendTimeout = 1000;
        private object _connectLocker=new object();
        private object _reconnectLocker = new object();
        private object _sendLocker = new object();
        private object _receiveLocker = new object();
        private object _closeLocker = new object();
        private AutoResetEvent _connectAutoResetEvent=new AutoResetEvent(false);
        private Socket _socket = null;
        private bool _logEnabled;
        private string _name;
        private eEvent _eventId;
        #endregion
        #region 属性
        /// 
        /// 重连间隔时长
        /// 
        public int ReconnectInterval { set { _reconnectInterval = value; } }
        /// 
        /// 连接超时时长
        /// 
        public int ConnectTimeout { set { _connectTimeout = value; } }
        /// 
        /// 接收超时时长
        /// 
        public int ReceiveTimeout { set { _receiveTimeout = value; } }
        /// 
        /// 发送超时时长
        /// 
        public int SendTimeout { set { _sendTimeout = value; } }
        /// 
        /// 连接状态
        /// 
        public bool Connected { get { return _connected; } }
        /// 
        /// 是否启用LOG
        /// 
        public bool LogEnabled { set { _logEnabled=value; }}
        /// 
        /// 名称
        /// 
        public string Name { set { _name=value; } }
        /// 
        /// 事件Id
        /// 
        public eEvent EventId { set { _eventId = value; } }
        #endregion
        /// 
        /// 构造函数
        /// 
        /// 
        /// 
        public JetTcpClient(string ip,int port)
        {
            _ip= ip;
            _port= port;
        }
        /// 
        /// 连接
        /// 
        public NetResult Connect()
        {
            if (_connected)
            {
                return NetResult.CreateSuccessResult();
            }
            if(!Monitor.TryEnter(_connectLocker,_connectTimeout))
            {
                return NetResult.CreateFailedResult(NetErrorCode.LockerOccupied);
            }
            _connectTime = DateTime.Now;
            _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _socket.ReceiveTimeout = _receiveTimeout;
            _socket.SendTimeout=_sendTimeout;
            NetStateObject stateObject=new NetStateObject();
            stateObject.Socket = _socket;
            stateObject.AutoResetEvent = _connectAutoResetEvent;
            EndPoint localEndpoint = _socket.LocalEndPoint;
            if(IPAddress.TryParse(_ip,out IPAddress ipAddress))
            {
                try
                {
                    _socket.BeginConnect(new IPEndPoint(ipAddress, _port), new AsyncCallback(ConnectCallBack), stateObject);
                }
                catch(Exception ex)
                {
                    stateObject.Dispose();
                    stateObject = null;
                    ConnectFailedBusiness();
                    Monitor.Exit(_connectLocker);
                    return NetResult.CreateFailedResult((int)NetErrorCode.InnerException, ex.Message);
                }
                if (!_connectAutoResetEvent.WaitOne(_connectTimeout))
                {
                    stateObject.Dispose();
                    stateObject = null;
                    ConnectFailedBusiness();
                    Monitor.Exit(_connectLocker);
                    return NetResult.CreateFailedResult(NetErrorCode.ConnectTimeout);
                }
                
                LOG.WriteLog(eEvent.EV_DEVICE_INFO, "System", $"Connect {_ip}:{_port} Success,local {localEndpoint}");
                _connected = true;
                stateObject.Dispose();
                stateObject = null;
                Monitor.Exit(_connectLocker);
                return NetResult.CreateSuccessResult();
            }
            else
            {
                stateObject.Dispose();
                stateObject = null;
                ConnectFailedBusiness();
                Monitor.Exit(_connectLocker);
                return NetResult.CreateFailedResult(NetErrorCode.InvalidIpAddress);
            }
        }
        /// 
        /// 中止
        /// 
        public void Stop()
        {
            CloseSocket();
        }
        /// 
        /// 连接失败后处理
        /// 
        /// 
        private void ConnectFailedBusiness()
        {            
            _connectAutoResetEvent.Reset();
            CloseSocket();
        }
        /// 
        /// 关闭Socket
        /// 
        private void CloseSocket()
        {
            if (Monitor.TryEnter(_closeLocker, 10))
            {
                if (_socket != null)
                {
                    try
                    {
                        _socket.Shutdown(SocketShutdown.Both);
                    }
                    catch
                    {
                    }
                    try
                    {
                        _socket.Close();
                    }
                    catch
                    {
                    }
                    _socket = null;
                    _connected = false;
                }
                Monitor.Exit(_closeLocker);
            }
        }
        /// 
        /// 当连接的结果返回
        /// 
        /// 异步对象
        private void ConnectCallBack(IAsyncResult ar)
        {
            if (ar.AsyncState is NetStateObject state)
            {
                if (state.Socket != null)
                {
                    try
                    {
                        state.Socket.EndConnect(ar);
                        state.AutoResetEvent.Set();
                    }
                    catch (Exception ex)
                    {
                    }
                }
            }
        }
        /// 
        /// 写日志
        /// 
        /// 
        /// 
        private void WriteInfoLog(byte[] bytes,int logType)
        {
            if (_logEnabled)
            {
                string str = string.Join(" ", Array.ConvertAll(bytes, x => x.ToString("X2")));
                string type = logType == 0 ? "receive" : "send";
                LOG.WriteBackgroundLog(_eventId, _name, $"{type} {str}");
            }
        }
        /// 
        /// 发送数据
        /// 
        /// 
        /// 
        public NetResult Send(byte[] data)
        {
            if(!Connected)
            {
                return NetResult.CreateFailedResult(NetErrorCode.NetOffline);
            }
            //清除缓存数据
            ClearPreData();
            //进入发送
            if (Monitor.TryEnter(_sendLocker,_sendTimeout))
            {
                if(_socket==null)
                {
                    return NetResult.CreateFailedResult(NetErrorCode.NullSocketObject);
                }
                try
                {
                    _socket.Send(data);
                    WriteInfoLog(data, 1);
                    Monitor.Exit(_sendLocker);
                    return NetResult.CreateSuccessResult();
                }
                catch (Exception ex)
                {
                    Monitor.Exit(_sendLocker);
                    ConnectFailedBusiness();
                    return NetResult.CreateFailedResult((int)NetErrorCode.InnerException, ex.Message);
                }
            }
            else
            {
                return NetResult.CreateFailedResult(NetErrorCode.GetLockTimeout);
            }
        }
        /// 
        /// 接收数据
        /// 
        /// 
        /// 
        public NetResult Receive(int length)
        {
            if (!Connected)
            {
                return NetResult.CreateFailedResult(NetErrorCode.NetOffline);
            }
            if (Monitor.TryEnter(_receiveLocker,_receiveTimeout))
            {
                if(_socket==null)
                {
                    return NetResult.CreateFailedResult(NetErrorCode.NullSocketObject);
                }
                try
                {
                    byte[] buffer = null;
                    if (length == -1)
                    {
                        buffer = new byte[_socket.Available];
                    }
                    else
                    {
                        buffer = new byte[length];
                    }
                    _socket.Receive(buffer, length, SocketFlags.None);
                    WriteInfoLog(buffer, 0);
                    Monitor.Exit(_receiveLocker);
                    return NetResult.CreateSuccessResult(buffer);
                }
                catch(SocketException ex)
                {
                    Monitor.Exit(_receiveLocker);
                    ConnectFailedBusiness();
                    return NetResult.CreateFailedResult((int)NetErrorCode.InnerException, ex.Message);
                }
                catch (Exception ex)
                {
                    Monitor.Exit(_receiveLocker);
                    ConnectFailedBusiness();
                    return NetResult.CreateFailedResult((int)NetErrorCode.InnerException, ex.Message);
                }
            }
            else
            {
                return NetResult.CreateFailedResult(NetErrorCode.GetLockTimeout);
            }
        }
        /// 
        /// 清除先前的数据
        /// 
        public void ClearPreData()
        {
            if (!Connected)
            {
                return;
            }
            if (Monitor.TryEnter(_receiveLocker, _receiveTimeout))
            {
                if (_socket == null)
                {
                    return;
                }
                try
                {
                    while (_socket.Available != 0)
                    {
                        byte[] buffer = new byte[_socket.Available];
                        _socket.Receive(buffer, buffer.Length, SocketFlags.None);
                    }
                    Monitor.Exit(_receiveLocker);
                }
                catch (SocketException ex)
                {
                    Monitor.Exit(_receiveLocker);
                    ConnectFailedBusiness();
                }
                catch (Exception ex)
                {
                    Monitor.Exit(_receiveLocker);
                    ConnectFailedBusiness();
                }
            }
        }
    }
}