/// <summary>
        /// Shuts the server down
        /// </summary>
        /// <param name="message"></param>
        public void Shutdown(string message)
        {
            Status = TcpServerStatus.ShuttingDown;
            OnTcpServerStatusChanged?.Invoke(this, new NetworkEventArgs {
                ServerStatus = Status
            });

            Parallel.ForEach(Repository.Values, user =>
            {
                var tcp = user as ITcpClientWrapper;
                tcp?.WriteToBuffer(message);
                user.Disconnect();
            });

            _listenerThread?.Abort();
            if (_tcpListener != null)
            {
                _tcpListener.Stop();
                _tcpListener = null;
            }

            Log.Info("TcpServer Shutdown.");
            Status = TcpServerStatus.Shutdown;

            OnTcpServerStatusChanged?.Invoke(this, new NetworkEventArgs {
                ServerStatus = Status
            });
        }
        private void ListenForClients()
        {
            try
            {
                _tcpListener.Start();
                Log.InfoFormat("TcpServer Listening on {0}", _tcpListener.LocalEndpoint);
                Status = TcpServerStatus.Listening;

                OnTcpServerStatusChanged?.Invoke(this, new NetworkEventArgs {
                    ServerStatus = Status
                });

                while (true)
                {
                    //// blocks until a client has connected to the server
                    if (_listenerThread.ThreadState != ThreadState.Running)
                    {
                        Log.InfoFormat("Listener Thread state {0}", _listenerThread.ThreadState);
                        break;
                    }

                    var user = new TcpUser(Log, _tcpListener.AcceptTcpClient(), Formatters);
                    user.OnConnect();
                    Repository.Add(user.Id, user);

                    OnTcpUserStatusChanged?.Invoke(user, new NetworkEventArgs {
                        SocketStatus = TcpSocketStatus.Connected
                    });

                    //// create a thread to handle communication with connected client
                    var clientThread = new Thread(HandleClientCommunication);
                    clientThread.Start(user);
                }
            }
            catch (SocketException ex)
            {
                ex.Handle(ExceptionHandlingOptions.RecordAndThrow, Log);
            }
        }
        /// <summary>
        /// Attempts to start the server on the given port and host address
        /// </summary>
        /// <param name="port"></param>
        /// <param name="host"></param>
        public void Startup(int port, IPAddress host)
        {
            if (port <= 1)
            {
                throw new ArgumentOutOfRangeException();
            }
            if (host == null)
            {
                throw new ArgumentNullException();
            }

            try
            {
                //// configure the listener thread on the pre-defined port
                Log.InfoFormat("TcpServer starting up on port {0}", port);
                Status = TcpServerStatus.Starting;
                OnTcpServerStatusChanged?.Invoke(this, new NetworkEventArgs {
                    ServerStatus = Status
                });

                Host = host;
                Port = port;

                _tcpListener    = new TcpListener(host, port);
                _listenerThread = new Thread(ListenForClients);
                _listenerThread.Start();
            }
            catch (ThreadStateException ex)
            {
                ex.Handle(ExceptionHandlingOptions.RecordAndThrow, Log);
            }
            catch (OutOfMemoryException ex)
            {
                ex.Handle(ExceptionHandlingOptions.RecordAndThrow, Log);
            }
        }