/
etc/
lib/
src/Abilities/
src/Abilities/Skills/
src/Abilities/Spells/
src/Abilities/Spells/Enums/
src/Affects/
src/ArtheaConsole/
src/ArtheaConsole/Properties/
src/ArtheaGUI/Properties/
src/Clans/Enums/
src/Commands/Communication/
src/Commands/ItemCommands/
src/Connections/
src/Connections/Colors/
src/Connections/Enums/
src/Connections/Players/
src/Connections/Players/Enums/
src/Continents/
src/Continents/Areas/
src/Continents/Areas/Characters/
src/Continents/Areas/Characters/Enums/
src/Continents/Areas/Items/
src/Continents/Areas/Items/Enums/
src/Continents/Areas/Rooms/
src/Continents/Areas/Rooms/Enums/
src/Continents/Areas/Rooms/Exits/
src/Creation/
src/Creation/Attributes/
src/Creation/Interfaces/
src/Database/
src/Database/Interfaces/
src/Environment/
src/Properties/
src/Scripts/Enums/
src/Scripts/Interfaces/
#region Arthea License

/***********************************************************************
*  Arthea MUD by R. Jennings (2007)      http://arthea.googlecode.com/ *
*  By using this code you comply with the Artistic and GPLv2 Licenses. *
***********************************************************************/

#endregion

using System;
using System.Diagnostics;
using System.IO;
using System.Net.Sockets;
using System.Text;
using Arthea.Clans;
using Arthea.Classes;
using Arthea.Commands;
using Arthea.Commands.Admin;
using Arthea.Connections.Colors;
using Arthea.Connections.Enums;
using Arthea.Connections.Players;
using Arthea.Creation;
using Arthea.Environment;
using Arthea.Races;
using ICSharpCode.SharpZipLib.Zip.Compression;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;

namespace Arthea.Connections
{
    /// <summary>
    /// Implements a connection to the server
    /// </summary>
    public class Connection
    {
        #region [rgn] Fields (16)

        private StringEditor composing;
        private Olc editing;
        private ConnectionFlags flags = new ConnectionFlags();
        private bool foundCommand;
        private StringBuilder inBuf = new StringBuilder();
        private Deflater mccp;
        private StringBuilder outBuf = new StringBuilder();
        private Player player;
        private int screenHeight = 24;
        private int screenWidth = 80;
        private bool sentPrompt;
        private Socket socket;
        private ConnectionState state = ConnectionState.EnterName;
        private string systemType;
        private string terminalType;
        private int wait;

        #endregion [rgn]

        #region [rgn] Constructors (2)

