package org.bukkit.command.defaults;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.scoreboard.DisplaySlot;
import org.bukkit.scoreboard.Objective;
import org.bukkit.scoreboard.Score;
import org.bukkit.scoreboard.Scoreboard;
import org.bukkit.scoreboard.Team;
import org.bukkit.util.StringUtil;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;

public class ScoreboardCommand extends VanillaCommand {

    private static final List<String> MAIN_CHOICES = ImmutableList.of("objectives", "players", "teams");
    private static final List<String> OBJECTIVES_CHOICES = ImmutableList.of("list", "add", "remove", "setdisplay");
    private static final List<String> OBJECTIVES_CRITERIA = ImmutableList.of("health", "playerKillCount", "totalKillCount", "deathCount", "dummy");
    private static final List<String> PLAYERS_CHOICES = ImmutableList.of("set", "add", "remove", "reset", "list");
    private static final List<String> TEAMS_CHOICES = ImmutableList.of("add", "remove", "join", "leave", "empty", "list", "option");
    private static final List<String> TEAMS_OPTION_CHOICES = ImmutableList.of("color", "friendlyfire", "seeFriendlyInvisibles");
    private static final Map<String, DisplaySlot> OBJECTIVES_DISPLAYSLOT = ImmutableMap.of("belowName", DisplaySlot.BELOW_NAME, "list", DisplaySlot.PLAYER_LIST, "sidebar", DisplaySlot.SIDEBAR);
    private static final Map<String, ChatColor> TEAMS_OPTION_COLOR = ImmutableMap.<String, ChatColor>builder()
            .put("aqua", ChatColor.AQUA)
            .put("black", ChatColor.BLACK)
            .put("blue", ChatColor.BLUE)
            .put("bold", ChatColor.BOLD)
            .put("dark_aqua", ChatColor.DARK_AQUA)
            .put("dark_blue", ChatColor.DARK_BLUE)
            .put("dark_gray",  ChatColor.DARK_GRAY)
            .put("dark_green", ChatColor.DARK_GREEN)
            .put("dark_purple", ChatColor.DARK_PURPLE)
            .put("dark_red", ChatColor.DARK_RED)
            .put("gold", ChatColor.GOLD)
            .put("gray", ChatColor.GRAY)
            .put("green", ChatColor.GREEN)
            .put("italic", ChatColor.ITALIC)
            .put("light_purple", ChatColor.LIGHT_PURPLE)
            .put("obfuscated", ChatColor.MAGIC) // This is the important line
            .put("red", ChatColor.RED)
            .put("reset", ChatColor.RESET)
            .put("strikethrough", ChatColor.STRIKETHROUGH)
            .put("underline", ChatColor.UNDERLINE)
            .put("white", ChatColor.WHITE)
            .put("yellow", ChatColor.YELLOW)
            .build();
    private static final List<String> BOOLEAN = ImmutableList.of("true", "false");

    public ScoreboardCommand() {
        super("scoreboard");
        this.description = "Scoreboard control";
        this.usageMessage = "/scoreboard";
        this.setPermission("bukkit.command.scoreboard");
    }

