/// <summary>
        /// Runs the logic for the chatbot action and records the start and stop of the action.
        /// </summary>
        /// <param name="action"></param>
        /// <param name="incommingChatMessage"></param>
        /// <param name="chatRoom"></param>
        private void RunChatbotAction(ChatbotAction action, Message incommingChatMessage, Room chatRoom)
        {
            // Record as started.
            var id = RunningChatbotActionsManager.MarkChatbotActionAsStarted(
                action.GetActionName(),
                incommingChatMessage.Author.Name,
                incommingChatMessage.Author.ID);

            try
            {
                action.RunAction(incommingChatMessage, chatRoom, roomSettings);

                // If the command was "stop bot", need to trigger a program shutdown.
                if (action is StopBot)
                {
                    if (StopBotCommandIssued != null)
                        StopBotCommandIssued(this, new EventArgs());
                }
            }
            catch (Exception ex)
            {
                // ChatMessageProcessor is responsible for outputting any errors that occur
                // while running chatbot actions. Anything outside of the RunAction() method
                // should be handled higher up.
                TellChatAboutErrorWhileRunningAction(ex, chatRoom, action);
            }

            // Mark as finished.
            RunningChatbotActionsManager.MarkChatbotActionAsFinished(id);
        }
        /// <summary>
        /// Call this method if you get an error while running a ChatbotAction.
        /// This will attempt to send a message to chat about error in a standard format.
        /// </summary>
        /// <param name="ex"></param>
        /// <param name="chatRoom"></param>
        /// <param name="actionToRun"></param>
        private void TellChatAboutErrorWhileRunningAction(Exception ex, Room chatRoom, ChatbotAction actionToRun)
        {
            var headerLine = "I hit an error while trying to run '{0}':"
                .FormatSafely(actionToRun.GetActionName());

            var errorMessage = "    " + ex.FullErrorMessage(Environment.NewLine + "    ");

            var stackTraceMessage = ex.GetAllStackTraces();

            var detailsLine = errorMessage + Environment.NewLine +
                "    ----" + Environment.NewLine +
                stackTraceMessage;

            chatRoom.PostMessageOrThrow(headerLine);
            chatRoom.PostMessageOrThrow(detailsLine);
        }
        /// <summary>
        /// Determines if the specified chat user has the correct permissions to run the chatbot action.
        /// </summary>
        /// <param name="actionToRun">The action the user would like to run.</param>
        /// <param name="chatUserId">The chat user who initiated this request.</param>
        /// <returns></returns>
        private bool DoesUserHavePermissionToRunAction(ChatbotAction actionToRun, int chatUserId)
        {
            var neededPermissionLevel = actionToRun.GetPermissionLevel();

            // If the permission level of the action is "everyone" then just return true.
            // Don't need to do anything else, like searching though the database.
            if (neededPermissionLevel == ActionPermissionLevel.Everyone)
                return true;

            // Now you need to look up the person in the database
            var userRecordInDB = da.GetRegisteredUserByChatProfileId(chatUserId);

            if (userRecordInDB == null) // At this point, the permission is Registered or Owner,
                return false;    // and if the user is not in the database at all then it can't work.

            if (neededPermissionLevel == ActionPermissionLevel.Registered)
                return true; // The user is in the list, that's all we need to check.

            if (userRecordInDB.IsOwner && neededPermissionLevel == ActionPermissionLevel.Owner)
                return true;

            // Fall past the last check (for owner), so default to "no".
            return false;
        }