/**
   * Given a class file (which must be of our Command interface), register that Command with Bukkit.
   *
   * @param clazz
   */
  private void registerDefaultCommand(Class<? extends Command> clazz) {
    try {
      Debug.getInstance().devDebug("registering command class ", clazz);
      Command cmd = (Command) clazz.newInstance();

      String cmdName = cmd.getCommandName();
      // do nothing if the command is disabled
      if (commandConfig.isDisabledCommand(cmdName)) {
        log.debug(
            "registerDefaultCommand() skipping ", cmdName, " because it is flagged as disabled");
        return;
      }

      register(cmd);
    } catch (Exception e) {
      log.severe(e, "error trying to load command class " + clazz);
    }
  }
  /**
   * Given a command name, look for and register that command from the admin-configured command
   * definitions.
   *
   * @param cmd
   * @param classes
   */
  private void registerConfigCommand(String cmd) {
    log.devDebug("processing config defined command ", cmd);
    Map<String, Object> cmdParams = commandConfig.getCommandParameters(cmd);

    Class<? extends Command> cmdClass = null;
    String className = null;
    Object clazz = cmdParams.get("class");

    // if no class given, just assume the name of the commmand
    if (clazz == null) clazz = cmd;

    if (clazz != null && clazz instanceof String) {
      className = (String) clazz;

      // if class given, but no package given, assume default package
      if (className.indexOf('.') == -1) {
        String firstChar = className.substring(0, 1);
        String theRest = className.substring(1);
        className = firstChar.toUpperCase() + theRest;
        cmdClass = findCommandClass(className);
      }
    }

    // if we have no commandClass yet, but we do have a className, then
    // try to find that className.
    if (cmdClass == null && className != null) {
      cmdClass = findCommandClass(className);
    }

    if (cmdClass == null) {
      log.warn("No class defined or found for command ", cmd);
      return;
    }

    try {
      Command command = (Command) cmdClass.newInstance();
      command.setCommandName(cmd.toLowerCase()); // default to name of instance key
      register(command, cmdParams);
    } catch (ClassCastException e) {
      log.warn("class " + cmdClass + " does not implement Command interface");
    } catch (Exception e) {
      log.warn(e, "error loading class " + cmdClass);
    }
  }
  /**
   * Register all known HSP commands. This includes those defined by the admin in the config file as
   * well as all commands found automatically on the command path.
   */
  public void registerAllCommands() {
    // loop through all config-defined command and load them up
    Set<String> commands = commandConfig.getDefinedCommands();
    for (String cmd : commands) {
      registerConfigCommand(cmd);
    }

    Set<Class<? extends Command>> commandClasses = getCommandClasses();
    // now loop through all normal commands in the class path
    for (Class<? extends Command> clazz : commandClasses) {
      log.devDebug("checking found class ", clazz);
      registerDefaultCommand(clazz);
    }
  }
  /**
   * Return all classes which extend our Command interface.
   *
   * @return
   */
  private Set<Class<? extends Command>> getCommandClasses() {
    if (commandClasses != null) return commandClasses;

    commandClasses = reflections.getSubTypesOf(Command.class);
    Set<Class<? extends BaseCommand>> baseCommandClasses =
        reflections.getSubTypesOf(BaseCommand.class);
    for (Class<? extends BaseCommand> bc : baseCommandClasses) {
      commandClasses.add((Class<? extends Command>) bc);
    }

    if (commandClasses == null || commandClasses.size() == 0) {
      log.severe("No command classes found, HSP will not be able to register commands!");
    }

    return commandClasses;
  }
  /**
   * Given a commandName, find the default command which matches.
   *
   * @param cmdName
   * @return
   */
  private Class<? extends Command> findDefaultCommand(String cmdName) {
    Set<Class<? extends Command>> classes = getCommandClasses();

    for (Class<? extends Command> clazz : classes) {
      try {
        Command cmd = (Command) clazz.newInstance();
        if (cmd.getCommandName().equals(cmdName)) return clazz;

        String[] aliases = cmd.getCommandAliases();
        if (aliases != null && aliases.length > 0) {
          for (String alias : aliases) {
            if (alias.equals(cmdName)) return clazz;
          }
        }
      } catch (Exception e) {
        log.severe(e, "Caught exception in findDefaultCommand for command " + cmdName);
      }
    }

    return null;
  }
  @SuppressWarnings("unchecked")
  public void register(Command command, Map<String, Object> cmdParams) {
    String cmdName = command.getCommandName();

    log.devDebug("register() command=", command, ",cmdParams=", cmdParams);
    command.setPlugin(plugin);
    command.setCommandParameters(cmdParams);

    if (cmdParams.containsKey("name")) cmdName = (String) cmdParams.get("name");

    // we never load the same command twice
    if (loadedCommands.contains(cmdName)) return;

    CraftServer cs = (CraftServer) Bukkit.getServer();
    SimpleCommandMap commandMap = cs.getCommandMap();

    try {
      Constructor<PluginCommand> constructor =
          PluginCommand.class.getDeclaredConstructor(String.class, Plugin.class);
      constructor.setAccessible(true);

      // construct a new PluginCommand object
      PluginCommand pc = constructor.newInstance(cmdName, plugin);
      pc.setExecutor(command);
      pc.setLabel(cmdName);
      if (command.getUsage() != null) pc.setUsage(command.getUsage());

      // don't set Permission node, not all permission plugins behave
      // with superperms command permissions nicely.
      //			pc.setPermission(command.getCommandPermissionNode());

      // check for aliases defined in the configuration
      Object o = cmdParams.get("aliases");
      if (o != null) {
        List<String> aliases = null;
        if (o instanceof List) {
          aliases = (List<String>) o;
        } else if (o instanceof String) {
          aliases = new ArrayList<String>(2);
          aliases.add((String) o);
        } else log.warn("invalid aliases defined for command ", cmdName, ": ", o);

        if (aliases == null) aliases = new ArrayList<String>(1);

        aliases.add("hsp" + command.getCommandName()); // all commands have "hsp" prefix alias
        pc.setAliases(aliases);
      }
      // otherwise set whatever the command has defined
      else {
        List<String> aliases = new ArrayList<String>(5);
        String[] strAliases = command.getCommandAliases();
        if (strAliases != null) {
          for (String alias : strAliases) {
            aliases.add(alias);
          }
        }
        aliases.add("hsp" + command.getCommandName()); // all commands have "hsp" prefix alias
        pc.setAliases(aliases);
      }

      // register it
      commandMap.register("hsp", pc);
      loadedCommands.add(cmdName);

      Debug.getInstance().devDebug("register() command ", command, " registered");
    } catch (Exception e) {
      e.printStackTrace();
    }
  }