    @Override
    public boolean execute(CommandSender sender, String currentAlias, String[] args) {
        if (!testPermission(sender))
            return true;
        if (args.length < 1 || args[0].length() == 0) {
            sender.sendMessage(ChatColor.RED + "Usage: /scoreboard <objectives|players|teams>");
            return false;
        }

        final Scoreboard mainScoreboard = Bukkit.getScoreboardManager().getMainScoreboard();

        if (args[0].equalsIgnoreCase("objectives")) {
            if (args.length == 1) {
                sender.sendMessage(ChatColor.RED + "Usage: /scoreboard objectives <list|add|remove|setdisplay>");
                return false;
            }
            if (args[1].equalsIgnoreCase("list")) {
                Set<Objective> objectives = mainScoreboard.getObjectives();
                if (objectives.isEmpty()) {
                    sender.sendMessage(ChatColor.RED + "There are no objectives on the scoreboard");
                    return false;
                }
                sender.sendMessage(ChatColor.DARK_GREEN + "Showing " + objectives.size() + " objective(s) on scoreboard");
                for (Objective objective : objectives) {
                    sender.sendMessage("- " + objective.getName() + ": displays as '" + objective.getDisplayName() + "' and is type '" + objective.getCriteria() + "'");
                }
            } else if (args[1].equalsIgnoreCase("add")) {
                if (args.length < 4) {
                    sender.sendMessage(ChatColor.RED + "/scoreboard objectives add <name> <criteriaType> [display name ...]");
                    return false;
                }
                String name = args[2];
                String criteria = args[3];

                if (criteria == null) {
                    sender.sendMessage(ChatColor.RED + "Invalid objective criteria type. Valid types are: " + stringCollectionToString(OBJECTIVES_CRITERIA));
                } else if (name.length() > 16) {
                    sender.sendMessage(ChatColor.RED + "The name '" + name + "' is too long for an objective, it can be at most 16 characters long");
                } else if (mainScoreboard.getObjective(name) != null) {
                    sender.sendMessage(ChatColor.RED + "An objective with the name '" + name + "' already exists");
                } else {
                    String displayName = null;
                    if (args.length > 4) {
                        displayName = StringUtils.join(ArrayUtils.subarray(args, 4, args.length), ' ');
                        if (displayName.length() > 32) {
                            sender.sendMessage(ChatColor.RED + "The name '" + displayName + "' is too long for an objective, it can be at most 32 characters long");
                            return false;
                        }
                    }
                    Objective objective = mainScoreboard.registerNewObjective(name, criteria);
                    if (displayName != null && displayName.length() > 0) {
                        objective.setDisplayName(displayName);
                    }
                    sender.sendMessage("Added new objective '" + name + "' successfully");
                }
            } else if (args[1].equalsIgnoreCase("remove")) {
                if (args.length != 3) {
                    sender.sendMessage(ChatColor.RED + "/scoreboard objectives remove <name>");
                    return false;
                }
                String name = args[2];
                Objective objective = mainScoreboard.getObjective(name);
                if (objective == null) {
                    sender.sendMessage(ChatColor.RED + "No objective was found by the name '" + name + "'");
                } else {
                    objective.unregister();
                    sender.sendMessage("Removed objective '" + name + "' successfully");
                }
            } else if (args[1].equalsIgnoreCase("setdisplay")) {
                if (args.length != 3 && args.length != 4) {
                    sender.sendMessage(ChatColor.RED + "/scoreboard objectives setdisplay <slot> [objective]");
                    return false;
                }
                String slotName = args[2];
                DisplaySlot slot = OBJECTIVES_DISPLAYSLOT.get(slotName);
                if (slot == null) {
                    sender.sendMessage(ChatColor.RED + "No such display slot '" + slotName + "'");
                } else {
                    if (args.length == 4) {
                        String objectiveName = args[3];
                        Objective objective = mainScoreboard.getObjective(objectiveName);
                        if (objective == null) {
                            sender.sendMessage(ChatColor.RED + "No objective was found by the name '" + objectiveName + "'");
                            return false;
                        }

                        objective.setDisplaySlot(slot);
                        sender.sendMessage("Set the display objective in slot '" + slotName + "' to '" + objective.getName() + "'");
                    } else {
                        Objective objective = mainScoreboard.getObjective(slot);
                        if (objective != null) {
                            objective.setDisplaySlot(null);
                        }
                        sender.sendMessage("Cleared objective display slot '" + slotName + "'");
                    }
                }
            }
        } else if (args[0].equalsIgnoreCase("players")) {
            if (args.length == 1) {
                sender.sendMessage(ChatColor.RED + "/scoreboard players <set|add|remove|reset|list>");
                return false;
            }
            if (args[1].equalsIgnoreCase("set") || args[1].equalsIgnoreCase("add") || args[1].equalsIgnoreCase("remove")) {
                if (args.length != 5) {
                    if (args[1].equalsIgnoreCase("set")) {
                        sender.sendMessage(ChatColor.RED + "/scoreboard players set <player> <objective> <score>");
                    } else if (args[1].equalsIgnoreCase("add")) {
                        sender.sendMessage(ChatColor.RED + "/scoreboard players add <player> <objective> <count>");
                    } else {
                        sender.sendMessage(ChatColor.RED + "/scoreboard players remove <player> <objective> <count>");
                    }
                    return false;
                }
                String objectiveName = args[3];
                Objective objective = mainScoreboard.getObjective(objectiveName);
                if (objective == null) {
                    sender.sendMessage(ChatColor.RED + "No objective was found by the name '" + objectiveName + "'");
                    return false;
                } else if (!objective.isModifiable()) {
                    sender.sendMessage(ChatColor.RED + "The objective '" + objectiveName + "' is read-only and cannot be set");
                    return false;
                }

                String valueString = args[4];
                int value;
                try {
                    value = Integer.parseInt(valueString);
                } catch (NumberFormatException e) {
                    sender.sendMessage(ChatColor.RED + "'" + valueString + "' is not a valid number");
                    return false;
                }
                if (value < 1 && !args[1].equalsIgnoreCase("set")) {
                    sender.sendMessage(ChatColor.RED + "The number you have entered (" + value + ") is too small, it must be at least 1");
                    return false;
                }

                String playerName = args[2];
                if (playerName.length() > 16) {
                    sender.sendMessage(ChatColor.RED + "'" + playerName + "' is too long for a player name");
                    return false;
                }
                Score score = objective.getScore(playerName);
                int newScore;
                if (args[1].equalsIgnoreCase("set")) {
                    newScore = value;
                } else if (args[1].equalsIgnoreCase("add")) {
                    newScore = score.getScore() + value;
                } else {
                    newScore = score.getScore() - value;
                }
                score.setScore(newScore);
                sender.sendMessage("Set score of " + objectiveName + " for player " + playerName + " to " + newScore);
            } else if (args[1].equalsIgnoreCase("reset")) {
                if (args.length != 3) {
                    sender.sendMessage(ChatColor.RED + "/scoreboard players reset <player>");
                    return false;
                }
                String playerName = args[2];
                if (playerName.length() > 16) {
                    sender.sendMessage(ChatColor.RED + "'" + playerName + "' is too long for a player name");
                    return false;
                }
                mainScoreboard.resetScores(playerName);
                sender.sendMessage("Reset all scores of player " + playerName);
            } else if (args[1].equalsIgnoreCase("list")) {
                if (args.length > 3) {
                    sender.sendMessage(ChatColor.RED + "/scoreboard players list <player>");
                    return false;
                }
                if (args.length == 2) {
                    Set<String> entries = mainScoreboard.getEntries();
                    if (entries.isEmpty()) {
                        sender.sendMessage(ChatColor.RED + "There are no tracked players on the scoreboard");
                    } else {
                        sender.sendMessage(ChatColor.DARK_GREEN + "Showing " + entries.size() + " tracked players on the scoreboard");
                        sender.sendMessage(stringCollectionToString(entries));
                    }
                } else {
                    String playerName = args[2];
                    if (playerName.length() > 16) {
                        sender.sendMessage(ChatColor.RED + "'" + playerName + "' is too long for a player name");
                        return false;
                    }
                    Set<Score> scores = mainScoreboard.getScores(playerName);
                    if (scores.isEmpty()) {
                        sender.sendMessage(ChatColor.RED + "Player " + playerName + " has no scores recorded");
                    } else {
                        sender.sendMessage(ChatColor.DARK_GREEN + "Showing " + scores.size() + " tracked objective(s) for " + playerName);
                        for (Score score : scores) {
                            sender.sendMessage("- " + score.getObjective().getDisplayName() + ": " + score.getScore() + " (" + score.getObjective().getName() + ")");
                        }
                    }
                }
            }
        } else if (args[0].equalsIgnoreCase("teams")) {
            if (args.length == 1) {
                sender.sendMessage(ChatColor.RED + "/scoreboard teams <list|add|remove|empty|join|leave|option>");
                return false;
            }
            if (args[1].equalsIgnoreCase("list")) {
                if (args.length == 2) {
                    Set<Team> teams = mainScoreboard.getTeams();
                    if (teams.isEmpty()) {
                        sender.sendMessage(ChatColor.RED + "There are no teams registered on the scoreboard");
                    } else {
                        sender.sendMessage(ChatColor.DARK_GREEN + "Showing " + teams.size() + " teams on the scoreboard");
                        for (Team team : teams) {
                            sender.sendMessage("- " + team.getName() + ": '" + team.getDisplayName() + "' has " + team.getSize() + " players");
                        }
                    }
                } else if (args.length == 3) {
                    String teamName = args[2];
                    Team team = mainScoreboard.getTeam(teamName);
                    if (team == null) {
                        sender.sendMessage(ChatColor.RED + "No team was found by the name '" + teamName + "'");
                    } else {
                        Set<OfflinePlayer> players = team.getPlayers();
                        if (players.isEmpty()) {
                            sender.sendMessage(ChatColor.RED + "Team " + team.getName() + " has no players");
                        } else {
                            sender.sendMessage(ChatColor.DARK_GREEN + "Showing " + players.size() + " player(s) in team " + team.getName());
                            sender.sendMessage(offlinePlayerSetToString(players));
                        }
                    }
                } else {
                    sender.sendMessage(ChatColor.RED + "/scoreboard teams list [name]");
                    return false;
                }
            } else if (args[1].equalsIgnoreCase("add")) {
                if (args.length < 3) {
                    sender.sendMessage(ChatColor.RED + "/scoreboard teams add <name> [display name ...]");
                    return false;
                }
                String name = args[2];
                if (name.length() > 16) {
                    sender.sendMessage(ChatColor.RED + "The name '" + name + "' is too long for a team, it can be at most 16 characters long");
                } else if (mainScoreboard.getTeam(name) != null) {
                    sender.sendMessage(ChatColor.RED + "A team with the name '" + name + "' already exists");
                } else {
                    String displayName = null;
                    if (args.length > 3) {
                        displayName = StringUtils.join(ArrayUtils.subarray(args, 3, args.length), ' ');
                        if (displayName.length() > 32) {
                            sender.sendMessage(ChatColor.RED + "The display name '" + displayName + "' is too long for a team, it can be at most 32 characters long");
                            return false;
                        }
                    }
                    Team team = mainScoreboard.registerNewTeam(name);
                    if (displayName != null && displayName.length() > 0) {
                        team.setDisplayName(displayName);
                    }
                    sender.sendMessage("Added new team '" + team.getName() + "' successfully");
                }
            } else if (args[1].equalsIgnoreCase("remove")) {
                if (args.length != 3) {
                    sender.sendMessage(ChatColor.RED + "/scoreboard teams remove <name>");
                    return false;
                }
                String name = args[2];
                Team team = mainScoreboard.getTeam(name);
                if (team == null) {
                    sender.sendMessage(ChatColor.RED + "No team was found by the name '" + name + "'");
                } else {
                    team.unregister();
                    sender.sendMessage("Removed team " + name);
                }
            } else if (args[1].equalsIgnoreCase("empty")) {
                if (args.length != 3) {
                    sender.sendMessage(ChatColor.RED + "/scoreboard teams clear <name>");
                    return false;
                }
                String name = args[2];
                Team team = mainScoreboard.getTeam(name);
                if (team == null) {
                    sender.sendMessage(ChatColor.RED + "No team was found by the name '" + name + "'");
                } else {
                    Set<OfflinePlayer> players = team.getPlayers();
                    if (players.isEmpty()) {
                        sender.sendMessage(ChatColor.RED + "Team " + team.getName() + " is already empty, cannot remove nonexistant players");
                    } else {
                        for (OfflinePlayer player : players) {
                            team.removePlayer(player);
                        }
                        sender.sendMessage("Removed all " + players.size() + " player(s) from team " + team.getName());
                    }
                }
            } else if (args[1].equalsIgnoreCase("join")) {
                if ((sender instanceof Player) ? args.length < 3 : args.length < 4) {
                    sender.sendMessage(ChatColor.RED + "/scoreboard teams join <team> [player...]");
                    return false;
                }
                String teamName = args[2];
                Team team = mainScoreboard.getTeam(teamName);
                if (team == null) {
                    sender.sendMessage(ChatColor.RED + "No team was found by the name '" + teamName + "'");
                } else {
                    Set<String> addedPlayers = new HashSet<String>();
                    if ((sender instanceof Player) && args.length == 3) {
                        team.addPlayer((Player) sender);
                        addedPlayers.add(sender.getName());
                    } else {
                        for (int i = 3; i < args.length; i++) {
                            String playerName = args[i];
                            OfflinePlayer offlinePlayer;
                            Player player = Bukkit.getPlayerExact(playerName);
                            if (player != null) {
                                offlinePlayer = player;
                            } else {
                                offlinePlayer = Bukkit.getOfflinePlayer(playerName);
                            }
                            team.addPlayer(offlinePlayer);
                            addedPlayers.add(offlinePlayer.getName());
                        }
                    }
                    sender.sendMessage("Added " + addedPlayers.size() + " player(s) to team " + team.getName() + ": " + stringCollectionToString(addedPlayers));
                }
            } else if (args[1].equalsIgnoreCase("leave")) {
                if (!(sender instanceof Player) && args.length < 3) {
                    sender.sendMessage(ChatColor.RED + "/scoreboard teams leave [player...]");
                    return false;
                }
                Set<String> left = new HashSet<String>();
                Set<String> noTeam = new HashSet<String>();
                if ((sender instanceof Player) && args.length == 2) {
                    Team team = mainScoreboard.getPlayerTeam((Player) sender);
                    if (team != null) {
                        team.removePlayer((Player) sender);
                        left.add(sender.getName());
                    } else {
                        noTeam.add(sender.getName());
                    }
                } else {
                    for (int i = 2; i < args.length; i++) {
                        String playerName = args[i];
                        OfflinePlayer offlinePlayer;
                        Player player = Bukkit.getPlayerExact(playerName);
                        if (player != null) {
                            offlinePlayer = player;
                        } else {
                            offlinePlayer = Bukkit.getOfflinePlayer(playerName);
                        }
                        Team team = mainScoreboard.getPlayerTeam(offlinePlayer);
                        if (team != null) {
                            team.removePlayer(offlinePlayer);
                            left.add(offlinePlayer.getName());
                        } else {
                            noTeam.add(offlinePlayer.getName());
                        }
                    }
                }
                if (!left.isEmpty()) {
                    sender.sendMessage("Removed " + left.size() + " player(s) from their teams: " + stringCollectionToString(left));
                }
                if (!noTeam.isEmpty()) {
                    sender.sendMessage("Could not remove " + noTeam.size() + " player(s) from their teams: " + stringCollectionToString(noTeam));
                }
            } else if (args[1].equalsIgnoreCase("option")) {
                if (args.length != 4 && args.length != 5) {
                    sender.sendMessage(ChatColor.RED + "/scoreboard teams option <team> <friendlyfire|color|seefriendlyinvisibles> <value>");
                    return false;
                }
                String teamName = args[2];
                Team team = mainScoreboard.getTeam(teamName);
                if (team == null) {
                    sender.sendMessage(ChatColor.RED + "No team was found by the name '" + teamName + "'");
                    return false;
                }
                String option = args[3].toLowerCase();
                if (!option.equals("friendlyfire") && !option.equals("color") && !option.equals("seefriendlyinvisibles")) {
                    sender.sendMessage(ChatColor.RED + "/scoreboard teams option <team> <friendlyfire|color|seefriendlyinvisibles> <value>");
                    return false;
                }
                if (args.length == 4) {
                    if (option.equals("color")) {
                        sender.sendMessage(ChatColor.RED + "Valid values for option color are: " + stringCollectionToString(TEAMS_OPTION_COLOR.keySet()));
                    } else {
                        sender.sendMessage(ChatColor.RED + "Valid values for option " + option + " are: true and false");
                    }
                } else {
                    String value = args[4].toLowerCase();
                    if (option.equals("color")) {
                        ChatColor color = TEAMS_OPTION_COLOR.get(value);
                        if (color == null) {
                            sender.sendMessage(ChatColor.RED + "Valid values for option color are: " + stringCollectionToString(TEAMS_OPTION_COLOR.keySet()));
                            return false;
                        }
                        team.setPrefix(color.toString());
                        team.setSuffix(ChatColor.RESET.toString());
                    } else {
                        if (!value.equals("true") && !value.equals("false")) {
                            sender.sendMessage(ChatColor.RED + "Valid values for option " + option + " are: true and false");
                            return false;
                        }
                        if (option.equals("friendlyfire")) {
                            team.setAllowFriendlyFire(value.equals("true"));
                        } else {
                            team.setCanSeeFriendlyInvisibles(value.equals("true"));
                        }
                    }
                    sender.sendMessage("Set option " + option + " for team " + team.getName() + " to " + value);
                }
            }
        } else {
            sender.sendMessage(ChatColor.RED + "Usage: /scoreboard <objectives|players|teams>");
            return false;
        }
        return true;
    }

