using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Management;
using HPSocketCS.Extended;
using System.Runtime.InteropServices;
namespace HPNetwork.TCPNetworkServer
{
	#region 在线用户列表		2017/07/03
	/// <summary>
	/// 在线用户列表;
	/// </summary>
	public struct OnlineUser
	{
		public IntPtr ConnId;
		public string strBranchId;
        public DateTime dtQueryTask;
        public DateTime dtQueryNeedDownload;
        public DateTime dtQueryBranchDetail;
    }
	#endregion

	/// <summary>
	/// TCP网络通信服务端
	/// </summary>
	public class TCP_NetworkServer
    {
		#region 在线用户列表		2017/07/03
		/// <summary>
		/// 在线用户列表;
		/// </summary>
		private List<OnlineUser> onlineuserlist = new List<OnlineUser>();
		/// <summary>
		/// 在线用户列表;
		/// </summary>
		public List<OnlineUser> OnlineUserList
		{
			get { return onlineuserlist; }
			set { onlineuserlist = value; }
		}

		public bool IsOnlineUserExists(string branchId)
		{
			bool bExists = false;
			foreach ( OnlineUser user in OnlineUserList )
			{
				if (branchId == user.strBranchId)
				{
					bExists = true;
					break;
				}
			}

			return bExists;
		}

		public void AddOnlineUser(IntPtr connId, string branchId)
		{
			if (IsOnlineUserExists(branchId))
				return;

			OnlineUser user = new OnlineUser
            {
                ConnId = connId,
                strBranchId = branchId,
                dtQueryTask = DateTime.Now,
                dtQueryNeedDownload = DateTime.Now,
                dtQueryBranchDetail = DateTime.Now
            };
			OnlineUserList.Add(user);
		}

		public void RemoveOnlineUser(IntPtr connId)
		{
			foreach (OnlineUser user in OnlineUserList)
			{
				if (connId == user.ConnId)
				{
					onlineuserlist.Remove(user);
					break;
				}
			}
		}

		public void RemoveOnlineUser(string branchId)
		{
			foreach (OnlineUser user in OnlineUserList)
			{
				if (branchId == user.strBranchId)
				{
					onlineuserlist.Remove(user);
					break;
				}
			}
		}

        public bool IsQueryTaskTimeOut(IntPtr connId)
        {
            for (int i = 0; i < OnlineUserList.Count; i++ )
            {
                OnlineUser user = OnlineUserList[i];
                if (connId == user.ConnId)
                {
                    TimeSpan tSpan = DateTime.Now - user.dtQueryTask;
                    if (tSpan.TotalMilliseconds > 15000)
                    {
                        user.dtQueryTask = DateTime.Now;
                        return true;
                    }
                }
            }

            return false;
        }

        public bool IsQueryNeedDownloadTimeOut(IntPtr connId)
        {
            for (int i = 0; i < OnlineUserList.Count; i++)
            {
                OnlineUser user = OnlineUserList[i];
                if (connId == user.ConnId)
                {
                    TimeSpan tSpan = DateTime.Now - user.dtQueryNeedDownload;
                    if (tSpan.TotalMilliseconds > 15000)
                    {
                        user.dtQueryNeedDownload = DateTime.Now;
                        return true;
                    }
                }
            }

            return false;
        }

        public bool IsQueryBranchDetailTimeOut(IntPtr connId)
        {
            for (int i = 0; i < OnlineUserList.Count; i++)
            {
                OnlineUser user = OnlineUserList[i];
                if (connId == user.ConnId)
                {
                    TimeSpan tSpan = DateTime.Now - user.dtQueryBranchDetail;
                    if (tSpan.TotalMilliseconds > 15000)
                    {
                        user.dtQueryBranchDetail = DateTime.Now;
                        return true;
                    }
                }
            }

            return false;
        }
        #endregion
        public TCP_NetworkServer()
        {


        }
        public TCP_NetworkServer(HPSocketCS.Extended.CustomTraceListener _traceListenerLog)
        {
            this.TraceListenerLog = _traceListenerLog;
        }