        /// <summary>
        /// Initializes a new instance of the <see cref="Connection"/> class.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="info">The info.</param>
        public Connection(string name, SocketInformation info)
        {
            socket = new Socket(info);
            Player = Player.Load(name);
            State = ConnectionState.Playing;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Connection"/> class.
        /// </summary>
        /// <param name="socket">The socket.</param>
        public Connection(Socket socket)
        {
            this.socket = socket;
            OnConnect();
        }

        #endregion [rgn]

        #region [rgn] Properties (13)

        /// <summary>
        /// Gets or sets the string being composed.
        /// </summary>
        /// <value>The composing.</value>
        public StringEditor Composing
        {
            get { return composing; }
            set
            {
                if (value != null)
                {
                    composing = value;
                    WriteLine("You are new entering the text editor.  Type '/?' on a new line for help.");
                }
                else
                {
                    if (composing != null)
                    {
                        WriteLine("You stop using the text editor.");
                    }
                    composing = value;
                }
            }
        }

        /// <summary>
        /// Gets a value indicating whether this <see cref="Connection"/> is connected.
        /// </summary>
        /// <value><c>true</c> if connected; otherwise, <c>false</c>.</value>
        public bool Connected
        {
            get { return (socket != null && socket.Connected); }
        }

        /// <summary>
        /// Gets or sets the editing.
        /// </summary>
        /// <value>The editing.</value>
        public Olc Editing
        {
            get { return editing; }
            set
            {
                if (value != null)
                {
                    editing = value;
                    WriteLine("You are now entering the {0} editor.  Type '?' for help.",
                              Olc.FieldToWords(editing.GetType().Name).ToLower());
                }
                else
                {
                    if (editing != null)
                    {
                        WriteLine("You stop using the {0} editor.", Olc.FieldToWords(editing.GetType().Name).ToLower());
                    }
                    editing = value;
                }
            }
        }

        /// <summary>
        /// Gets or sets the flags
        /// </summary>
        /// <value>the connection flags</value>
        public ConnectionFlags Flags
        {
            get { return flags; }
            set { flags = value; }
        }

        /// <summary>
        /// Gets or sets the player.
        /// </summary>
        /// <value>The player.</value>
        public Player Player
        {
            get { return player; }
            set
            {
                if (player != null && value != player)
                {
                    player.Connection = null;
                }
                player = value;
                if (player != null)
                {
                    player.Connection = this;
                }
            }
        }

        /// <summary>
        /// Gets or sets the screen height
        /// </summary>
        /// <value>the screen height</value>
        public int ScreenHeight
        {
            get { return screenHeight; }
            set { screenHeight = value; }
        }

        /// <summary>
        /// Gets or sets the screen width
        /// </summary>
        /// <value>the screen width</value>
        public int ScreenWidth
        {
            get { return screenWidth; }
            set { screenWidth = value; }
        }

        /// <summary>
        /// Gets or sets a value indicating whether [prompt was sent].
        /// </summary>
        /// <value><c>true</c> if [prompt was sent]; otherwise, <c>false</c>.</value>
        public bool SentPrompt
        {
            get { return sentPrompt; }
            set { sentPrompt = value; }
        }

        /// <summary>
        /// Gets or sets the socket.
        /// </summary>
        /// <value>The socket.</value>
        public Socket Socket
        {
            get { return socket; }
            set { socket = value; }
        }

        /// <summary>
        /// Gets or sets the state.
        /// </summary>
        /// <value>The state.</value>
        public ConnectionState State
        {
            get { return state; }
            set
            {
                state = value;
                PromptConnectionState();
            }
        }

        /// <summary>
        /// Gets or sets the type of the system.
        /// </summary>
        /// <value>The type of the system.</value>
        public string SystemType
        {
            get { return systemType; }
            set { systemType = value; }
        }

        /// <summary>
        /// Gets or sets the type of the terminal.
        /// </summary>
        /// <value>The type of the terminal.</value>
        public string TerminalType
        {
            get { return terminalType; }
            set { terminalType = value; }
        }

        /// <summary>
        /// Gets or sets the wait time.
        /// </summary>
        /// <value>The wait.</value>
        public int Wait
        {
            get { return wait; }
            set { wait = value; }
        }

        #endregion [rgn]

        #region [rgn] Methods (25)

        // [rgn] Public Methods (20)

        /// <summary>
        /// Attaches this instance to applicable lists.
        /// </summary>
        public void Attach()
        {
            Lists.Connections.Add(this);
        }

        /// <summary>
        /// Determines whether this instance can error.
        /// </summary>
        /// <returns>
        /// 	<c>true</c> if this instance can error; otherwise, <c>false</c>.
        /// </returns>
        public bool CanError()
        {
            return socket.Poll(1, SelectMode.SelectError);
        }

        /// <summary>
        /// Determines whether this instance can read.
        /// </summary>
        /// <returns>
        /// 	<c>true</c> if this instance can read; otherwise, <c>false</c>.
        /// </returns>
        public bool CanRead()
        {
            return socket.Available > 0;
        }

        /// <summary>
        /// Determines whether this instance can write.
        /// </summary>
        /// <returns>
        /// 	<c>true</c> if this instance can write; otherwise, <c>false</c>.
        /// </returns>
        public bool CanWrite()
        {
            return socket.Poll(1, SelectMode.SelectWrite) &&
                   outBuf.ToString().Length > 0;
        }

        /// <summary>
        /// Closes this instance.
        /// </summary>
        public void Close()
        {
            Release();

            Socket.Close();
        }

        /// <summary>
        /// Edits the specified obj.
        /// </summary>
        /// <param name="obj">The obj.</param>
        public void Edit(object obj)
        {
            if (obj != null)
                Editing = new Olc(this, obj);
        }

        /// <summary>
        /// Determines whether this instance has input.
        /// </summary>
        /// <returns>
        /// 	<c>true</c> if this instance has input; otherwise, <c>false</c>.
        /// </returns>
        public bool HasInput()
        {
            return String.HasLine(inBuf.ToString());
        }

        /// <summary>
        /// Checks for an invalid name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <returns></returns>
        public bool InvalidName(String name)
        {
            foreach (char c in name)
            {
                if (!char.IsLetter(c))
                {
                    WriteLine("Invalid name.  Please use only letters in your name.");
                    return true;
                }
            }
            if (name.Length > 12 || name.Length < 2)
            {
                WriteLine("Invalid name.  Please choose a name between 2 and 12 characters.");
                return true;
            }

            foreach (Clan clan in Lists.Clans)
            {
                if (name == clan.Name)
                {
                    WriteLine("There is a clan with that name already.");
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// Process a connections input
        /// </summary>
        public void ProcessInput()
        {
            Debug.Assert(inBuf.Length > 0);

            String buf = inBuf.ToString();

            String line = buf.GetLine().Trim();

            inBuf = new StringBuilder(buf);

            foundCommand = true;

            try
            {
                StateHandler(line);
            }
            catch (Exception ex)
            {
                Log.Bug(ex.Message);
                Log.Error(ex.StackTrace);
            }
            finally
            {
                foundCommand = false;
            }
        }

        /// <summary>
        /// Processes the output.
        /// </summary>
        public void ProcessOutput()
        {
            if (State == ConnectionState.Playing && Player != null && !sentPrompt)
            {
                Player.DisplayPrompt();
            }

            string text = Color.Convert(outBuf.ToString(), Player);

            WriteToSocket(Globals.Encoding.GetBytes(text));

            outBuf = new StringBuilder();
        }

        /// <summary>
        /// Reads input.
        /// </summary>
        public void Read()
        {
            byte[] bytes = new byte[Socket.Available];

            int nRead = Socket.Receive(bytes);

            for (int i = 0; i < nRead; i++)
            {
                // handle delete and backspace
                if (bytes[i] == 127 || bytes[i] == Telopt.Backspace)
                {
                    if (inBuf.Length > 0)
                        inBuf.Remove(inBuf.Length - 1, 1);
                    continue;
                }
                else if (bytes[i] == Telopt.IAC)
                {
                    Telnet.Process(bytes, ref i, this);
                    continue;
                }

                char c = Convert.ToChar(bytes[i]);

                inBuf.Append(c);

                // cancel composite format characters
                switch (c)
                {
                    case '}':
                        inBuf.Append('}');
                        break;
                    case '{':
                        inBuf.Append('{');
                        break;
                }
            }
        }

        /// <summary>
        /// Releases this instance from applicable lists.
        /// </summary>
        public void Release()
        {
            Lists.Connections.Remove(this);

            if (Player != null)
            {
                Player.Release();
                Player = null;
            }
            Editing = null;
            Composing = null;
        }

        /// <summary>
        /// Returns a <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
        /// </returns>
        public override string ToString()
        {
            if (socket == null)
                return "disconnected";

            return socket.ToString();
        }

        // [rgn] Private Methods (5)

        private void Newbize()
        {
            WriteLine("Welcome to Arthea, {0}, enjoy your stay.", player.Name);
            WriteLine("Type 'help' for assistance.");
            WriteLine();

            Player.Title = string.Format("the {0} {1}.",
                                         Player.Race.ToString().ToLower(), Player.Class.ToString().ToLower());

            if (Persistance.GetDirectoryXmlFiles(Paths.PlayerDir).Length == 0)
            {
                Player.Level = Levels.Admin;
                WriteLine("You are the first connection, granting administrator privledges.");
                foreach (Command cmd in Lists.Commands.FindAdmin())
                    Player.Powers.Add(cmd);
                foreach (Powers power in Enum.GetValues(typeof (Powers)))
                    Player.Powers.Add(power);

                Log.Warn("No players, setting {0} as an admin.", Player.Name);
            }
            else
            {
                Player.Level = 1;
                WriteLine("You are now level 1.");
            }
            Player.Room = Lists.Rooms[Globals.Limbo];
            WriteLine();
        }

        /// <summary>
        /// Prefixes a new line a number of times.
        /// Positive values remains prefixing 1 line consecutivly.
        /// Negative values stop prefixing after initial prefixes.
        /// </summary>
        private void NewLinePrefix()
        {
            if (!foundCommand)
                outBuf.AppendLine();
            if (sentPrompt)
            {
                outBuf.AppendLine();
                sentPrompt = false;
            }
        }

        /// <summary>
        /// Called when [connect].
        /// </summary>
        private void OnConnect()
        {
            // Let the client request options - RJ Sep'07
            // Telnet.Advertise(this);

            if (File.Exists(Paths.GreetingFile))
            {
                WriteLine(File.ReadAllText(Paths.GreetingFile));
            }
            else
            {
                WriteLine("Welcome to...");
                Write(Server.Instance.Version);
                WriteLine(Server.Instance.About);
            }

            if (!Globals.LockDown)
            {
                Write("What is your name? ");
                Attach();
            }
            else
            {
                WriteLine("Arthea is under a lock down.  No new connections are being accepted.");
                Wait = 100;
                State = ConnectionState.Disconnected;
            }
        }

        /// <summary>
        /// Starts the connections player playing.
        /// </summary>
        private void SetPlaying()
        {
            if (Player == null)
                return;

            Lists.Characters.Add(Player);
            Lists.Players.Add(Player);
            LookCommand.Instance.Process(Player, "");
            Player.Act(null, null, Act.ToWorld, "$n has returned to Arthea.");
        }

        /// <summary>
        /// Handles the connections state.
        /// </summary>
        /// <param name="input">The input of input.</param>
        private void StateHandler(String input)
        {
            if (Composing != null)
            {
                Composing.Compose(input);
                return;
            }

            if (Editing != null && Editing.Edit(input))
            {
                return;
            }

            switch (state)
            {
                case ConnectionState.Playing:
                    HandlePlayingState(input);
                    break;
                case ConnectionState.EnterName:
                    HandleEnterName(input);
                    break;
                case ConnectionState.ConfirmNewName:
                    HandleNewName(input);
                    break;
                case ConnectionState.EnterPassword:
                    HandleEnterPassword(input);
                    break;
                case ConnectionState.ConfirmReconnect:
                    HandleConfirmReconnect(input);
                    break;
                case ConnectionState.EnterNewPassword:
                    HandleEnterNewPassword(input);
                    break;
                case ConnectionState.ConfirmNewPassword:
                    HandleConfirmNewPassword(input);
                    break;
                case ConnectionState.RollStats:
                    HandleRollStats(input);
                    break;
                case ConnectionState.GetClass:
                    HandleGetClass(input);
                    break;
                case ConnectionState.GetRace:
                    HandleGetRace(input);
                    break;
                case ConnectionState.ReadMOTD:
                    HandleReadMOTD();
                    break;
            }
        }

        #region WriteMethods

        /// <summary>
        /// Writes the specified text.
        /// </summary>
        /// <param name="text">The text.</param>
        /// <param name="args">The args.</param>
        public void Write(string text, params object[] args)
        {
            NewLinePrefix();
            outBuf.AppendFormat(text, args);
        }

        /// <summary>
        /// Writes the input.
        /// </summary>
        /// <param name="text">The text.</param>
        /// <param name="args">The args.</param>
        public void WriteLine(string text, params object[] args)
        {
            NewLinePrefix();
            outBuf.AppendFormat(text, args);
            outBuf.AppendLine();
        }

        /// <summary>
        /// Writes a input.
        /// </summary>
        public void WriteLine()
        {
            outBuf.AppendLine();
        }

        /// <summary>
        /// Writes raw bytes to the socket.
        /// </summary>
        /// <param name="text">The bytes.</param>
        public void WriteToSocket(byte[] text)
        {
#if ENABLE_COMPRESSION
            if (flags.Has(ConnectionFlags.MCCP))
            {
                Socket.Send(Compress(text));
                return;
            }
#endif
            Socket.Send(text);
        }

        #endregion

        #region Compression Methods

        /// <summary>
        /// Compresses the specified bytes.
        /// Theoretically, this implementation of MCCP
        /// should work, but I can't get it to.
        /// </summary>
        /// <param name="text">The text.</param>
        /// <returns>compressed bytes</returns>
        public byte[] Compress(byte[] text)
        {
            MemoryStream mem = new MemoryStream();
            DeflaterOutputStream s = new DeflaterOutputStream(mem,
                                                              mccp);
            s.Write(text, 0, text.Length);
            s.Finish();
            s.Flush();
            s.Close();

            return mem.ToArray();
        }

        /// <summary>
        /// Ends the compression.
        /// </summary>
        public void EndCompression()
        {
            flags.Remove(ConnectionFlags.MCCP);
            WriteLine("Compressed ratio was {0}%.", (mccp.TotalIn*100)/mccp.TotalOut);
            mccp = null;
        }

        /// <summary>
        /// Starts the compression.
        /// </summary>
        public void StartCompression()
        {
            flags.Set(ConnectionFlags.MCCP);
            mccp = new Deflater(Deflater.BEST_COMPRESSION, false);
        }

        #endregion

        #endregion [rgn]

        #region ConnectionState Handlers

        private void PromptConnectionState()
        {
            switch (state)
            {
                case ConnectionState.Playing:
                    SetPlaying();
                    break;
                case ConnectionState.ReadMOTD:
                    if (File.Exists(Paths.MOTDFile))
                    {
                        WriteLine(File.ReadAllText(Paths.MOTDFile));
                    }
                    WriteLine("[Hit enter to continue]");
                    break;
                case ConnectionState.ConfirmReconnect:
                    Write("Would to like to reconnect (Y/N)? ");
                    break;
                case ConnectionState.EnterPassword:
                    Write("Please enter your password: ");
                    WriteToSocket(Telnet.EchoOff);
                    break;
                case ConnectionState.ConfirmNewName:
                    Write("Are you sure you want to be known as {0}? ", Player.Name);
                    break;
                case ConnectionState.EnterNewPassword:
                    Write("Please enter a password: ");
                    WriteToSocket(Telnet.EchoOff);
                    break;
                case ConnectionState.EnterName:
                    Write("Ok then, what is your name? ");
                    break;
                case ConnectionState.ConfirmNewPassword:
                    Write("Enter password again: ");
                    break;
                case ConnectionState.RollStats:
                    Player.Stats.Roll();
                    WriteLine();
                    Player.WriteLine(Player.Stats);
                    WriteLine();

                    Write("Accept stats (Y/n)? ");
                    break;
                case ConnectionState.GetRace:
                    WriteLine();
                    WriteLine(Lists.Races.ToString());
                    Write("What is your race? ");
                    break;
                case ConnectionState.GetClass:
                    WriteLine();
                    WriteLine(Lists.Classes.ToString());

                    Write("What is you class? (help <class> for more info): ");
                    break;
            }
        }

        /// <summary>
        /// Handles the playing state.
        /// </summary>
        /// <param name="input">The input of input.</param>
        private void HandlePlayingState(String input)
        {
            try
            {
                Command.Interpret(Player, input);
            }
            catch (Exception ex)
            {
                Player.WriteLine("There was an error processing your command.");
                Log.Bug(ex.Message);
                Log.Error(ex.StackTrace);
            }
        }

        /// <summary>
        /// Handles entering a name.
        /// </summary>
        /// <param name="input">The input.</param>
        private void HandleEnterName(String input)
        {
            input = input.Capitalize();
            Player twin = Lists.Players.FindName(input);
            if (twin != null)
            {
                WriteLine("There is already a player named '{0}' playing.", twin.Name);
                if (twin.Connection == null)
                {
                    State = ConnectionState.ConfirmReconnect;
                }
                else
                {
                    WriteLine();
                    Write("What is your name? ");
                }
                return;
            }
            if (Persistance.XmlFileExists(Paths.PlayerDir + input))
            {
                try
                {
                    Player = Player.Load(input.ToString());
                    State = ConnectionState.EnterPassword;
                }
                catch (Exception ex)
                {
                    Log.Bug(ex.Message);
                    Log.Error(ex.StackTrace);
                    WriteLine("There was a problem loading that player file.");
                    WriteLine("Please send an email to the administrators to fix the problem.");
                    WriteLine();
                    Write("You may enter another name: ");
                    Player = null;
                }
            }
            else if (!InvalidName(input))
            {
                Player = new Player(this, input);
                State = ConnectionState.ConfirmNewName;
            }
            else
            {
                WriteLine();
                Write("Please enter another name: ");
            }
        }

        /// <summary>
        /// Handles a new name.
        /// </summary>
        /// <param name="input">The input.</param>
        private void HandleNewName(String input)
        {
            switch (char.ToUpper(input[0]))
            {
                case 'Y':
                    WriteLine("Welcome to Arthea {0}.", Player.Name);
                    State = ConnectionState.EnterNewPassword;
                    break;
                case 'N':
                    State = ConnectionState.EnterName;
                    break;
                default:
                    Write("Please enter Yes or No: ");
                    break;
            }
        }

        /// <summary>
        /// Handles entering a password.
        /// </summary>
        /// <param name="input">The input.</param>
        private void HandleEnterPassword(String input)
        {
            WriteLine();
            if (Util.Encrypt(input) == Player.Password)
            {
                Player.Connection = this;
                Log.Info("{0} has returned.", Player.Name);
                WriteToSocket(Telnet.EchoOn);
                State = ConnectionState.ReadMOTD;
            }
            else
            {
                WriteLine("Invalid password.");
                WriteLine();
                Write("Enter your password: ");
            }
        }

        /// <summary>
        /// Handles confirming a reconnect.
        /// </summary>
        /// <param name="input">The input.</param>
        private void HandleConfirmReconnect(String input)
        {
            switch (char.ToUpper(input[0]))
            {
                case 'Y':
                    State = ConnectionState.EnterPassword;
                    break;
                case 'N':
                    State = ConnectionState.EnterName;
                    Player = null;
                    break;
                default:
                    WriteLine();
                    Write("Would you like to reconnect to {0} (Y/N)?", Player.Name);
                    break;
            }
        }

        /// <summary>
        /// Handles entering a new password.
        /// </summary>
        /// <param name="input">The input.</param>
        private void HandleEnterNewPassword(String input)
        {
            if (input.Length > 12 || input.Length < 6)
            {
                WriteLine("Invalid password.  Please choose a password between 6 and 12 characters.");
                WriteLine();
                Write("Enter new password: ");
                return;
            }
            Player.Password = Util.Encrypt(input.ToString());
            State = ConnectionState.ConfirmNewPassword;
        }

        /// <summary>
        /// Handles confirming a new password.
        /// </summary>
        /// <param name="input">The input.</param>
        private void HandleConfirmNewPassword(String input)
        {
            if (Util.Encrypt(input.ToString()) == Player.Password)
            {
                Log.Info("New player '{0}' has connected.", Player.Name);

                WriteToSocket(Telnet.EchoOn);
                State = ConnectionState.RollStats;
            }
            else
            {
                WriteLine("Passwords don't match.");
                State = ConnectionState.EnterNewPassword;
            }
        }

        private void HandleRollStats(String input)
        {
            switch (char.ToUpper(input[0]))
            {
                case 'Y':
                    State = ConnectionState.GetRace;
                    break;
                case 'N':
                    State = ConnectionState.RollStats;
                    break;
                default:
                    Player.Write("Please enter (Y)es or (N)o: ");
                    break;
            }
        }

        private void HandleGetRace(String input)
        {
            Race race;

            if (input.StartsWith("help"))
            {
                input.FirstArg();

                race = Lists.Races.FindPlayerRaceName(input);

                if (race == null)
                {
                    WriteLine("That is not a race.");
                }
                else
                {
                    WriteLine(race.ToString());
                }
                Write("What is your race? ");
                return;
            }

            race = Lists.Races.FindPlayerRaceName(input);

            if (race == null)
            {
                Write("That is not a race.  What is your race? ");
                return;
            }

            Player.Race = race;

            WriteLine("You are now a {0}.", race.Name);

            State = ConnectionState.GetClass;
        }

        /// <summary>
        /// Handles the getting the players class.
        /// </summary>
        /// <param name="input">The input.</param>
        private void HandleGetClass(String input)
        {
            Class @class;

            if (input == "help")
            {
                input.FirstArg();

                @class = Lists.Classes.FindName(input);

                if (@class == null)
                {
                    WriteLine("No such class.");
                }
                else
                {
                    WriteLine(@class.ToString());
                }
                Write("What is your class? ");
                return;
            }

            @class = Lists.Classes.FindName(input);

            if (@class == null)
            {
                Write("That is not a class.  What is your class? ");
                return;
            }

            Player.Class = @class;

            WriteLine("Ok, you are a {0}.", @class.Name);
            WriteLine();

            State = ConnectionState.ReadMOTD;
        }

        /// <summary>
        /// Handles the read MOTD.
        /// </summary>
        private void HandleReadMOTD()
        {
            if (Player.Level == 0)
            {
                Newbize();
            }

            else
            {
                WriteLine("Welcome back {0}!", Player.Name);
                WriteLine();
            }
            State = ConnectionState.Playing;
        }

        #endregion
    }
}