    @Override
    public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
        Validate.notNull(sender, "Sender cannot be null");
        Validate.notNull(args, "Arguments cannot be null");
        Validate.notNull(alias, "Alias cannot be null");

        if (args.length == 1) {
            return StringUtil.copyPartialMatches(args[0], MAIN_CHOICES, new ArrayList<String>());
        }
        if (args.length > 1) {
            if (args[0].equalsIgnoreCase("objectives")) {
                if (args.length == 2) {
                    return StringUtil.copyPartialMatches(args[1], OBJECTIVES_CHOICES, new ArrayList<String>());
                }
                if (args[1].equalsIgnoreCase("add")) {
                    if (args.length == 4) {
                        return StringUtil.copyPartialMatches(args[3], OBJECTIVES_CRITERIA, new ArrayList<String>());
                    }
                } else if (args[1].equalsIgnoreCase("remove")) {
                    if (args.length == 3) {
                        return StringUtil.copyPartialMatches(args[2], this.getCurrentObjectives(), new ArrayList<String>());
                    }
                } else if (args[1].equalsIgnoreCase("setdisplay")) {
                    if (args.length == 3) {
                        return StringUtil.copyPartialMatches(args[2], OBJECTIVES_DISPLAYSLOT.keySet(), new ArrayList<String>());
                    }
                    if (args.length == 4) {
                        return StringUtil.copyPartialMatches(args[3], this.getCurrentObjectives(), new ArrayList<String>());
                    }
                }
            } else if (args[0].equalsIgnoreCase("players")) {
                if (args.length == 2) {
                    return StringUtil.copyPartialMatches(args[1], PLAYERS_CHOICES, new ArrayList<String>());
                }
                if (args[1].equalsIgnoreCase("set") || args[1].equalsIgnoreCase("add") || args[1].equalsIgnoreCase("remove")) {
                    if (args.length == 3) {
                        return super.tabComplete(sender, alias, args);
                    }
                    if (args.length == 4) {
                        return StringUtil.copyPartialMatches(args[3], this.getCurrentObjectives(), new ArrayList<String>());
                    }
                } else {
                    if (args.length == 3) {
                        return StringUtil.copyPartialMatches(args[2], this.getCurrentEntries(), new ArrayList<String>());
                    }
                }
            } else if (args[0].equalsIgnoreCase("teams")) {
                if (args.length == 2) {
                    return StringUtil.copyPartialMatches(args[1], TEAMS_CHOICES, new ArrayList<String>());
                }
                if (args[1].equalsIgnoreCase("join")) {
                    if (args.length == 3) {
                        return StringUtil.copyPartialMatches(args[2], this.getCurrentTeams(), new ArrayList<String>());
                    }
                    if (args.length >= 4) {
                        return super.tabComplete(sender, alias, args);
                    }
                } else if (args[1].equalsIgnoreCase("leave")) {
                    return super.tabComplete(sender, alias, args);
                } else if (args[1].equalsIgnoreCase("option")) {
                    if (args.length == 3) {
                        return StringUtil.copyPartialMatches(args[2], this.getCurrentTeams(), new ArrayList<String>());
                    }
                    if (args.length == 4) {
                        return StringUtil.copyPartialMatches(args[3], TEAMS_OPTION_CHOICES, new ArrayList<String>());
                    }
                    if (args.length == 5) {
                        if (args[3].equalsIgnoreCase("color")) {
                            return StringUtil.copyPartialMatches(args[4], TEAMS_OPTION_COLOR.keySet(), new ArrayList<String>());
                        } else {
                            return StringUtil.copyPartialMatches(args[4], BOOLEAN, new ArrayList<String>());
                        }
                    }
                } else {
                    if (args.length == 3) {
                        return StringUtil.copyPartialMatches(args[2], this.getCurrentTeams(), new ArrayList<String>());
                    }
                }
            }
        }

