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


namespace GameServer
{
    public enum ClientStateEnum
    {
        None,

        InitGetName,

        Version,
        Login,

        PartyCreate,

        PlayerCreate,

        Enter,
        Game
    };

    class ClientClass
    {
        public bool flgInUse;

        public bool flgClosing;

        public ClientStateEnum State;

        public string UserName;

        public int PartyUUID;

        public int PartyIndex;
                  
        public DateTime LastPing;

        public double Latency;

        private int DataCount;
             

        // socket info
        public Socket workerSocket;

        public Object SocketLock = new Object();

        public byte[] recvBuffer = new byte[1400];
        public byte[] sendBuffer = new byte[1400];

        //public byte[] pingBuffer = new byte[100];
        //public byte[] pingBuffer2 = new byte[100];
        public byte[] pingBuffer3 = new byte[100];

        public int PacketID;
        public int NeedLen;

        //public bool flgPingSent;
        


        // packets
        public PacketResult pktResult;


        // functions
        public ClientClass()
        {
            Clear();
                        
            pktResult = new PacketResult();
            

            BitConverter.GetBytes(6).CopyTo(pingBuffer3, 0);
            BitConverter.GetBytes(0).CopyTo(pingBuffer3, 4);
            BitConverter.GetBytes(2).CopyTo(pingBuffer3, 8);
            BitConverter.GetBytes(1).CopyTo(pingBuffer3, 12);
            BitConverter.GetBytes((float)0.5).CopyTo(pingBuffer3, 16);
            BitConverter.GetBytes(2).CopyTo(pingBuffer3, 20);
            BitConverter.GetBytes((float)0.5).CopyTo(pingBuffer3, 24);

        }

        public void Clear()
        {
            //Log.Add("client cleared!");

            flgInUse = false;
            flgClosing = false;
            State = ClientStateEnum.None;
            workerSocket = null;
            PacketID = 0;
            UserName = "";
            PartyIndex = 0;
            LastPing = DateTime.MinValue;
            Latency = 0.0;
            DataCount = 0;
        }

        //////////////////////////////////////////////////////////////////////////////////////////

        public void Send(byte[] buffer, int length)
        {
            try
            {
                if (!flgInUse)
                    return;

                lock (SocketLock)
                {
                    workerSocket.Send(buffer, length, SocketFlags.None);

                }

                DataCount += length;

                if (DataCount > 512)   // this slows data sending cuz agk client disconnects if send too fast. Don't know why.
                {
                    DataCount = 0;
                    Thread.Sleep(20);
                }
                
            }
            catch (Exception err)
            {
                Log.Add("Error_Client_Send : " + err.Message);

                Log.Add("Client " + UserName + " Disconnected (1000)");

                if (State == ClientStateEnum.Game && PartyIndex > 0)
                    EventProcess.Add(EventClass.EventEnum.Event_LeaveWorld, 0, PartyIndex, 0, 0, 0);

                Clear();
                Game.flgUpdateClientList = true;
            }
        }

        //////////////////////////////////////////////////////////////////////////////////////////

    }




    class Net
    {
        //////////////////////////////////////////////////////////////////////////////////////////

        private static AsyncCallback pfnPacketIDCallBack;
        private static AsyncCallback pfnPacketDataCallBack;
        private static AsyncCallback pfnPacketData5CallBack;

        // thread lock objects
        ////private static Object SetupClientForRecvPacketID_Lock = new Object();
        ////private static Object SetupClientForRecvPacketData_Lock = new Object();
        private static Object OnPacketIDReceived_Lock = new Object();
        private static Object OnPacketDataReceived_Lock = new Object();

        private static Socket mainSocket;

        public static ClientClass[] Client = new ClientClass[100];


        //////////////////////////////////////////////////////////////////////////////////////////