        #region 网络程序处理代码
        private AppState appState = AppState.Stoped;
        public HPSocketCS.TcpPackServer hp_Server = new HPSocketCS.TcpPackServer();

        HPSocketCS.Extended.CustomTraceListener _TraceListenerLog = null;
        
        /// <summary>
        /// 服务器运行日志跟踪侦听器
        /// </summary>
        public HPSocketCS.Extended.CustomTraceListener TraceListenerLog
        {
            get { return _TraceListenerLog; }
            set { _TraceListenerLog = value; }
        }
        
        /// <summary>
        /// 启动网络
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        public void StartRun(string ip = "0.0.0.0", ushort port = 8500)
        {
            try
            {
                if (!this.isInitializesNetwork)
                {
                    this.InitializesNetwork();
                }
                ServerStartTimeStamp = "1492583059892";//DateTime.Now.ToString("yyyyMMddHHmmsss");
                // 写在这个位置是上面可能会异常
                SetAppState(AppState.Starting);
                hp_Server.IpAddress = ip;
                hp_Server.Port = port;
                // 启动服务
                if (hp_Server.Start())
                {
                    SetAppState(AppState.Started);
                    SystemFileLogs.WriteLogs("服务器网络启动成功 IP:" + ip + ":" + port.ToString(), this.TraceListenerLog);
                }
                else
                {
                    SetAppState(AppState.Stoped);
                    throw new Exception(string.Format("$绑定套接字失败(套接字绑定),可能是端口“" + port.ToString() + "”被占用 -> {0}({1})", hp_Server.ErrorMessage, hp_Server.ErrorCode));
                }
            }
            catch (Exception ex)
            {
                SystemFileLogs.WriteLogs("服务器网络启动失败:" + ex.Message, this.TraceListenerLog);
            }
        }

        public void StopRun()
        {
            try
            {
                if (this.IsInitializesNetwork)
                {
                    SetAppState(AppState.Stoping);

                    // 停止服务
                    SystemFileLogs.WriteLogs("服务器网络停止服务", this.TraceListenerLog);
                    if (hp_Server.Stop())
                    {
                        SetAppState(AppState.Stoped);
                    }
                    else
                    {
                        SystemFileLogs.WriteLogs("服务器网络停止服务时出错:" + hp_Server.ErrorMessage + "(" + hp_Server.ErrorCode + ")", this.TraceListenerLog);
                    }
                }
            }
            catch { }
        }

        bool isInitializesNetwork = false;
        /// <summary>
        /// 网络服务是否已初始化
        /// </summary>
        public bool IsInitializesNetwork
        {
            get { return isInitializesNetwork; }
            set { isInitializesNetwork = value; }
        }