        return ImmutableList.of();
    }

    private static String offlinePlayerSetToString(Set<OfflinePlayer> set) {
        StringBuilder string = new StringBuilder();
        String lastValue = null;
        for (OfflinePlayer value : set) {
            string.append(lastValue = value.getName()).append(", ");
        }
        string.delete(string.length() - 2, Integer.MAX_VALUE);
        if (string.length() != lastValue.length()) {
            string.insert(string.length() - lastValue.length(), "and ");
        }
        return string.toString();

    }

    private static String stringCollectionToString(Collection<String> set) {
        StringBuilder string = new StringBuilder();
        String lastValue = null;
        for (String value : set) {
            string.append(lastValue = value).append(", ");
        }
        string.delete(string.length() - 2, Integer.MAX_VALUE);
        if (string.length() != lastValue.length()) {
            string.insert(string.length() - lastValue.length(), "and ");
        }
        return string.toString();
    }

    private List<String> getCurrentObjectives() {
        List<String> list = new ArrayList<String>();
        for (Objective objective : Bukkit.getScoreboardManager().getMainScoreboard().getObjectives()) {
            list.add(objective.getName());
        }
        Collections.sort(list, String.CASE_INSENSITIVE_ORDER);
        return list;
    }

    private List<String> getCurrentEntries() {
        List<String> list = new ArrayList<String>();
        for (String entry : Bukkit.getScoreboardManager().getMainScoreboard().getEntries()) {
            list.add(entry);
        }
        Collections.sort(list, String.CASE_INSENSITIVE_ORDER);
        return list;
    }

    private List<String> getCurrentTeams() {
        List<String> list = new ArrayList<String>();
        for (Team team : Bukkit.getScoreboardManager().getMainScoreboard().getTeams()) {
            list.add(team.getName());
        }
        Collections.sort(list, String.CASE_INSENSITIVE_ORDER);
        return list;
    }
}
