/**
   * Loads the global alias file in from the file system. If a player is running the command, send a
   * reference to them, and they will see compile errors, otherwise, null.
   *
   * @param player
   * @param settings The argument list for the settings.
   */
  public final void reload(MCPlayer player, String[] settings) {
    boolean reloadGlobals = true;
    boolean reloadTimeouts = true;
    boolean reloadExecutionQueue = true;
    boolean reloadPersistenceConfig = true;
    boolean reloadPreferences = true;
    boolean reloadProfiler = true;
    boolean reloadScripts = true;
    boolean reloadExtensions = true;

    if (settings != null) {
      ArgumentParser.ArgumentParserResults results;
      try {
        results = reloadOptions.match(settings);
      } catch (ArgumentParser.ValidationException ex) {
        Logger.getLogger(AliasCore.class.getName()).log(Level.SEVERE, null, ex);
        return;
      }
      if (results.isFlagSet('h')) {
        if (player != null) {
          player.sendMessage(reloadOptions.getBuiltDescription());
        } else {
          System.out.println(reloadOptions.getBuiltDescription());
        }
        return;
      }
      if (results.isFlagSet("whitelist")) {
        // Invert the results
        reloadGlobals = false;
        reloadTimeouts = false;
        reloadExecutionQueue = false;
        reloadPersistenceConfig = false;
        reloadPreferences = false;
        reloadProfiler = false;
        reloadScripts = false;
        reloadExtensions = false;
      }
      if (results.isFlagSet('g')) {
        reloadGlobals = !reloadGlobals;
      }
      if (results.isFlagSet('t')) {
        reloadTimeouts = !reloadTimeouts;
      }
      if (results.isFlagSet('e')) {
        reloadExecutionQueue = !reloadExecutionQueue;
      }
      if (results.isFlagSet('r') || results.isFlagSet("persistence-config")) {
        reloadPersistenceConfig = !reloadPersistenceConfig;
      }
      if (results.isFlagSet('p')) {
        reloadPreferences = !reloadPreferences;
      }
      if (results.isFlagSet('f')) {
        reloadProfiler = !reloadProfiler;
      }
      if (results.isFlagSet('s')) {
        reloadScripts = !reloadScripts;
      }
      if (results.isFlagSet('x')) {
        reloadExtensions = !reloadExtensions;
      }
    }
    try {
      if (Prefs.AllowDynamicShell()) {
        CHLog.GetLogger()
            .Log(
                CHLog.Tags.GENERAL,
                LogLevel.WARNING,
                "allow-dynamic-shell is set to true in "
                    + CommandHelperFileLocations.getDefault().getProfilerConfigFile().getName()
                    + " you should set this to false, except during development.",
                Target.UNKNOWN);
      }

      // Allow new-style extensions know we are about to reload aliases.
      ExtensionManager.PreReloadAliases(
          reloadGlobals,
          reloadTimeouts,
          reloadExecutionQueue,
          reloadPersistenceConfig,
          reloadPreferences,
          reloadProfiler,
          reloadScripts,
          reloadExtensions);

      StaticLayer.GetConvertor().runShutdownHooks();
      CHLog.initialize(MethodScriptFileLocations.getDefault().getConfigDirectory());

      // Clear out the data source cache
      DataSourceFactory.DisconnectAll();

      if (reloadExtensions) {
        ExtensionManager.Startup();
      }
      CHLog.GetLogger()
          .Log(CHLog.Tags.GENERAL, LogLevel.VERBOSE, "Scripts reloading...", Target.UNKNOWN);
      if (parent.profiler == null || reloadProfiler) {
        parent.profiler =
            new Profiler(MethodScriptFileLocations.getDefault().getProfilerConfigFile());
      }
      if (parent.persistenceNetwork == null || reloadPersistenceConfig) {
        MemoryDataSource.ClearDatabases();
        // PacketJumper.startup();
        ConnectionMixinFactory.ConnectionMixinOptions options =
            new ConnectionMixinFactory.ConnectionMixinOptions();
        options.setWorkingDirectory(MethodScriptFileLocations.getDefault().getConfigDirectory());
        parent.persistenceNetwork =
            new PersistenceNetwork(
                MethodScriptFileLocations.getDefault().getPersistenceConfig(),
                new URI(
                    "sqlite:/"
                        + MethodScriptFileLocations.getDefault()
                            .getDefaultPersistenceDBFile()
                            .getCanonicalFile()
                            .toURI()
                            .getRawSchemeSpecificPart()
                            .replace("\\", "/")),
                options);
      }
      GlobalEnv gEnv;
      try {
        gEnv =
            new GlobalEnv(
                parent.executionQueue,
                parent.profiler,
                parent.persistenceNetwork,
                parent.permissionsResolver,
                MethodScriptFileLocations.getDefault().getConfigDirectory(),
                new Profiles(MethodScriptFileLocations.getDefault().getSQLProfilesFile()));
      } catch (Profiles.InvalidProfileException ex) {
        CHLog.GetLogger().e(CHLog.Tags.GENERAL, ex.getMessage(), Target.UNKNOWN);
        return;
      }
      if (reloadExecutionQueue) {
        parent.executionQueue.stopAllNow();
      }
      CommandHelperEnvironment cEnv = new CommandHelperEnvironment();
      Environment env = Environment.createEnvironment(gEnv, cEnv);
      if (reloadGlobals) {
        Globals.clear();
      }
      if (reloadTimeouts) {
        Scheduling.ClearScheduledRunners();
      }
      if (!aliasConfig.exists()) {
        aliasConfig.getParentFile().mkdirs();
        aliasConfig.createNewFile();
        try {
          String samp_config =
              getStringResource(AliasCore.class.getResourceAsStream("/samp_config.txt"));
          // Because the sample config may have been written an a machine that isn't this type,
          // replace all
          // line endings
          samp_config = samp_config.replaceAll("\n|\r\n", System.getProperty("line.separator"));
          file_put_contents(aliasConfig, samp_config, "o");
        } catch (Exception e) {
          logger.log(Level.WARNING, "CommandHelper: Could not write sample config file");
        }
      }

      if (!mainFile.exists()) {
        mainFile.getParentFile().mkdirs();
        mainFile.createNewFile();
        try {
          String samp_main =
              getStringResource(AliasCore.class.getResourceAsStream("/samp_main.txt"));
          samp_main = samp_main.replaceAll("\n|\r\n", System.getProperty("line.separator"));
          file_put_contents(mainFile, samp_main, "o");
        } catch (Exception e) {
          logger.log(Level.WARNING, "CommandHelper: Could not write sample main file");
        }
      }

      if (!Prefs.isInitialized() || reloadPreferences) {
        Prefs.init(prefFile);
      }

      if (reloadScripts) {
        EventUtils.UnregisterAll();
        ExtensionManager.RunHooks();
        IncludeCache.clearCache(); // Clear the include cache, so it re-pulls files
        Static.getServer()
            .getMessenger()
            .closeAllChannels(); // Close all channel messager channels registered by CH.

        scripts = new ArrayList<Script>();

        LocalPackage localPackages = new LocalPackage();

        // Run the main file once
        String main = file_get_contents(mainFile.getAbsolutePath());
        localPackages.appendMS(main, mainFile);

        String alias_config =
            file_get_contents(aliasConfig.getAbsolutePath()); // get the file again
        localPackages.appendMSA(alias_config, aliasConfig);

        // Now that we've included the default files, search the local_packages directory
        GetAuxAliases(auxAliases, localPackages);

        autoIncludes = localPackages.getAutoIncludes();

        ProfilePoint compilerMS =
            parent.profiler.start("Compilation of MS files in Local Packages", LogLevel.VERBOSE);
        try {
          localPackages.compileMS(player, env);
        } finally {
          compilerMS.stop();
        }
        ProfilePoint compilerMSA =
            parent.profiler.start("Compilation of MSA files in Local Packages", LogLevel.VERBOSE);
        try {
          localPackages.compileMSA(scripts, player);
        } finally {
          compilerMSA.stop();
        }
      }
    } catch (IOException ex) {
      logger.log(
          Level.SEVERE,
          "[CommandHelper]: Path to config file is not correct/accessable. Please"
              + " check the location and try loading the plugin again.");
    } catch (Throwable t) {
      t.printStackTrace();
    }

    if (!Economy.setupEconomy()) {
      if (Prefs.DebugMode()) {
        logger.log(
            Level.WARNING,
            "[CommandHelper]: Economy could not be initialized. No further"
                + " errors will occur, unless you try to use an Economy function.");
      }
    }

    ExtensionManager.PostReloadAliases();
  }
  /**
   * This is the workhorse function. It takes a given command, then converts it into the actual
   * command(s). If the command maps to a defined alias, it will run the specified alias. It will
   * search through the global list of aliases, as well as the aliases defined for that specific
   * player. This function doesn't handle the /alias command however.
   *
   * @param command
   * @return
   */
  public boolean alias(String command, final MCCommandSender player, List<Script> playerCommands) {

    GlobalEnv gEnv;
    try {
      gEnv =
          new GlobalEnv(
              parent.executionQueue,
              parent.profiler,
              parent.persistenceNetwork,
              parent.permissionsResolver,
              MethodScriptFileLocations.getDefault().getConfigDirectory(),
              new Profiles(MethodScriptFileLocations.getDefault().getSQLProfilesFile()));
    } catch (IOException ex) {
      Logger.getLogger(AliasCore.class.getName()).log(Level.SEVERE, null, ex);
      return false;
    } catch (Profiles.InvalidProfileException ex) {
      throw ConfigRuntimeException.CreateUncatchableException(ex.getMessage(), Target.UNKNOWN);
    }
    CommandHelperEnvironment cEnv = new CommandHelperEnvironment();
    cEnv.SetCommandSender(player);
    Environment env = Environment.createEnvironment(gEnv, cEnv);

    if (player instanceof MCBlockCommandSender) {
      cEnv.SetBlockCommandSender((MCBlockCommandSender) player);
    }

    if (scripts == null) {
      throw ConfigRuntimeException.CreateUncatchableException(
          "Cannot run alias commands, no config file is loaded", Target.UNKNOWN);
    }

    boolean match = false;
    try { // catch RuntimeException
      // If player is null, we are running the test harness, so don't
      // actually add the player to the array.
      if (player != null
          && player instanceof MCPlayer
          && echoCommand.contains(((MCPlayer) player).getName())) {
        // we are running one of the expanded commands, so exit with false
        return false;
      }

      // Global aliases override personal ones, so check the list first
      for (Script s : scripts) {
        try {
          if (s.match(command)) {
            this.addPlayerReference(player);
            if (Prefs.ConsoleLogCommands() && s.doLog()) {
              StringBuilder b = new StringBuilder("CH: Running original command ");
              if (player instanceof MCPlayer) {
                b.append("on player ").append(((MCPlayer) player).getName());
              } else {
                b.append("from a MCCommandSender");
              }
              b.append(" ----> ").append(command);
              Static.getLogger().log(Level.INFO, b.toString());
            }
            try {
              env.getEnv(CommandHelperEnvironment.class).SetCommand(command);
              ProfilePoint alias =
                  env.getEnv(GlobalEnv.class)
                      .GetProfiler()
                      .start("Global Alias - \"" + command + "\"", LogLevel.ERROR);
              try {
                s.run(
                    s.getVariables(command),
                    env,
                    new MethodScriptComplete() {
                      @Override
                      public void done(String output) {
                        try {
                          if (output != null) {
                            if (!output.trim().isEmpty() && output.trim().startsWith("/")) {
                              if (Prefs.DebugMode()) {
                                if (player instanceof MCPlayer) {
                                  Static.getLogger()
                                      .log(
                                          Level.INFO,
                                          "[CommandHelper]: Executing command on "
                                              + ((MCPlayer) player).getName()
                                              + ": "
                                              + output.trim());
                                } else {
                                  Static.getLogger()
                                      .log(
                                          Level.INFO,
                                          "[CommandHelper]: Executing command from console equivalent: "
                                              + output.trim());
                                }
                              }

                              if (player instanceof MCPlayer) {
                                ((MCPlayer) player).chat(output.trim());
                              } else {
                                Static.getServer()
                                    .dispatchCommand(player, output.trim().substring(1));
                              }
                            }
                          }
                        } catch (Throwable e) {
                          System.err.println(e.getMessage());
                          player.sendMessage(MCChatColor.RED + e.getMessage());
                        } finally {
                          Static.getAliasCore().removePlayerReference(player);
                        }
                      }
                    });
              } finally {
                alias.stop();
              }
            } catch (ConfigRuntimeException ex) {
              ex.setEnv(env);
              ConfigRuntimeException.React(ex, env);
            } catch (Throwable e) {
              // This is not a simple user script error, this is a deeper problem, so we always
              // handle this.
              System.err.println(
                  "An unexpected exception occured: " + e.getClass().getSimpleName());
              player.sendMessage(
                  "An unexpected exception occured: "
                      + MCChatColor.RED
                      + e.getClass().getSimpleName());
              e.printStackTrace();
            } finally {
              Static.getAliasCore().removePlayerReference(player);
            }
            match = true;
            break;
          }
        } catch (Exception e) {
          System.err.println("An unexpected exception occured inside the command " + s.toString());
          e.printStackTrace();
        }
      }

      if (player instanceof MCPlayer) {
        if (match == false && playerCommands != null) {
          // if we are still looking, look in the aliases for this player
          for (Script ac : playerCommands) {
            // RunnableAlias b = ac.getRunnableAliases(command, player);
            try {

              ac.compile();

              if (ac.match(command)) {
                Static.getAliasCore().addPlayerReference(player);
                ProfilePoint alias =
                    env.getEnv(GlobalEnv.class)
                        .GetProfiler()
                        .start(
                            "User Alias (" + player.getName() + ") - \"" + command + "\"",
                            LogLevel.ERROR);
                try {
                  ac.run(
                      ac.getVariables(command),
                      env,
                      new MethodScriptComplete() {
                        @Override
                        public void done(String output) {
                          if (output != null) {
                            if (!output.trim().isEmpty() && output.trim().startsWith("/")) {
                              if (Prefs.DebugMode()) {
                                Static.getLogger()
                                    .log(
                                        Level.INFO,
                                        "[CommandHelper]: Executing command on "
                                            + ((MCPlayer) player).getName()
                                            + ": "
                                            + output.trim());
                              }
                              ((MCPlayer) player).chat(output.trim());
                            }
                          }
                          Static.getAliasCore().removePlayerReference(player);
                        }
                      });
                } finally {
                  alias.stop();
                }
                match = true;
                break;
              }
            } catch (ConfigRuntimeException e) {
              // Unlike system scripts, this should just report the problem to the player
              // env.getEnv(CommandHelperEnvironment.class).SetCommandSender(player);
              Static.getAliasCore().removePlayerReference(player);
              e.setEnv(env);
              ConfigRuntimeException.React(e, env);
              match = true;
            } catch (ConfigCompileException e) {
              // Something strange happened, and a bad alias was added
              // to the database. Our best course of action is to just
              // skip it.
            }
          }
        }
      }
    } catch (Throwable e) {
      // Not only did an error happen, an error happened in our error handler
      throw new InternalException(
          TermColors.RED
              + "An unexpected error occured in the CommandHelper plugin. "
              + "Further, this is likely an error with the error handler, so it may be caused by your script, "
              + "however, there is no more information at this point. Check your script, but also report this "
              + "as a bug in CommandHelper. Also, it's possible that some commands will no longer work. As a temporary "
              + "workaround, restart the server, and avoid doing whatever it is you did to make this happen.\nThe error is as follows: "
              + e.toString()
              + "\n"
              + TermColors.reset()
              + "Stack Trace:\n"
              + StringUtil.joinString(Arrays.asList(e.getStackTrace()), "\n", 0));
    }
    return match;
  }