        /// <summary>
        /// 初始化网络
        /// </summary>
        void InitializesNetwork()
        {
            try
            {
                // 设置服务器事件
                hp_Server.OnPrepareListen += new HPSocketCS.TcpServerEvent.OnPrepareListenEventHandler(OnPrepareListen);
                hp_Server.OnAccept += new HPSocketCS.TcpServerEvent.OnAcceptEventHandler(OnAccept);
                hp_Server.OnSend += new HPSocketCS.TcpServerEvent.OnSendEventHandler(OnSend);
                hp_Server.OnReceive += new HPSocketCS.TcpServerEvent.OnReceiveEventHandler(OnReceive);
                hp_Server.OnClose += new HPSocketCS.TcpServerEvent.OnCloseEventHandler(OnClose);
                hp_Server.OnShutdown += new HPSocketCS.TcpServerEvent.OnShutdownEventHandler(OnShutdown);

                // 设置包头标识,与对端设置保证一致性
                hp_Server.PackHeaderFlag = 0x1ff;
                // 设置最大封包大小
                hp_Server.MaxPackSize = 0x2000 * 32;
                hp_Server.SocketBufferSize = 512 * 1024;//hp_Server.MaxPackSize;
                this.isInitializesNetwork = true;
                SystemFileLogs.WriteLogs("服务器初始化网络成功", this.TraceListenerLog);
                SetAppState(AppState.Stoped);
            }
            catch (Exception ex)
            {
                SetAppState(AppState.Error);
                SystemFileLogs.WriteLogs("服务器初始化网络时出错:" + ex.Message, this.TraceListenerLog);
            }
        }
        /// <summary>
        /// 准备监听了事件
        /// </summary>
        /// <param name="soListen"></param>
        /// <returns></returns>
        HPSocketCS.HandleResult OnPrepareListen(IntPtr soListen)
        {
            // 监听事件到达了,一般没什么用吧?
            SystemFileLogs.WriteLogs("服务器已成功开始网络侦听...", this.TraceListenerLog);
            return HPSocketCS.HandleResult.Ok;
        }
        /// <summary>
        /// 连接到达事件
        /// </summary>
        /// <param name="connId"></param>
        /// <param name="pClient"></param>
        /// <returns></returns>
        HPSocketCS.HandleResult OnAccept(IntPtr connId, IntPtr pClient)
        {
            // 客户进入了

            // 获取客户端ip和端口
            string ip = string.Empty;
            ushort port = 0;
            if (hp_Server.GetRemoteAddress(connId, ref ip, ref port))
            {
                SystemFileLogs.WriteLogs("收接连接请求:" + ip + ":" + port.ToString(), this.TraceListenerLog);
            }
            else
            {
                SystemFileLogs.WriteLogs("获取某个连接的ip和端口时出错", this.TraceListenerLog);
                return HPSocketCS.HandleResult.Error;
            }

            // 设置附加数据
            HPSocketCS.Extended.ClientInfo ci = new HPSocketCS.Extended.ClientInfo();
            ci.ConnId = connId;
            ci.IpAddress = ip;
            ci.Port = port;
            if (hp_Server.SetConnectionExtra(connId, ci) == false)
            {
                SystemFileLogs.WriteLogs("设置连接的附加数据失败,IP地址为 " + ip + ":" + port.ToString(), this.TraceListenerLog);
                return HPSocketCS.HandleResult.Error;
            }


            return HPSocketCS.HandleResult.Ok;
        }
        /// <summary>
        /// 数据包发送事件
        /// </summary>
        /// <param name="connId"></param>
        /// <param name="bytes"></param>
        /// <returns></returns>
        HPSocketCS.HandleResult OnSend(IntPtr connId, byte[] bytes)
        {
            // 服务器发数据了
            return HPSocketCS.HandleResult.Ok;
        }
        
