/// <summary>
        /// When a packet is received, this function is called
        /// </summary>
        /// <param name="ar"></param>
        private void OnReceive(IAsyncResult ar)
        {
            try
            {
                Socket clientSocket = (Socket)ar.AsyncState;
                clientSocket.EndReceive(ar);

                ClientInfo clientInfo;
                byte[] message = null;
                String User = "******";

                
                //Transform the array of bytes received from the user into an
                //intelligent form of object Data
                MTGNetworkPacket msgReceived = new MTGNetworkPacket(byteData);
                MTGNetworkPacket msgToSend = new MTGNetworkPacket();
                                
                
                //If the message is to login, logout, or simple text message
                //then when send to others the type of the message remains the same
                switch (msgReceived.OpCode)
                {
                    // *** Login ***
                    case MTGNetworkPacket.MTGOpCode.Login:

                        Int32 result = 0;

                        // verify that this user can log on
                        String data = msgReceived.Data.ToString();
                        String user = data.Substring(0, data.IndexOf(":"));
                        String pass = data.Substring(data.IndexOf(":") + 1);

                        // now check the user against the database...
                        if (MTGDB.ValidateUser(user, pass))
                        {   
                            result = 1;

                            if (MTGDB.IsAdmin(user, pass))
                            {
                                result += 1;
                            }
                        }

                        //When a user logs in to the server then we add them to our list of clients
                        clientInfo = new ClientInfo();
                        clientInfo.Socket= clientSocket;
                        clientInfo.Player = user;
                        ClientList.Add(clientInfo);

                        // Send back a login packet to the user to tell them if user was validate against db
                        msgToSend.OpCode = MTGNetworkPacket.MTGOpCode.Login;
                        msgToSend.Data = result;

                        message = msgToSend.ToByte();

                        clientSocket.BeginSend(message, 0, message.Length, SocketFlags.None, new AsyncCallback(OnSend), clientSocket);

                        // this player isn't a valid player, so disconnect the client
                        if (result == 0)
                        {
                            // error, just disconnect this connection
                            foreach (ClientInfo client in ClientList)
                            {
                                if (client.Socket == clientSocket)
                                {
                                    // remove this user from the client list
                                    ClientList.Remove(client);
                                    break;
                                }
                            }
                        }
                        else
                        {

                            // mmb - todo
                            // save data like online field, login time, etc

                            //Send the name of the users in the chat room... User has logged in.
                            // Send back a login packet to the user to tell them if user was validate against db
                            msgToSend.OpCode = MTGNetworkPacket.MTGOpCode.Chat;
                            msgToSend.Data = "Player [" + user + "] is now online";
                            message = msgToSend.ToByte();
                            foreach (ClientInfo client in ClientList)
                            {
                                client.Socket.BeginSend(message, 0, message.Length, SocketFlags.None, new AsyncCallback(OnSend), client.Socket);
                            }
                            
                            // Query DB to get Player's collection and send it back to that client
                            MTGCollection collection = MTGDB.GetPlayerCollection(user);
                            if (collection.Cards.Count > 0)
                            {
                                // send the collection data for this user to his client  
                                msgToSend.OpCode = MTGNetworkPacket.MTGOpCode.ReceiveCollection;
                                msgToSend.Data = collection;
                                message = msgToSend.ToByte();
                                clientSocket.BeginSend(message, 0, message.Length, SocketFlags.None, new AsyncCallback(OnSend), clientSocket);
                            }
                        }                        

                        break;
                        
                    // *** Logout ***
                    case MTGNetworkPacket.MTGOpCode.Logout:

                        // mmb - todo
                        // save data like online field, logout time, etc

                        // send an acknowledgement logout message back to client
                        msgToSend.OpCode = MTGNetworkPacket.MTGOpCode.Logout;
                        msgToSend.Data = "1";

                        message = msgToSend.ToByte();

                        clientSocket.BeginSend(message, 0, message.Length, SocketFlags.None, new AsyncCallback(OnSendAndClose), clientSocket);


                        //Send the name of the users in the chat room... User has logged in.
                        // Send back a login packet to the user to tell them if user was validate against db
                        msgToSend.OpCode = MTGNetworkPacket.MTGOpCode.Chat;
                        
                        foreach (ClientInfo client in ClientList)
                        {
                            if (client.Socket == clientSocket)
                            {
                                User = "******"+ client.Player + "] ";
                            }
                        }
                        msgToSend.Data = "Player [" + User + "] is offline";
                        message = msgToSend.ToByte();


                        //When a user wants to log out of the server then we search for her 
                        //in the list of clients and close the corresponding connection
                        foreach (ClientInfo client in ClientList)
                        {
                            if (client.Socket == clientSocket)
                            {
                                // remove user from client list
                                ClientList.Remove(client);
                                break;
                            }
                            else
                            {
                                //Send the name of this logged out player to all the players in the chat room... 
                                client.Socket.BeginSend(message, 0, message.Length, SocketFlags.None, new AsyncCallback(OnSend), client.Socket);
                            }
                        }

                        // break the network connection with the client
                        clientSocket.Close();

                        break;
                        
                    // *** Buy ***
                    case MTGNetworkPacket.MTGOpCode.Purchase:

                        // Determine what is purchased
                        String Purchase = msgReceived.Data.ToString();
                        MTGCollection Collection = DeterminePurchases(Purchase);

                        // send back the udpated collection with the purchased items in it
                        msgToSend.OpCode = MTGNetworkPacket.MTGOpCode.PurchaseReceive;
                        msgToSend.Data = Collection;
                        message = msgToSend.ToByte();                        
                        clientSocket.BeginSend(message, 0, message.Length, SocketFlags.None, new AsyncCallback(OnSend), clientSocket);          

                        break;

                    // *** Chat ***
                    case MTGNetworkPacket.MTGOpCode.Chat:
                        
                        // First, get the string 
                        String ChatData = msgReceived.Data.ToString();

                        // now find out the player's name
                        foreach (ClientInfo client in ClientList)
                        {
                            if (client.Socket == clientSocket)
                            {
                                // this is the player, collect the name
                                User = "******" + client.Player + "] ";
                            }
                        }

                        // Check to see if this is a command
                        // examples:
                        // /who
                        // /help
                        // /commands
                        // /friends
                        if (ChatData.StartsWith("/"))
                        {
                            String Outbound = "UNKOWN";


                            switch (ChatData.Substring(1).ToUpper())
                            {
                                case "WHO":
                                    // list all the online players
                                    // mmb - TODO
                                    Outbound = "An unknown number of people are online";
                                    break;
                                default:
                                    Outbound = "Unknown Command";
                                    break;
                            }

                            // Create the outgoing chat packet
                            msgToSend.OpCode = MTGNetworkPacket.MTGOpCode.Chat;
                            msgToSend.Data = Outbound;
                            message = msgToSend.ToByte();
                            clientSocket.BeginSend(message, 0, message.Length, SocketFlags.None, new AsyncCallback(OnSend), clientSocket);
                        }
                        else
                        {
                            // This is just a normal chat message, so send it to all the other online players

                            // Create the outgoing chat packet
                            msgToSend.OpCode = MTGNetworkPacket.MTGOpCode.Chat;
                            msgToSend.Data = User + ChatData;

                            message = msgToSend.ToByte();

                            foreach (ClientInfo client in ClientList)
                            {
                                // send chat message back to other players
                                // including the player who sent it
                                client.Socket.BeginSend(message, 0, message.Length, SocketFlags.None, new AsyncCallback(OnSend), client.Socket);
                            }
                        }

                        break;

                    // *** Catchall...
                    default:
                        // record this because it shouldn't be happening
                        AddError(String.Format("OnReceive: Unknown Packet Recieved. {0}", msgReceived.OpCode));
                        break;
                }

                //If the user is logging out then we need not listen from her
                if (msgReceived.OpCode != MTGNetworkPacket.MTGOpCode.Logout)
                {
                    //Start listening to the message send by the user
                    clientSocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(OnReceive), clientSocket);
                }
            }
            catch (Exception ex)
            {
                AddError(String.Format("OnReceive: {0}", ex.Message));
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonBuyThemeDecks_Click(object sender, EventArgs e)
        {
            if (!Connected)
            {
                // error!
                LogError("Not connected to the server.  Please login again.");
            }
            else
            {
                //Fill the info for the message to be send
                MTGNetworkPacket packet = new MTGNetworkPacket();
                String data = "10E:KAMAHLSTEMPER:1";

                packet.OpCode = MTGNetworkPacket.MTGOpCode.Purchase;
                packet.Data = data;

                byte[] ConvertedData = packet.ToByte();

                //Send it to the server
                clientSocket.BeginSend(ConvertedData, 0, ConvertedData.Length, SocketFlags.None, new AsyncCallback(OnSendAndWait), null);

                LogInfo("Client is sending a PURCHASE message to server.");
                UpdateStatusStrip("Attempting to buy a Preconstructed Theme Deck...");
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="ar"></param>
        private void OnReceive(IAsyncResult ar)
        {
            Int32 size = 0;


            try
            {
                LogDebug("Client has received a message from the server.");

                if (ar.IsCompleted)
                {
                    size = clientSocket.EndReceive(ar);


                    if (size < PacketSize)
                    {
                        if (WaitingForData > 1)
                        {
                            byte[] temp = new byte[PacketSize * WaitingForData];
                            WaitingData.CopyTo(temp, 0);
                            byteData.CopyTo(temp, WaitingData.Length);
                            WaitingData = new byte[PacketSize * WaitingForData];
                            WaitingData = temp;
                        }
                        else
                        {
                            WaitingForData = 1;
                            byteData.CopyTo(WaitingData, 0);
                        }

                        MTGNetworkPacket packet = new MTGNetworkPacket(WaitingData);

                        //Accordingly process the message received
                        switch (packet.OpCode)
                        {
                            case MTGNetworkPacket.MTGOpCode.Login:
                                String result = packet.Data.ToString();
                                //AddStatus("Login: [" + result + "]");                                

                                // was login successful?
                                if (result != "0")
                                {
                                    // if so, then change login button, make edit boxes uneditable, etc
                                    SetLoginButtonText("Logout");
                                    EnableUserTextBox(false);
                                    EnablePasswordTextBox(false);

                                    LogInfo("Login successful!  Welcome to the MTG Server!");
                                    UpdateStatusStrip("Successfully Logged on to the MTG Server");

                                    // check to see if this user is an admin
                                    if (result == "2")
                                    {
                                        Admin = true;
                                    }

                                    EnableTabPages(true);
                                }
                                else
                                {
                                    // if not, then disconnect from server
                                    UpdateStatusStrip("Failed to Log on to the MTG Server");

                                    // message was successfully sent
                                    clientSocket.Close();

                                    SetLoginButtonText("Login");
                                    EnableUserTextBox(true);
                                    EnablePasswordTextBox(true);

                                    Connected = false;
                                    LogInfo("Log on has failed!  Disconnected");
                                }
                                break;

                            case MTGNetworkPacket.MTGOpCode.Logout:

                                // mmb - this won't happen!

                                LogDebug("Logout: [" + packet.Data.ToString() + "]");
                                UpdateStatusStrip("Successfully Logged off the MTG Server");

                                EnableTabPages(false);
                                Receiving = true;

                                break;

                            case MTGNetworkPacket.MTGOpCode.PurchaseReceive:
                                LogDebug("PurchaseReceive: [" + packet.Data.ToString() + "]");
                                MTGCollection NewCards = (MTGCollection)packet.Data;
                                UpdateStatusStrip("Purchase made.");
                                AddToCollection(NewCards);
                                UpdateStatusStrip("New purchase of cards have been added to your collection.");
                                break;

                            case MTGNetworkPacket.MTGOpCode.ReceiveCollection:
                                LogDebug("ReceiveCollection: [" + packet.Data.ToString() + "]");
                                Collection.Clear();
                                Collection = (MTGCollection)packet.Data;
                                UpdateStatusStrip("Player Collection has been received.");
                                break;

                            case MTGNetworkPacket.MTGOpCode.Chat:
                                Log(packet.Data.ToString());
                                break;
                        }

                        WaitingData = new byte[PacketSize];
                    }
                    else
                    {
                        // wait for more data?
                        LogDebug("OnReceive:  Waiting for more data from server...");
                                                
                        byte[] temp = new byte[PacketSize * WaitingForData];
                        WaitingData.CopyTo(temp, 0);
                        byteData.CopyTo(temp, (PacketSize * (WaitingForData - 1)));
                        WaitingData = new byte[PacketSize * WaitingForData];
                        WaitingData = temp;
                        WaitingForData++;
                    }
                }
            }
            catch (ObjectDisposedException exo)
            {
                String Error = "OnReceive:  Unable to receive. ObjectDisposed. [" + exo.Message + "]";
                //AddError(Error);
                LogError("Connection to the server was terminated.");
            }
            catch (Exception ex)
            {
                LogError("OnReceive:  Unable to receive. [" + ex.Message + "]");
            }

            if (size != 0 && Connected)
            {
                // now wait for a reply
                try
                {
                    byteData = new byte[PacketSize];
                    clientSocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(OnReceive), null);
                }
                catch (Exception ex)
                {
                    LogError("OnReceive:  Unable to begin to receive. [" + ex.Message + "]");
                }
            }
        }
        /// <summary>
        /// 
        /// </summary>
        private void SendChatMessage()
        {
            // send some chat text to the server to be sent to all the online users
            String data = String.Format(textBoxChat.Text);

            if (data != "")
            {
                //Fill the info for the message to be send
                MTGNetworkPacket packet = new MTGNetworkPacket();


                packet.OpCode = MTGNetworkPacket.MTGOpCode.Chat;
                packet.Data = data;

                byte[] ConvertedData = packet.ToByte();

                //Send it to the server
                clientSocket.BeginSend(ConvertedData, 0, ConvertedData.Length, SocketFlags.None, new AsyncCallback(OnSendAndWait), null);
                LogInfo("Client is sending a CHAT message to the server.");

                // now clear the chat text
                textBoxChat.Text = "";
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonLogin_Click(object sender, EventArgs e)
        {
            try
            {
                if (buttonLogin.Text == "Login")
                {
                    // login to server
                    SetLoginButtonText("Cancel");
                    EnableUserTextBox(false);
                    EnablePasswordTextBox(false);

                    if (!Connected)
                    {
                        UpdateStatusStrip("Connecting to the MTG Server...");
                        ConnectToServer();
                    }

                    while (!Connected)
                    {
                        // wait for the timeout... // mmb - fix this!
                    }

                    if (Connected)
                    {
                        UpdateStatusStrip("Connected to the MTG Server Successfully.");

                        //Fill the info for the message to be send
                        MTGNetworkPacket packet = new MTGNetworkPacket();
                        String data = String.Format(textBoxUser.Text + ":" + textBoxPassword.Text);

                        packet.OpCode = MTGNetworkPacket.MTGOpCode.Login;
                        packet.Data = data;

                        byte[] ConvertedData = packet.ToByte();

                        //Send it to the server
                        clientSocket.BeginSend(ConvertedData, 0, ConvertedData.Length, SocketFlags.None, new AsyncCallback(OnSendAndWait), null);
                        LogDebug("Client is sending a LOGIN message to server.");

                        UpdateStatusStrip("Logging on to the MTG Server...");
                    }
                }
                else if (buttonLogin.Text == "Cancel")
                {
                    // cancel logging into server
                    EnableUserTextBox(true);
                    EnablePasswordTextBox(true);
                }
                else if (buttonLogin.Text == "Logout")
                {
                    // log out of server
                    if (Connected)
                    {
                        //Fill the info for the message to be send
                        MTGNetworkPacket packet = new MTGNetworkPacket();

                        packet.OpCode = MTGNetworkPacket.MTGOpCode.Logout;

                        byte[] ConvertedData = packet.ToByte();

                        //Send it to the server
                        clientSocket.BeginSend(ConvertedData, 0, ConvertedData.Length, SocketFlags.None, new AsyncCallback(OnSendAndClose), null);
                        LogDebug("Client is sending a LOGOUT message to server.");

                        UpdateStatusStrip("Logging off the MTG Server...");
                    }
                }
            }
            catch (Exception ex)
            {
                LogError("buttonLogin_Click:  Unable to send message to the server. [" + ex.Message + "]");
            }  
        }