@Command(
      name = "help",
      permission = Permissions.PERMISSION_HELP,
      descref = Messages.Help.Description.HELP,
      usage = "/spleef help")
  public void onHelpCommand(CommandContext context, HeavySpleef heavySpleef)
      throws CommandException {
    CommandSender sender = context.getSender();
    if (sender instanceof Player) {
      sender = heavySpleef.getSpleefPlayer(sender);
    }

    SpleefCommandManager manager = (SpleefCommandManager) heavySpleef.getCommandManager();
    CommandManagerService service = manager.getService();

    CommandContainer container = service.getCommand(BASE_COMMAND);
    List<CommandContainer> childs = Lists.newArrayList(container.getChildCommands());
    for (Iterator<CommandContainer> iterator = childs.iterator(); iterator.hasNext(); ) {
      CommandContainer child = iterator.next();
      String permission = child.getPermission();

      if (permission.isEmpty() || sender.hasPermission(child.getPermission())) {
        continue;
      }

      iterator.remove();
    }

    Collections.sort(childs, COMPARATOR);

    int maxPage = (int) Math.ceil(childs.size() / (double) RECORDS_PER_PAGE);
    int page = 0;
    if (context.argsLength() > 0) {
      try {
        page = Integer.parseInt(context.getString(0));
      } catch (NumberFormatException nfe) {
      }

      page = Math.max(page - 1, 0);
    }

    String header =
        i18n.getVarString(Messages.Command.HELP_HEADER)
            .setVariable("page", String.valueOf(page + 1))
            .setVariable("max-pages", String.valueOf(maxPage))
            .toString();

    if (sender instanceof SpleefPlayer) {
      ((SpleefPlayer) sender).sendUnprefixedMessage(header);
    } else {
      sender.sendMessage(header);
    }

    for (int i = page * RECORDS_PER_PAGE; i < page * RECORDS_PER_PAGE + RECORDS_PER_PAGE; i++) {
      if (i >= childs.size()) {
        break;
      }

      CommandContainer child = childs.get(i);

      String desc = child.getDescription();
      if (desc.isEmpty() && !child.getDescriptionRef().isEmpty()) {
        String i18nReference = child.getI18NRef();
        I18N i18n = I18NManager.getGlobal();

        if (!i18nReference.isEmpty()) {
          i18n = heavySpleef.getI18NManager().getI18N(i18nReference);
        }

        desc = i18n.getString(child.getDescriptionRef());
      }

      String record =
          i18n.getVarString(Messages.Command.HELP_RECORD)
              .setVariable("command_fq", child.getFullyQualifiedName())
              .setVariable("command", child.getName())
              .setVariable("usage", child.getUsage())
              .setVariable("description", desc)
              .toString();

      if (sender instanceof SpleefPlayer) {
        SpleefPlayer player = (SpleefPlayer) sender;
        player.sendUnprefixedMessage(record);
      } else {
        sender.sendMessage(record);
      }
    }
  }
  @Command(
      name = "spectate",
      description = "Spectates a spleef game",
      usage = "/spleef spectate [game]",
      permission = Permissions.PERMISSION_SPECTATE)
  @PlayerOnly
  public static void onSpectateCommand(CommandContext context, HeavySpleef heavySpleef)
      throws CommandException {
    Player player = context.getSender();
    SpleefPlayer spleefPlayer = heavySpleef.getSpleefPlayer(player);
    String gameName = context.getStringSafely(0);
    final I18N i18n = I18NManager.getGlobal();

    GameManager manager = heavySpleef.getGameManager();

    Game game = null;
    FlagSpectate spectateFlag = null;

    for (Game otherGame : manager.getGames()) {
      if (!otherGame.isFlagPresent(FlagSpectate.class)) {
        continue;
      }

      FlagSpectate flag = otherGame.getFlag(FlagSpectate.class);
      if (!flag.isSpectating(spleefPlayer)) {
        continue;
      }

      game = otherGame;
      spectateFlag = flag;
      break;
    }

    if (game == null) {
      CommandValidate.isTrue(
          !gameName.isEmpty(),
          i18n.getVarString(Messages.Command.USAGE_FORMAT)
              .setVariable("usage", context.getCommand().getUsage())
              .toString());
      CommandValidate.isTrue(
          manager.hasGame(gameName),
          i18n.getVarString(Messages.Command.GAME_DOESNT_EXIST)
              .setVariable("game", gameName)
              .toString());

      game = manager.getGame(gameName);

      spectateFlag = game.getFlag(FlagSpectate.class);
      CommandValidate.notNull(spectateFlag, i18n.getString(Messages.Player.NO_SPECTATE_FLAG));
    }

    CommandValidate.isTrue(
        game.getFlag(FlagQueueLobby.class) == null || !game.isQueued(spleefPlayer),
        i18n.getString(Messages.Command.CANNOT_SPECTATE_IN_QUEUE_LOBBY));

    if (!spectateFlag.isSpectating(spleefPlayer)) {
      boolean success = spectateFlag.spectate(spleefPlayer, game);
      if (success) {
        spleefPlayer.sendMessage(
            i18n.getVarString(Messages.Player.PLAYER_SPECTATE)
                .setVariable("game", game.getName())
                .toString());
      }
    } else {
      spectateFlag.leave(spleefPlayer);
      spleefPlayer.sendMessage(
          i18n.getVarString(Messages.Player.PLAYER_LEAVE_SPECTATE)
              .setVariable("game", game.getName())
              .toString());
    }
  }