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


namespace SmartScreen
{
    public enum ClientStateEnum
    {
        None,
        InitGetName,
        Version,
        Login,
        PartyCreate,
        PlayerCreate,
        Enter,
        Game
    };

    public 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;
        public PacketMessage pktMessage;


        // functions
        public ClientClass()
        {
            Clear();

            pktResult = new PacketResult();
            pktMessage = new PacketMessage();


            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;
            pktMessage = null;
        }

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

        public void Send(string message)
        {
            byte[] bytes = GetBytes(message);
            Send(bytes, bytes.Length);

        }
        
        public void Send(byte[] buffer, int length)
        {
            string str = "";

            try
            {
                if (!flgInUse)
                    return;

                lock (SocketLock)
                {
                    Log.Add("Sending Data : ");
                    for(int n = 0; n<buffer.Length - 1; n++) {
                        str += Convert.ToString(buffer[n]) + ",";
                    }
                    Log.Add(str);
                    Log.Add("   Length : " + length.ToString());
                    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;
            }

        }


        // *****************************************
        public void SendMessage(string Message)
        // *****************************************
        // Allow a simple mesage to be sent
        // *****************************************
        {
            SendMessage(Message, PktMessageType1.GENERIC, PktMessageType2.GENERIC);
        }

            public void SendMessage(string Message, PktMessageType1 messageType1,  PktMessageType2 messageType2)
        {

            Log.Add("*** SEND MESSAGE ***");
            Log.Add("   Message: " + Message);
            Log.Add("   Type: " + messageType1 + "," + messageType2);
            Log.Add("   Type: " + (int)messageType1 + "," + (int)messageType2);
            Log.Add("   Length: " + (Message.Length + 12));

            try
            {
                pktMessage.NetMessageType1 = messageType1;
                pktMessage.NetMessageType2 = messageType2;
                pktMessage.NetMessage = Message;

                Send(pktMessage.dataBuffer, pktMessage.PacketLen);

            }
            catch (Exception e)
            {
                Log.Add("Error_NetClass.SendMessage : " + e.Message);
            }
        }

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

        static byte[] GetBytes(string str)
        {
            byte[] bytes = new byte[str.Length * sizeof(char)];
            System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
            return bytes;
        }

        static string GetString(byte[] bytes)
        {
            char[] chars = new char[bytes.Length / sizeof(char)];
            System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
            return new string(chars);
        }

    }


    public class AGKNet
    {
        //////////////////////////////////////////////////////////////////////////////////////////

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

        // thread lock objects
        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 bool networkRunning;

        public static int port;

        public static frmSmartScreen parentForm;

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

        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);