        /// <summary>
        /// 数据到达
        /// </summary>
        /// <param name="connId"></param>
        /// <param name="bytes"></param>
        /// <returns></returns>
        HPSocketCS.HandleResult OnReceive(IntPtr connId, byte[] bytes)
        {
            // 数据到达了
            try
            {

                bool retProcessed = true;//处理情况
                //收到的数据
                byte[] receiveBytes = new byte[0];

                TcpHeadInfo header = hp_Server.BytesToStruct<TcpHeadInfo>(bytes);
                DataType dType = (DataType)header.MsgDataType;
                int headSize = Marshal.SizeOf(header);
                TcpTailInfo tail = new TcpTailInfo();
                if (header.IsTail)
                {

                    //有附加尾数据时
                    int tailSize = Marshal.SizeOf(tail);
                    byte[] tailBytes = new byte[tailSize];
                    Array.ConstrainedCopy(bytes, bytes.Length - tailSize, tailBytes, 0, tailBytes.Length);
                    tail = hp_Server.BytesToStruct<TcpTailInfo>(tailBytes);
                    receiveBytes = new byte[bytes.Length - headSize - tailSize];
                    Array.ConstrainedCopy(bytes, headSize, receiveBytes, 0, receiveBytes.Length);
                    tailBytes = null;
                }
                else
                {
                    // 因为没有附加尾数据,所以大小可以用length - objSize
                    receiveBytes = new byte[bytes.Length - headSize];
                    Array.ConstrainedCopy(bytes, headSize, receiveBytes, 0, receiveBytes.Length);
                }

                bytes = null;
                //接收到的客户端发送来的数据
                byte[] recbytes = null;
                try
                {

                    if (header.TransportStart && header.TransportEnd)
                    {
                        recbytes = receiveBytes;
                        receiveBytes = null;
                    }
                    else
                    {
                        ReceiveData rData = hp_Server.SCommonLibrary.GetReceiveData(header);
                        if (rData == null)
                        {
                            rData = new ReceiveData();
                            hp_Server.SCommonLibrary.AddReceiveData(rData);
                        }
                        rData.ReceiveRemoteClientInfo = header;
                        rData.ReceiveDataMstream.Write(receiveBytes, 0, receiveBytes.Length);
                        if (header.TransportEnd)
                        {
                            rData.ReceiveDataMstream.Position = 0;
                            //recbytes = rData.ReceiveDataMstream.ToArray();
                            recbytes = new byte[rData.ReceiveDataMstream.Length];
                            rData.ReceiveDataMstream.Read(recbytes, 0, recbytes.Length);
                            hp_Server.SCommonLibrary.RemoveReceiveDataData(rData);
                        }
                    }

                    if (recbytes != null)
                    {
                        recbytes = HPSocketCS.Extended.DataSetSerializerDeserialize.DataDecompressRetBytes(recbytes);
                        switch (dType)
                        {
                            case DataType.File:
                                FileRequestType RequestType = (FileRequestType)tail.RequestType;
                                if (this.EventFileDataRequest != null)
                                {
                                    this.EventFileDataRequest(hp_Server, header, tail, connId, recbytes);
                                }
                                switch (RequestType)
                                {
                                    case FileRequestType.Upload:
                                        //接收文件
                                        retProcessed = hp_Server.ReceiveFileToServerRootDirectory(tail, recbytes);
                                        break;
                                    case FileRequestType.Download:
                                        //发送文件
                                        retProcessed = hp_Server.SenFileToClient(header, tail, connId);
                                        break;
                                }

                                break;

                            case DataType.SQLHelper:
                            case DataType.Serialization:
                                if (this.EventSerializationDataRequest != null)
                                {
                                    this.EventSerializationDataRequest(hp_Server, header, connId, recbytes);
                                }
                                break;
                            case DataType.List:

                                break;
                            case DataType.Array:

                                break;
                            case DataType.None:

                                break;
                        }
                    }
                }
                finally
                {
                    try
                    {
                        System.Array.Clear(recbytes, 0, recbytes.Length);
                    }
                    catch { }
                    recbytes = null;
                }


                if (retProcessed)
                {
                    return HPSocketCS.HandleResult.Ok;
                }
                else
                {
                    //return HandleResult.Error;
                    return HPSocketCS.HandleResult.Ignore;
                }
            }
            catch (Exception ex)
            {
                SystemFileLogs.WriteLogs("接收数据时出错:" + ex.Message, this.TraceListenerLog);
                return HPSocketCS.HandleResult.Ignore;
            }
            finally
            {
                System.GC.Collect();
            }
        }
        /// <summary>
        /// 连接关闭事件
        /// </summary>
        /// <param name="connId"></param>
        /// <param name="enOperation"></param>
        /// <param name="errorCode"></param>
        /// <returns></returns>
        HPSocketCS.HandleResult OnClose(IntPtr connId, HPSocketCS.SocketOperation enOperation, int errorCode)
        {
			// 移除在线用户;
			RemoveOnlineUser(connId);

            if (errorCode == 0)
            {
                HPSocketCS.Extended.ClientInfo cInfo = hp_Server.GetClientInfo(connId);
                if (cInfo != null)
                {
                    SystemFileLogs.WriteLogs(String.Format("ID为{0}的连接已关闭,IP:{1}:{2}", connId, cInfo.IpAddress, cInfo.Port), this.TraceListenerLog);
                }
                else {
                    SystemFileLogs.WriteLogs(String.Format("ID为{0}的连接已关闭", connId), this.TraceListenerLog);
                }
            }
            else if (enOperation == HPSocketCS.SocketOperation.Close)
            {
                SystemFileLogs.WriteLogs(String.Format("客户端已关闭连接 > [{0},OnError] -> OP:{1},CODE:{2}", connId, enOperation, errorCode), this.TraceListenerLog);
            }
            else
            {
                SystemFileLogs.WriteLogs(String.Format("连接出错 > [{0},OnError] -> OP:{1},CODE:{2}", connId, enOperation, errorCode), this.TraceListenerLog);

                // return HPSocketSdk.HandleResult.Ok;
                return HPSocketCS.HandleResult.Error;
            }
            //hp_Server.SCommonLibrary.ClearInvalidConnectionResource(connId);
            //if (hp_Server.SetConnectionExtra(connId, null) == false)
            //{
            //    SystemFileLogs.WriteLogs("清除连接的附加数据失败:" + errorCode, this.TraceListenerLog);
            //}

            return HPSocketCS.HandleResult.Ok;
        }
        /// <summary>
        /// 服务器关闭事件
        /// </summary>
        /// <returns></returns>
        HPSocketCS.HandleResult OnShutdown()
        {
            // 服务关闭了

            hp_Server.SCommonLibrary.ClearAllInvalidResource();
            return HPSocketCS.HandleResult.Ok;
        }
        /// <summary>
        /// 设置程序状态
        /// </summary>
        /// <param name="state"></param>
        void SetAppState(AppState state)
        {
            appState = state;
        }
        
