// Broadcasts a message to every online Steam friend, including the current user
        public bool OnBroadcastCommand(JKAUserHandler sender, string arg)
        {
            if (string.IsNullOrWhiteSpace(arg))
            {
                sender.SendChatMessage("Please specify a message to broadcast.");
                return true;
            }

            int amount = 0;

            foreach (UserHandler friend in sender.Bot.GetOnlineFriends())
            {
                // always send the broadcast to the sender so he can see his own message
                if (sender.Bot.ConfigManager.ShouldReceiveMessage(sender, true) || sender.OtherSID == friend.OtherSID)
                {
                    // obviously don't count the sender in the messaged people
                    if (sender.OtherSID != friend.OtherSID)
                    {
                        ++amount;
                    }

                    friend.SendChatMessage("[{0}] {1}", sender.Bot.SteamFriends.GetFriendPersonaName(sender.OtherSID), arg);
                }
            }

            sender.SendChatMessage("Messaged {0} people.", amount);

            return true;
        }
        // Parses a command without the leading '!' and returns whether or not the command exists
        public bool OnCommand(JKAUserHandler sender, string command)
        {
            if (string.IsNullOrEmpty(command))
            {
                return false;
            }

            string args = string.Empty;
            int index = command.IndexOf(' ');

            if (index > 0)
            {
                args = command.Substring(index + 1).Trim();
                command = command.Substring(0, index).Trim();
            }

            command = command.ToLower();
            JKACommand commandCallback;

            if (!commandCallbacks.TryGetValue(command, out commandCallback))
            {
                return false;
            }

            if (commandCallback.admin && !sender.IsAdmin)
            {
                sender.SendChatMessage("You do not have permission to run this command.");
            }
            else if (!commandCallback.callback(sender, args))
            {
                sender.SendChatMessage("An error occured while running the command.");
                sender.Bot.Log.Warn("Error while running command '{0}' with args '{1}' from {2}", command, args, sender.Bot.SteamFriends.GetFriendPersonaName(sender.OtherSID));
            }

            return true;
        }
        // sends the formatted list of players online on the server
        public bool OnStatusCommand(JKAUserHandler sender, string arg)
        {
            List<JKAPlayer> players = sender.Bot.Gamestate.players.OrderBy(p => p.isBot).ThenByDescending(p => p.score).ToList();
            StringBuilder builder = new StringBuilder();

            builder.AppendLine();
            builder.AppendFormat("Map: {0}", sender.Bot.Gamestate.mapname);
            builder.AppendLine();

            if (players.Count > 0)
            {
                builder.AppendLine();
                builder.Append("score: ping: name:");

                foreach (JKAPlayer player in players)
                {
                    builder.AppendLine();
                    builder.AppendFormat("{0,-6} {1,-5} {2}", player.score, player.isBot ? "Bot" : "" + player.ping, player.name);
                }
            }
            else
            {
                builder.Append("The server is empty.");
            }

            sender.SendChatMessage(builder.ToString());

            return true;
        }
        public bool OnInviteCommand(JKAUserHandler sender, string arg)
        {
            if (string.IsNullOrWhiteSpace(arg))
            {
                sender.SendChatMessage("Please specify a Steam ID to invite.");
                return true;
            }

            SteamID id;

            if (Configuration.JsonToSteamID.Steam2Regex.IsMatch(arg))
            {
                id = new SteamID(arg);
            }
            else
            {
                ulong accountid;

                if (!ulong.TryParse(arg, out accountid))
                {
                    sender.SendChatMessage(@"Invalid Steam ID, see: https://steamid.io/lookup");
                    return true;
                }

                id = new SteamID(accountid);
            }

            sender.Bot.SteamFriends.AddFriend(id);

            return true;
        }
        // Prints commands to which the user has access to
        public bool OnHelpCommand(JKAUserHandler sender, string arg)
        {
            StringBuilder builder = new StringBuilder();

            foreach (KeyValuePair<string, JKACommand> command in commandCallbacks)
            {
                if (command.Value.admin && !sender.IsAdmin)
                {
                    continue;
                }

                builder.AppendLine();
                builder.AppendFormat("- !{0}{1}", command.Key, command.Value.description);
            }

            sender.SendChatMessage(builder.ToString());

            return true;
        }
        public bool OnConfigCommand(JKAUserHandler sender, string arg)
        {
            JKAConfig config = sender.Bot.ConfigManager.GetUserConfig(sender);

            if (string.IsNullOrWhiteSpace(arg))
            {
                sender.SendChatMessage(GetConfigSummary(config));
                return true;
            }

            List<string> args = arg.Split(' ').ToList();
            args.RemoveAll(str => string.IsNullOrWhiteSpace(str));

            if (args.Count != 4)
            {
                sender.SendChatMessage(GetConfigCommandUsage());
                return true;
            }

            bool receiveBroadcasts = "yes".Equals(args[0].ToLower());
            int playerThreshold;

            if (!int.TryParse(args[1], out playerThreshold))
            {
                sender.SendChatMessage(GetConfigCommandUsage());
                return true;
            }

            bool receiveAFK = "yes".Equals(args[2].ToLower());
            bool receiveInGame = "yes".Equals(args[3].ToLower());

            config.receiveBroadcasts = receiveBroadcasts;
            config.playerThreshold = playerThreshold;
            config.receiveAFK = receiveAFK;
            config.receiveInGame = receiveInGame;

            try
            {
                config.Save();
            }
            catch
            {
                return false;
            }

            sender.SendChatMessage(GetConfigSummary(config));

            return true;
        }