                //if port has not been set by application, then use a default value
                if (port == 0) { 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 on port " + port.ToString());
                networkRunning = true;
            }
            catch (SocketException se)
            {
                Log.Add("Error_SetupNet: " + se.Message);
                networkRunning = false;
            }
        }

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

        static public void setParentForm(frmSmartScreen frm)
        {
            parentForm = frm;
        }


        static public void Close()
        {
            try
            {
                mainSocket.Close();
                networkRunning = false;
            }
            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)
        {
            //When closing network, this method gets erroneously called. Drop out if network not running
            if (networkRunning != true)
            {
                return;
            }

            try
            {
                int cIndex = -1;

                for (int i = 0; i <= Client.GetUpperBound(0) - 1; 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[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);

            }
            catch (SocketException se)
            {
                Log.Add("Error_OnClientConnect(socket): " + se.Message);
            }
            catch (Exception e)
            {
                Log.Add("Error_OnClientConnect: " + e.Message);
            }

            if (networkRunning == true)
            {
                mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);
            }
        }

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

        public static void OnPacketIDReceived(IAsyncResult asyn)
        {

            int cIndex = 0;
            int state = 0;

            try
            {
                lock (OnPacketIDReceived_Lock)
                {
                    state = 100;

                    cIndex = (int)asyn.AsyncState;

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

                    if (!Client[cIndex].workerSocket.Connected)
                    {
                        // hits this if got booted or .close() is called or whatever else?

                        if (Client[cIndex].State == ClientStateEnum.Game && Client[cIndex].PartyIndex > 0)

                        //Client[cIndex].workerSocket.Shutdown(SocketShutdown.Both);
                        Client[cIndex].Clear();

                        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)

                        Client[cIndex].workerSocket.Shutdown(SocketShutdown.Both);
                        Client[cIndex].Clear();

                        return;
                    }



                    state = 210;

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

                    state = 300;

                    Client[cIndex].NeedLen = -1;

                    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)

                            Client[cIndex].Clear();

                            return;
                        }

                        if (Client[cIndex].PacketID == 5)
                        {
                            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)

                            Client[cIndex].Clear();

                            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();

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

                    }
                    else if (Client[cIndex].NeedLen > Client[cIndex].workerSocket.Available || DataLen < Client[cIndex].NeedLen)
                    {

                        Client[cIndex].workerSocket.BeginReceive(Client[cIndex].recvBuffer, 0, Client[cIndex].NeedLen, SocketFlags.Peek, pfnPacketIDCallBack, cIndex);
                    }
                    else
                    {
                        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
                            {

                                Client[cIndex].Clear();

                                AGKmessage agkMessage = new AGKmessage();
                                agkMessage.Type1 = (int)PktMessageType1.ERROR;
                                agkMessage.Msg = "Client " + cIndex.ToString() + " Disconnected";
                                parentForm.processMessage(agkMessage);

                            }
                        }
            
            catch (Exception e)
            {

                Client[cIndex].Clear();

                AGKmessage agkMessage = new AGKmessage();
                agkMessage.Type1 = (int)PktMessageType1.ERROR;
                agkMessage.Msg = "Client " + cIndex.ToString() + " Disconnected";
                parentForm.processMessage(agkMessage);
            
            }
        }

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

        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);


                    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);

                        // 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].pingBuffer3, 20);


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

                        // 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

                            lock (Client[cIndex].SocketLock)
                            {

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

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

                        }

                        if (Client[cIndex].PacketID == 0)
                        {

                        }
                    }


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

                }
                
                    
                                catch (SocketException se)
                                {
                                    if (se.ErrorCode == 10054) // Error code for Connection reset by peer
                                    {
                                        
                                        Client[cIndex].Clear();

                                        AGKmessage agkMessage = new AGKmessage();
                                        agkMessage.Type1 = (int)PktMessageType1.ERROR;
                                        agkMessage.Msg = "Client " + cIndex.ToString() + " Disconnected";
                                        parentForm.processMessage(agkMessage);

                                    }
                                    else
                                    {
                                        Log.Add("Error_OnDataReceived :  " + se.Message);
                                    }
                                }

                catch (Exception err)
                {

                    Client[cIndex].Clear();

                    AGKmessage agkMessage = new AGKmessage();
                    agkMessage.Type1 = (int)PktMessageType1.ERROR;
                    agkMessage.Msg = "Client " + cIndex.ToString() + " Disconnected";
                    parentForm.processMessage(agkMessage);
                
                }
            }
        }

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

        public static void OnPacketData5Received(IAsyncResult asyn)
        {

            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
                        Client[cIndex].Clear();

                        AGKmessage agkMessage = new AGKmessage();
                        agkMessage.Type1 = (int)PktMessageType1.ERROR;
                        agkMessage.Msg = "Client " + cIndex.ToString() + " Disconnected";
                        parentForm.processMessage(agkMessage);
                        
                        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

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

                    Log.Add("Got PacketID " + PacketID);
                    string str = "";
                    for (int n = 0; n < Client[cIndex].recvBuffer.Length - 1; n++)
                    {
                        str += Convert.ToString(Client[cIndex].recvBuffer[n]) + ","; 
                    }
                    Log.Add(str);


                    //**** Receive message

                    RecvRequest(cIndex);
                    Log.Add("Packet type 4 received");




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

                }
                
                    
                                catch (SocketException se)
                                {
                                    if (se.ErrorCode == 10054) // Error code for Connection reset by peer
                                    {

                                        Client[cIndex].Clear();

                                        AGKmessage agkMessage = new AGKmessage();
                                        agkMessage.Type1 = (int)PktMessageType1.ERROR;
                                        agkMessage.Msg = "Client " + cIndex.ToString() + " Disconnected";
                                        parentForm.processMessage(agkMessage);

                                    }
                                    else
                                    {
                                        Log.Add("Error_OnData5Received :  " + se.Message);
                                    }
                                }
                catch (Exception err)
                {

                    Client[cIndex].Clear();

                    AGKmessage agkMessage = new AGKmessage();
                    agkMessage.Type1 = (int)PktMessageType1.ERROR;
                    agkMessage.Msg = "Client " + cIndex.ToString() + " Disconnected";
                    parentForm.processMessage(agkMessage);
                
                }
            }
        }

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

        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;

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

                AGKmessage agkMessage = new AGKmessage();
                agkMessage.Type1 = (int)PktMessageType1.ERROR;
                agkMessage.Msg = err.Message;
                parentForm.processMessage(agkMessage);

            }

        }

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

        public static void RecvRequest(int cIndex)
        {
            try
            {
                AGKmessage agkMessage = new AGKmessage();

                //Type 1
                int index = 16;
                agkMessage.Type1 = BitConverter.ToInt32(Client[cIndex].recvBuffer, index);

                //Type 2
                index += 4;
                agkMessage.Type2 = BitConverter.ToInt32(Client[cIndex].recvBuffer, index);

                //Text String Length
                index += 4;
                int textLength = BitConverter.ToInt32(Client[cIndex].recvBuffer, index);

                //Text String
                index += 4;
                agkMessage.Msg = Encoding.UTF8.GetString(Client[cIndex].recvBuffer, index, textLength);


                parentForm.processMessage(agkMessage);



                return;

            }
            catch (Exception err)
            {
                AGKmessage agkMessage = new AGKmessage();
                agkMessage.Type1 = (int)PktMessageType1.ERROR;
                agkMessage.Msg = err.Message;
                parentForm.processMessage(agkMessage);

            }
        }

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

    }


    static class PacketVersion
    {
        static public int MajorVersion = 0;
        static public int MinorVersion = 1;
    };


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

    public enum PktResultEnum
    {
        Version = 10,

        Login = 20

    };


    public class PacketResult
    {
        public int PacketID = 10;

        public int PacketLen = 32;

        public byte[] dataBuffer;

        public PacketResult()
        {
            dataBuffer = new byte[PacketLen];

            // agk header
            BitConverter.GetBytes(5).CopyTo(dataBuffer, 0);     // agk packet id 5 "net msg"
            BitConverter.GetBytes(1).CopyTo(dataBuffer, 4);     // from id, always server

            BitConverter.GetBytes(PacketLen - 12).CopyTo(dataBuffer, 8);    // data length

            BitConverter.GetBytes(PacketID).CopyTo(dataBuffer, 12);       // game packetid    

        }


        public PktResultEnum Result
        {
            set
            {
                BitConverter.GetBytes((int)value).CopyTo(dataBuffer, 16);
            }
        }

        public int Data1
        {
            set
            {
                BitConverter.GetBytes(value).CopyTo(dataBuffer, 20);
            }
        }

        public int Data2
        {
            set
            {
                BitConverter.GetBytes(value).CopyTo(dataBuffer, 24);
            }
        }

        public int Data3
        {
            set
            {
                BitConverter.GetBytes(value).CopyTo(dataBuffer, 28);
            }
        }
    };

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

    public class PacketRequest
    {
        public int Request;

        public int Data1;
        public int Data2;
        public int Data3;
    };

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

    public class AGKmessage
    {

        public int Type1;
        public int Type2;
        public string Msg;
    };


    static class Log
    {

        private static System.IO.StreamWriter sw;
        private static bool logFileOpen;

        // !! Change this to your Form where the log text box resides
        public static SmartScreen.frmSmartScreen parent;

        public static void OpenLogFile()
        {
            sw = new System.IO.StreamWriter(AppDomain.CurrentDomain.BaseDirectory + "\\log.txt",false);
            logFileOpen = true;
        }

        public static void openLogFile(string fileName)
        {
            sw = new System.IO.StreamWriter(fileName,false);
            logFileOpen = true;
        }


        public static void Add(string text)
        {
            if (!logFileOpen)
            {
                OpenLogFile();
            }
            sw.WriteLine(text);
        }


    }


    // **********************************************************

    /*
     * Enumerate your message types here. This is the first part of the message type
     * For example, specify this is a server message, or game action
     * They must be matched in the AGK network code
     */
    public enum PktMessageType1
    {
        GENERIC = 5,
        SYSTEM = 10,
        IMAGE = 20,
        SPRITE = 30,
        OBJECT = 40,
        SOUND = 50,
        MUSIC = 60,
        TEXT = 70,
        FILE = 80,
        PHYSICS = 90,
        PARTICLES = 100,
        INPUT = 110,
        ERROR = 120
        // Add any other message types here
    };

    /*
     * Enumerate your message types here. This is the second part of the message type
     * For example, specify this is a server message, or game action
     * They must be matched in the AGK network code
     */
    public enum PktMessageType2
    {
        GENERIC = 5,
        CREATE = 10,
        DELETE = 20,
        MOVE = 30,
        ROTATE = 40,
        SIZE = 50,
        POSITION = 60,
        ANGLE = 70,
        PLAY = 80,
        OPEN = 90,
        CLOSE = 100
    };

    // **********************************************************

    /*
     * This class builds a message to be sent. It includes the headers required by AGK
     * set the NetMessageType (from pktTextTypeEnum)
     * set the NetMessage - your data
     * After building, call the Send() method for the client you are sending to...
     * Client[n].Send(Client[n].pktMessage.dataBuffer, message.length + 12)
     */
    public class PacketMessage
    {

        public int PacketLen = 300;

        public byte[] dataBuffer;

        public PacketMessage()
        {
            dataBuffer = new byte[PacketLen];

            BitConverter.GetBytes(5).CopyTo(dataBuffer, 0);     // agk packet id 5 "net msg"
            BitConverter.GetBytes(1).CopyTo(dataBuffer, 4);     // from id, always server

            BitConverter.GetBytes((int)PacketLen - 12).CopyTo(dataBuffer, 8);    // data length

        }



        public PktMessageType1 NetMessageType1
        {
            set
            {
                BitConverter.GetBytes((int)value).CopyTo(dataBuffer, 12);
            }
        }

        public PktMessageType2 NetMessageType2
        {
            set
            {
                BitConverter.GetBytes((int)value).CopyTo(dataBuffer, 16);
            }
        }

        /*
         * NetMessage - set the message you want to send
         * Also need to set the PacketID (first part of message type) and NetMessageType (second part of message type)
         */
        public string NetMessage
        {
            set
            {

                // *** Put the message length into the buffer at position 20

                BitConverter.GetBytes(value.Length).CopyTo(dataBuffer, 20);

                // *** now add the message from position 24
                for (int i = 0; i < value.Length; i++)
                {
                    dataBuffer[24 + i] = Convert.ToByte(value[i]);
                }

            }
        }


    }  // End Class NetMessage


} // end namespace