        static string _ServerStartTimeStamp = "";
        /// <summary>
        /// 服务器启动时间标识
        /// </summary>
        public static string ServerStartTimeStamp
        {
            get { return TCP_NetworkServer._ServerStartTimeStamp; }
            set { TCP_NetworkServer._ServerStartTimeStamp = value; }
        }
        /// <summary>
        /// 申明委托
        /// </summary>
        /// <param name="e"></param>
        /// <returns></returns>
       // public delegate void EventLockVerifiedHandler(EventLockVerified e);
        /// <summary>
        /// EventClientLockVerified事件
        /// </summary>
       // public event EventLockVerifiedHandler EventClientLockVerified;
        #endregion

        #region 客户端请求处理事件
        /// <summary>
        /// 申明客户端请求处理事件委托
        /// </summary>
        /// <param name="hp_Server"></param>
        /// <param name="header"></param>
        /// <param name="connId"></param>
        /// <param name="bytes"></param>
        public delegate void EventSerializationDataRequestHandler(HPSocketCS.TcpPackServer hp_Server, TcpHeadInfo header, IntPtr connId, byte[] bytes);
        /// <summary>
        /// 申明客户端请求处理事件
        /// </summary>
        public event EventSerializationDataRequestHandler EventSerializationDataRequest;

        /// <summary>
        /// 申明客户端请求文件传输处理事件委托
        /// </summary>
        /// <param name="hp_Server"></param>
        /// <param name="header"></param>
        /// <param name="connId"></param>
        /// <param name="bytes"></param>
        public delegate void EventFileDataRequestHandler(HPSocketCS.TcpPackServer hp_Server, TcpHeadInfo header, TcpTailInfo tail, IntPtr connId, byte[] bytes);
        /// <summary>
        /// 申明客户端请求文件传输处理事件
        /// </summary>
        public event EventFileDataRequestHandler EventFileDataRequest;
        #endregion

    }

   /// <summary>
   /// EventLockVerified 客户端连接事件对象
   /// </summary>
   public class EventLockVerified : EventArgs
   {
       public EventLockVerified()
       {

       }
        HPSocketCS.Extended.ClientInfo _CInfo;
       /// <summary>
       /// 客户端信息
       /// </summary>
        public HPSocketCS.Extended.ClientInfo CInfo
       {
           get { return _CInfo; }
           set { _CInfo = value; }
       }    

   }
}