/**
  * Register an class that contains commands (denoted by {@link Command}. If no dependency injector
  * is specified, then the methods of the class will be registered to be called statically.
  * Otherwise, new instances will be created of the command classes and methods will not be called
  * statically.
  *
  * @param cls
  */
 public void register(Class<?> cls) {
   registerMethods(cls, null);
 }
  /**
   * Register the methods of a class.
   *
   * @param cls
   * @param parent
   * @param obj
   * @return
   */
  private List<Command> registerMethods(Class<?> cls, Method parent, Object obj) {
    Map<String, Method> map;
    List<Command> registered = new ArrayList<Command>();

    // Make a new hash map to cache the commands for this class
    // as looking up methods via reflection is fairly slow
    if (commands.containsKey(parent)) {
      map = commands.get(parent);
    } else {
      map = new HashMap<String, Method>();
      commands.put(parent, map);
    }

    for (Method method : cls.getMethods()) {
      if (!method.isAnnotationPresent(Command.class)) {
        continue;
      }

      boolean isStatic = Modifier.isStatic(method.getModifiers());

      Command cmd = method.getAnnotation(Command.class);

      // Cache the aliases too
      for (String alias : cmd.aliases()) {
        map.put(alias, method);
      }

      // We want to be able invoke with an instance
      if (!isStatic) {
        // Can't register this command if we don't have an instance
        if (obj == null) {
          continue;
        }

        instances.put(method, obj);
      }

      // Build a list of commands and their usage details, at least for
      // root level commands
      if (parent == null) {
        final String commandName = cmd.aliases()[0];
        final String desc = cmd.desc();

        final String usage = cmd.usage();
        if (usage.length() == 0) {
          descs.put(commandName, desc);
        } else {
          descs.put(commandName, usage + " - " + desc);
        }

        String help = cmd.help();
        if (help.length() == 0) {
          help = desc;
        }

        final CharSequence arguments = getArguments(cmd);
        for (String alias : cmd.aliases()) {
          final String helpMessage = "/" + alias + " " + arguments + "\n\n" + help;
          final String key = alias.replaceAll("/", "");
          String previous = helpMessages.put(key, helpMessage);

          if (previous != null
              && !previous
                  .replaceAll("^/[^ ]+ ", "")
                  .equals(helpMessage.replaceAll("^/[^ ]+ ", ""))) {
            helpMessages.put(key, previous + "\n\n" + helpMessage);
          }
        }
      }

      // Add the command to the registered command list for return
      registered.add(cmd);

      // Look for nested commands -- if there are any, those have
      // to be cached too so that they can be quickly looked
      // up when processing commands
      if (method.isAnnotationPresent(NestedCommand.class)) {
        NestedCommand nestedCmd = method.getAnnotation(NestedCommand.class);

        for (Class<?> nestedCls : nestedCmd.value()) {
          registerMethods(nestedCls, method);
        }
      }
    }

    if (cls.getSuperclass() != null) {
      registerMethods(cls.getSuperclass(), parent, obj);
    }

    return registered;
  }