        public static void SetupNet()
        {
            try
            {
                for (int i = 0; i <= Client.GetUpperBound(0); i++)
                    Client[i] = new ClientClass();

                pfnPacketIDCallBack = new AsyncCallback(OnPacketIDReceived);
                pfnPacketDataCallBack = new AsyncCallback(OnPacketDataReceived);
                pfnPacketData5CallBack = new AsyncCallback(OnPacketData5Received);

                int port = 4503;

                // Create the listening socket...
                mainSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                IPEndPoint ipLocal = new IPEndPoint(IPAddress.Any, port);

                // Bind to local IP Address...
                mainSocket.Bind(ipLocal);

                // Start listening...
                mainSocket.Listen(5);

                // Create the call back for any client connections...
                mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);

                Log.Add("Network Ready");
            }
            catch (SocketException se)
            {
                Log.Add("Error_SetupNet: " + se.Message);
            }
        }

        //////////////////////////////////////////////////////////////////////////////////////////

        static public void Close()
        {
            try
            {
                mainSocket.Close();
            }
            catch (Exception err)
            {
                Log.Add("Error_Net.Close : " + err.Message);
            }
        }

        //////////////////////////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////////////////////////

        // This is the call back function, which will be invoked when a client is connected
        private static void OnClientConnect(IAsyncResult asyn)
        {
            try
            {
                int cIndex = -1;

                for (int i = 1; i <= Client.GetUpperBound(0); i++)
                {
                    if (!Client[i].flgInUse)
                    {
                        Client[i].workerSocket = mainSocket.EndAccept(asyn);

                        Client[i].workerSocket.NoDelay = true;

                        Client[i].workerSocket.ReceiveBufferSize = 1000;
                        Client[i].workerSocket.SendBufferSize = 16000;

                        Client[i].workerSocket.SendTimeout = 0;

                        ///Client[cIndex].workerSocket.Blocking   // need to set???

                        Client[i].flgInUse = true;
                        Client[i].State = ClientStateEnum.InitGetName;
                        cIndex = i;
                        break;
                    }
                }

                if (cIndex == -1)
                {
                    // server full
                    Log.Add("Server is full!");

                    mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);

                    return;
                }

                Log.Add("Client connected " + cIndex + " on IP " + Client[cIndex].workerSocket.RemoteEndPoint.ToString());

                Client[cIndex].workerSocket.BeginReceive(Client[cIndex].recvBuffer, 0, 4, SocketFlags.Peek, pfnPacketIDCallBack, cIndex);

                Game.flgUpdateClientList = true;

                //mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);
            }
            catch (SocketException se)
            {
                Log.Add("Error_OnClientConnect(socket): " + se.Message);
            }
            catch (Exception e)
            {
                Log.Add("Error_OnClientConnect: " + e.Message);
            }

            mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);
        }

        //////////////////////////////////////////////////////////////////////////////////////////

        public static void OnPacketIDReceived(IAsyncResult asyn)
        {
            //Log.Add("OnPacketIDReceived");

            int cIndex = 0;
            int state = 0;

            try
            {
                lock (OnPacketIDReceived_Lock)
                {
                    state = 100;

                    cIndex = (int)asyn.AsyncState;

                    if (Client[cIndex] == null || Client[cIndex].flgClosing) // || !Client[cIndex].workerSocket.Connected)
                        return;

                    if (!Client[cIndex].workerSocket.Connected)
                    {
                        //Log.Add("Recv: Not connected!");
                        // hits this if got booted or .close() is called or whatever else?

                        if (Client[cIndex].State == ClientStateEnum.Game && Client[cIndex].PartyIndex > 0)
                            EventProcess.Add(EventClass.EventEnum.Event_LeaveWorld, 0, Client[cIndex].PartyIndex, 0, 0, 0);

                        //Client[cIndex].workerSocket.Shutdown(SocketShutdown.Both);
                        Client[cIndex].Clear();
                        Game.flgUpdateClientList = true;

                        return;
                    }

                    state = 200;

                    int DataLen = Client[cIndex].workerSocket.EndReceive(asyn);

                    if (DataLen == 0)
                    {
                        // disconnected?
                        Log.Add(DateTime.Now + " Client " + cIndex + " Disconnected in PacketIDRecv");

                        if (Client[cIndex].State == ClientStateEnum.Game && Client[cIndex].PartyIndex > 0)
                            EventProcess.Add(EventClass.EventEnum.Event_LeaveWorld, 0, Client[cIndex].PartyIndex, 0, 0, 0);

                        Client[cIndex].workerSocket.Shutdown(SocketShutdown.Both);
                        Client[cIndex].Clear();
                        Game.flgUpdateClientList = true;

                        return;
                    }



                    state = 210;

                    Client[cIndex].PacketID = BitConverter.ToInt32(Client[cIndex].recvBuffer, 0);

                    //Log.Add("client " + cIndex + " Client[cIndex].PacketID = " + Client[cIndex].PacketID + " : conpleted=" + asyn.IsCompleted);

                    state = 300;

                    Client[cIndex].NeedLen = -1;
                    //byte[] dataBuffer = null;

                    if (Client[cIndex].State == ClientStateEnum.InitGetName)
                    {
                        Client[cIndex].NeedLen = Client[cIndex].PacketID + 4;
                    }
                    else
                    {
                        if (Client[cIndex].PacketID == 6)
                        {
                            // safe disconnect sent from client

                            Log.Add("Client " + cIndex + " disconnected  (6)");

                            Client[cIndex].workerSocket.Disconnect(true);

                            if (Client[cIndex].State == ClientStateEnum.Game && Client[cIndex].PartyIndex > 0)
                                EventProcess.Add(EventClass.EventEnum.Event_LeaveWorld, 0, Client[cIndex].PartyIndex, 0, 0, 0);

                            Client[cIndex].Clear();
                            Game.flgUpdateClientList = true;

                            return;
                        }

                        if (Client[cIndex].PacketID == 5)
                        {
                            // network message: <5><FromNetID><ToNetID><length><data>

                            //Log.Add("got msg 5, avail=" + Client[cIndex].workerSocket.Available);

                            //string s1 = "Data= ";
                            //for (int i = 0; i < Client[cIndex].workerSocket.Available; i++)
                            //    s1 += Client[cIndex].recvBuffer[i];
                            //Log.Add(s1);
                            /*
                                                        //if (Client[cIndex].workerSocket.Available < 16)
                                                        if (DataLen < 16)
                                                        {
                                                            Log.Add("Recv PacketID : DataLen < 16");
                                                            Client[cIndex].NeedLen = 16;
                                                        }
                                                        else
                                                        {
                                                            //Log.Add("got msg 5, 100");
                                                            Client[cIndex].NeedLen = 16 + BitConverter.ToInt32(Client[cIndex].recvBuffer, 12);
                                                            //Log.Add("got msg 5, 200");
                                                        }
                            */
                            Client[cIndex].workerSocket.BeginReceive(Client[cIndex].recvBuffer, 0, 16, SocketFlags.Peek, pfnPacketData5CallBack, cIndex);
                            return;
                        }
                        else if (Client[cIndex].PacketID == 7 || Client[cIndex].PacketID == 0)
                        {
                            Client[cIndex].NeedLen = 4;
                        }
                        else
                        {
                            Log.Add("Unknown Packet ID " + Client[cIndex].PacketID + " on client " + cIndex);

                            Client[cIndex].workerSocket.Disconnect(true);

                            if (Client[cIndex].State == ClientStateEnum.Game && Client[cIndex].PartyIndex > 0)
                                EventProcess.Add(EventClass.EventEnum.Event_LeaveWorld, 0, Client[cIndex].PartyIndex, 0, 0, 0);

                            Client[cIndex].Clear();
                            Game.flgUpdateClientList = true;

                            return;
                        }
                    }



                    state = 400;

                    if (Client[cIndex].NeedLen == -1)
                    {
                        // unknown packet ID... drop the connection
                        Log.Add("Unknown Packet ID " + Client[cIndex].PacketID + " on client " + cIndex);

                        Client[cIndex].workerSocket.Disconnect(true);

                        if (Client[cIndex].State == ClientStateEnum.Game && Client[cIndex].PartyIndex > 0)
                            EventProcess.Add(EventClass.EventEnum.Event_LeaveWorld, 0, Client[cIndex].PartyIndex, 0, 0, 0);

                        Client[cIndex].Clear();
                        Game.flgUpdateClientList = true;

                        //SendTextToAll("Client " + cIndex + " has left the world.", 0, cIndex);

                    }
                    else if (Client[cIndex].NeedLen > Client[cIndex].workerSocket.Available || DataLen < Client[cIndex].NeedLen)
                    {
                        //Log.Add("NeedLen > Available!!!!   Available=" + Client[cIndex].workerSocket.Available);

                        Client[cIndex].workerSocket.BeginReceive(Client[cIndex].recvBuffer, 0, Client[cIndex].NeedLen, SocketFlags.Peek, pfnPacketIDCallBack, cIndex);
                    }
                    else
                    {
                        //Log.Add("start Recv full pkt");
                        Client[cIndex].workerSocket.BeginReceive(Client[cIndex].recvBuffer, 0, Client[cIndex].NeedLen, SocketFlags.None, pfnPacketDataCallBack, cIndex);
                    }

                    state = 500;
                }
            }
            /*
                        catch (SocketException se)
                        {
                            if (se.ErrorCode == 10054) // Error code for Connection reset by peer
                            {
                                Log.Add("Client " + cIndex + " Disconnected (100)");

                                if (Client[cIndex].State == ClientStateEnum.Game && Client[cIndex].UnitIndex > 0)
                                    EventProcess.Add(EventClass.EventEnum.Event_LeaveWorld, 0, Client[cIndex].UnitIndex, 0, 0, 0);

                                Client[cIndex].Clear();
                                Game.flgUpdateClientList = true;

                                //SendTextToAll("Client " + cIndex + " has left the world.", 0, cIndex);
                            }
                            else
                            {
                                Log.Add("Error_OnPacketIDReceived :  " + se.Message + " : StateA=" + state);
                            }
                        }
             */
            catch (Exception e)
            {
                Log.Add("Error_PacketIdReceived :  " + e.Message + " : StateB=" + state);

                Log.Add("Client " + cIndex + " Disconnected (100)");

                if (Client[cIndex].State == ClientStateEnum.Game && Client[cIndex].PartyIndex > 0)
                    EventProcess.Add(EventClass.EventEnum.Event_LeaveWorld, 0, Client[cIndex].PartyIndex, 0, 0, 0);

                Client[cIndex].Clear();
                Game.flgUpdateClientList = true;
            }
        }

        //////////////////////////////////////////////////////////////////////////////////////////

        public static void OnPacketDataReceived(IAsyncResult asyn)
        {
            //Log.Add("OnPacketDataReceived");

            lock (OnPacketDataReceived_Lock)
            {
                int cIndex = (int)asyn.AsyncState;

                try
                {
                    if (Client[cIndex] == null || Client[cIndex].flgClosing)
                        return;

                    int DataLen = Client[cIndex].workerSocket.EndReceive(asyn);

                    //Log.Add("client " + cIndex + " Full data recv DataLen=" + DataLen);

                    if (Client[cIndex].State == ClientStateEnum.InitGetName)
                    {
                        // don't really need the name
                        //string UserName;
                        //UserName = System.Text.Encoding.UTF8.GetString(Client[cIndex].recvBuffer, 4, Client[cIndex].NeedLen - 4).Trim('\0', ' ');
                        //Log.Add("UserName=" + UserName);

                        // send ack
                        BitConverter.GetBytes(1).CopyTo(Client[cIndex].sendBuffer, 0);
                        //Client[cIndex].workerSocket.Send(Client[cIndex].sendBuffer, 4, SocketFlags.None);

                        // send net id
                        BitConverter.GetBytes(cIndex + 1).CopyTo(Client[cIndex].sendBuffer, 4);

                        Client[cIndex].workerSocket.Send(Client[cIndex].sendBuffer, 8, SocketFlags.None);


                        // set net id for ping sending
                        //BitConverter.GetBytes(cIndex + 1).CopyTo(Client[cIndex].pingBuffer2, 16);
                        BitConverter.GetBytes(cIndex + 1).CopyTo(Client[cIndex].pingBuffer3, 20);


                        // send number of clients on, just 1 for server
                        BitConverter.GetBytes(1).CopyTo(Client[cIndex].sendBuffer, 0);
                        //Client[cIndex].workerSocket.Send(Client[cIndex].sendBuffer, 4, SocketFlags.None);

                        // send server id, name, variables
                        BitConverter.GetBytes(1).CopyTo(Client[cIndex].sendBuffer, 4);
                        BitConverter.GetBytes(6).CopyTo(Client[cIndex].sendBuffer, 8);
                        System.Text.Encoding.UTF8.GetBytes("server").CopyTo(Client[cIndex].sendBuffer, 12);
                        BitConverter.GetBytes(0).CopyTo(Client[cIndex].sendBuffer, 18);

                        lock (Client[cIndex].SocketLock)
                        {
                            Client[cIndex].workerSocket.Send(Client[cIndex].sendBuffer, 22, SocketFlags.None);
                        }

                        Client[cIndex].State = ClientStateEnum.Version;
                    }
                    else
                    {
                        if (Client[cIndex].PacketID == 7)
                        {
                            // ping request

                            //BitConverter.GetBytes(6).CopyTo(Client[cIndex].sendBuffer, 0);
                            //BitConverter.GetBytes(0).CopyTo(Client[cIndex].sendBuffer, 4);
                            //BitConverter.GetBytes(2).CopyTo(Client[cIndex].sendBuffer, 8);
                            //BitConverter.GetBytes(1).CopyTo(Client[cIndex].sendBuffer, 12);
                            //BitConverter.GetBytes(0).CopyTo(Client[cIndex].sendBuffer, 16);
                            //BitConverter.GetBytes(2).CopyTo(Client[cIndex].sendBuffer, 20);
                            //BitConverter.GetBytes(0).CopyTo(Client[cIndex].sendBuffer, 24);


                            //Log.Add(DateTime.Now + " got ping");

                            //SendTime(cIndex);

                            lock (Client[cIndex].SocketLock)
                            {
                                //Client[cIndex].workerSocket.Send(Client[cIndex].pingBuffer, 4, SocketFlags.None);

                                //Client[cIndex].workerSocket.Send(Client[cIndex].pingBuffer2, 24, SocketFlags.None);

                                Client[cIndex].workerSocket.Send(Client[cIndex].pingBuffer3, 28, SocketFlags.None);
                            }

                            Client[cIndex].LastPing = DateTime.Now.AddSeconds(0.5);

                            //Log.Add("ping sent");
                        }

                        if (Client[cIndex].PacketID == 0)
                        {
                            // ping ack
                            //Client[cIndex].flgPingSent = false;

                            //Log.Add("ping ack recv");
                        }
                    }


                    if (Client[cIndex].workerSocket != null && Client[cIndex].workerSocket.Connected)
                    {
                        Client[cIndex].workerSocket.BeginReceive(Client[cIndex].recvBuffer, 0, 4, SocketFlags.Peek, pfnPacketIDCallBack, cIndex);
                        //Log.Add("Beginrecv");
                    }

                }
                /*
                                catch (SocketException se)
                                {
                                    if (se.ErrorCode == 10054) // Error code for Connection reset by peer
                                    {
                                        Log.Add("Client " + cIndex + " Disconnected (200)");

                                        if (Client[cIndex].State == ClientStateEnum.Game && Client[cIndex].UnitIndex > 0)
                                            EventProcess.Add(EventClass.EventEnum.Event_LeaveWorld, 0, Client[cIndex].UnitIndex, 0, 0, 0);

                                        Client[cIndex].Clear();
                                        Game.flgUpdateClientList = true;

                                        //SendTextToAll("Client " + cIndex + " has left the world.", 0, cIndex);
                                    }
                                    else
                                    {
                                        Log.Add("Error_OnDataReceived :  " + se.Message);
                                    }
                                }
                 */
                catch (Exception err)
                {
                    Log.Add("Error_OnDataReceived :  " + err.Message);

                    Log.Add("Client " + cIndex + " Disconnected (200)");

                    if (Client[cIndex].State == ClientStateEnum.Game && Client[cIndex].PartyIndex > 0)
                        EventProcess.Add(EventClass.EventEnum.Event_LeaveWorld, 0, Client[cIndex].PartyIndex, 0, 0, 0);

                    Client[cIndex].Clear();
                    Game.flgUpdateClientList = true;
                }
            }
        }

        //////////////////////////////////////////////////////////////////////////////////////////

        public static void OnPacketData5Received(IAsyncResult asyn)
        {
            //Log.Add("OnPacketDataReceived");

            lock (OnPacketDataReceived_Lock)
            {
                int cIndex = (int)asyn.AsyncState;

                try
                {
                    if (Client[cIndex] == null || Client[cIndex].flgClosing)
                        return;

                    int DataLen = Client[cIndex].workerSocket.EndReceive(asyn);

                    //Log.Add("client " + cIndex + " Full data recv DataLen=" + DataLen);


                    if (DataLen == 0)
                    {
                        // disconnected
                        Log.Add("Client " + cIndex + " Disconnected (5)");

                        if (Client[cIndex].State == ClientStateEnum.Game && Client[cIndex].PartyIndex > 0)
                            EventProcess.Add(EventClass.EventEnum.Event_LeaveWorld, 0, Client[cIndex].PartyIndex, 0, 0, 0);

                        Client[cIndex].Clear();
                        Game.flgUpdateClientList = true;
                        return;
                    }
                    else if (DataLen == 16)
                    {
                        Client[cIndex].NeedLen = 16 + BitConverter.ToInt32(Client[cIndex].recvBuffer, 12);

                        Client[cIndex].workerSocket.BeginReceive(Client[cIndex].recvBuffer, 0, Client[cIndex].NeedLen, SocketFlags.None, pfnPacketData5CallBack, cIndex);
                        return;
                    }

                    // should have full packet data at this point
                    //Log.Add("got full packet  datalen=" + DataLen + " , avail=" + Client[cIndex].workerSocket.Available);

                    int PacketID = BitConverter.ToInt32(Client[cIndex].recvBuffer, 16);
                    //float PacketID = BitConverter.ToSingle(Client[cIndex].recvBuffer, 16); 
                    //int StringLen = BitConverter.ToInt32(Client[cIndex].recvBuffer, 16); 
                    //string PacketID = System.Text.Encoding.UTF8.GetString(Client[cIndex].recvBuffer, 20, StringLen);

                    //Log.Add("Got PacketID " + PacketID);


                    switch (PacketID)
                    {

                        case 1:
                            // version 

                            if (Client[cIndex].State == ClientStateEnum.Version)
                            {
                                int MajorVer = BitConverter.ToInt32(Client[cIndex].recvBuffer, 20);
                                int MinorVer = BitConverter.ToInt32(Client[cIndex].recvBuffer, 24);

                                if (MajorVer != PacketVersion.MajorVersion || MinorVer != PacketVersion.MinorVersion)
                                {
                                    SendResult(cIndex, PktResultEnum.Version, 0, 0);
                                    // disconnect event
                                    //Log.Add("Version bad on " + cIndex);

                                }
                                else
                                {
                                    SendResult(cIndex, PktResultEnum.Version, 1, 0);
                                    //Log.Add("Version good on " + cIndex);
                                    
                                    Client[cIndex].State = ClientStateEnum.Login;
                                }
                            }
                            else
                            {
                                // need to boot
                            }

                            break;
                        case 2:
                            // login

                            
                            if (Client[cIndex].State == ClientStateEnum.Login)
                            {
                                //Log.Add("got login pkt : 100");
                                RecvLogin(cIndex);
                            }
                            else
                            {
                                //Log.Add("got login pkt : 200");
                                // need to boot
                            }

                            break;

                        case 3:
                            // create party

                            RecvCreateParty(cIndex);

                            break;

                        case 4:
                            // REQUEST

                            RecvRequest(cIndex);

                            break;

                        case 5:
                            // chat

                            RecvChat(cIndex);

                            break;
/***
                        case 6:
                            // ping

                            //RecvPing(cIndex);
                            Log.Add("RecvPing?!?!?");

                            break;

                        case 7:
                            // latency

                            RecvLatency(cIndex);

                            break;
***/
                        case 10:
                            // create player

                            RecvCreatePlayer(cIndex);

                            break;

                        default:
                            Log.Add("Unknown packetid=" + PacketID + " from client " + cIndex);

                            break;
                    }


                    if (Client[cIndex].workerSocket != null && Client[cIndex].workerSocket.Connected)
                    {
                        Client[cIndex].workerSocket.BeginReceive(Client[cIndex].recvBuffer, 0, 4, SocketFlags.Peek, pfnPacketIDCallBack, cIndex);
                        //Log.Add("Beginrecv");
                    }

                }
                /*
                                catch (SocketException se)
                                {
                                    if (se.ErrorCode == 10054) // Error code for Connection reset by peer
                                    {
                                        Log.Add("Client " + cIndex + " Disconnected (200)");

                                        if (Client[cIndex].State == ClientStateEnum.Game && Client[cIndex].UnitIndex > 0)
                                            EventProcess.Add(EventClass.EventEnum.Event_LeaveWorld, 0, Client[cIndex].UnitIndex, 0, 0, 0);

                                        Client[cIndex].Clear();
                                        Game.flgUpdateClientList = true;

                                        //SendTextToAll("Client " + cIndex + " has left the world.", 0, cIndex);
                                    }
                                    else
                                    {
                                        Log.Add("Error_OnData5Received :  " + se.Message);
                                    }
                                }
                 */
                catch (Exception err)
                {
                    Log.Add("Error_OnData5Received :  " + err.Message);

                    Log.Add("Client " + cIndex + " Disconnected (201)");

                    if (Client[cIndex].State == ClientStateEnum.Game && Client[cIndex].PartyIndex > 0)
                        EventProcess.Add(EventClass.EventEnum.Event_LeaveWorld, 0, Client[cIndex].PartyIndex, 0, 0, 0);

                    Client[cIndex].Clear();
                    Game.flgUpdateClientList = true;
                }
            }
        }

        //////////////////////////////////////////////////////////////////////////////////////////

        public static void SendResult(int cIndex, PktResultEnum Result, int Data1, int Data2, int Data3 = 0)
        {
            try
            {
                if (cIndex == 0)
                    return;

                Client[cIndex].pktResult.Result = Result;
                Client[cIndex].pktResult.Data1 = Data1;
                Client[cIndex].pktResult.Data2 = Data2;
                Client[cIndex].pktResult.Data3 = Data3;

                //lock (Client[cIndex].SocketLock)
                //{
                Client[cIndex].Send(Client[cIndex].pktResult.dataBuffer, Client[cIndex].pktResult.PacketLen);
                //}
            }
            catch (Exception err)
            {
                Log.Add("Error_SendResult :  " + err.Message);
            }

        }

        //////////////////////////////////////////////////////////////////////////////////////////

        public static void RecvRequest(int cIndex)
        {
            try
            {
                PacketRequest pkt = new PacketRequest();

                // 3 int
                int index = 20;
                pkt.Request = BitConverter.ToInt32(Client[cIndex].recvBuffer, index);
                pkt.Data1 = BitConverter.ToInt32(Client[cIndex].recvBuffer, index += 4);
                pkt.Data2 = BitConverter.ToInt32(Client[cIndex].recvBuffer, index += 4);
                pkt.Data3 = BitConverter.ToInt32(Client[cIndex].recvBuffer, index += 4);

                //Log.Add("net.RecvReq : " + pkt.Request);

                EventProcess.Add(EventClass.EventEnum.Event_Net_Request, 0, cIndex, pkt.Request, pkt.Data1, pkt.Data2, pkt.Data3);
                
                return;

            }
            catch (Exception err)
            {
                Log.Add("Error_Net_RecvRequest :  " + err.Message);
            }
        }

        //////////////////////////////////////////////////////////////////////////////////////////

    }
}