| 
						 
							
							
							
						 
					 | 
				
			
			 | 
			 | 
			
				@@ -1,27 +1,53 @@
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				package envoy.client.data.commands;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import java.util.*;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import java.util.concurrent.atomic.AtomicBoolean;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import java.util.function.Consumer;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import java.util.logging.*;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import java.util.regex.Pattern;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import java.util.stream.Collectors;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import javafx.application.Platform;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import javafx.scene.control.Alert;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import javafx.scene.control.Alert.AlertType;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import envoy.util.EnvoyLog;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				/**
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 * This class stores all {@link SystemCommand}s used.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 * Stores all {@link SystemCommand}s used.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 * SystemCommands can be called using an activator char and the text that needs
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 * to be present behind the activator.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 * Additionally offers the option to request recommendations for a partial input
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 * String.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 *
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 * @author Leon Hofmeister
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 * @since Envoy Client v0.2-beta
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				public final class SystemCommandMap {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					private final Character						activator;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					private final Map<String, SystemCommand>	systemCommands	= new HashMap<>();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					private final Pattern commandPattern = Pattern.compile("^[a-zA-Z0-9_:!\\(\\)\\?\\.\\,\\;\\-]+$");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					private final Pattern						commandPattern	= Pattern.compile("^[a-zA-Z0-9_:!/\\(\\)\\?\\.\\,\\;\\-]+$");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					private static final Logger logger = EnvoyLog.getLogger(SystemCommandMap.class);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					/**
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * Creates a new {@code SystemCommandMap} with the given char as activator.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * If this Character is null, any text used as input will be treated as a system
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * command.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 *
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @param activator the char to use as activator for commands
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @since Envoy Client v0.3-beta
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					public SystemCommandMap(Character activator) { this.activator = activator; }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					/**
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * Creates a new {@code SystemCommandMap} with '/' as activator.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 *
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @since Envoy Client v0.3-beta
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					public SystemCommandMap() { activator = '/'; }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					/**
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * Adds a new command to the map if the command name is valid.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 *
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -39,19 +65,16 @@ public final class SystemCommandMap {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					/**
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * This method checks if the input String is a key in the map and returns the
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * wrapped System command if present.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * It will return an empty optional if the value after the slash is not a key in
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * the map, which is a valid case (i.e. input="3/4" and "4" is not a key in the
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * map).
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * <p>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * Usage example:<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * {@code SystemCommandMap systemCommands = new SystemCommandMap();}<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * {@code Button button = new  Button();}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * {@code systemCommands.add("example", text -> button.setText(text.get(0), 1);}<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * {@code SystemCommandMap systemCommands = new SystemCommandMap('*');}<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * {@code systemCommands.add("example", new SystemCommand(text -> {}, 1, null,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * ""));}<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * {@code ....}<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * user input: {@code "/example xyz ..."}<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * user input: {@code "*example xyz ..."}<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * {@code systemCommands.get("example xyz ...")} or
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * {@code systemCommands.get("/example xyz ...")}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * result: {@code Optional<SystemCommand>}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * {@code systemCommands.get("*example xyz ...")}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * result: {@code Optional<SystemCommand>.get() != null}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 *
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @param input the input string given by the user
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @return the wrapped system command, if present
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -60,33 +83,36 @@ public final class SystemCommandMap {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					public Optional<SystemCommand> get(String input) { return Optional.ofNullable(systemCommands.get(getCommand(input.toLowerCase()))); }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					/**
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * This method ensures that the "/" of a {@link SystemCommand} is stripped.<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * This method ensures that the activator of a {@link SystemCommand} is
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * stripped.<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * It only checks the word beginning from the first non-blank position in the
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * input.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * It returns the command as (most likely) entered as key in the map for the
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * first word of the text.<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * It should only be called on strings that contain a "/" at position 0/-1.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * Activators in the middle of the word will be disregarded.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 *
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @param raw the input
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @return the command as entered in the map
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @since Envoy Client v0.2-beta
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @apiNote this method will (most likely) not return anything useful if
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 *          whatever is entered after the slash is not a system command. Only
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 *          exception: for recommendation purposes.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 *          whatever is entered after the activator is not a system command.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 *          Only exception: for recommendation purposes.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					public String getCommand(String raw) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						final var trimmed = raw.stripLeading();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						// Entering only a slash should not throw an error
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if (trimmed.length() == 1 && trimmed.charAt(0) == '/') return "";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						// Entering only the activator should not throw an error
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if (trimmed.length() == 1 && activator != null && activator.equals(trimmed.charAt(0))) return "";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						else {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							final var index = trimmed.indexOf(' ');
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							return trimmed.substring(trimmed.charAt(0) == '/' ? 1 : 0, index < 1 ? trimmed.length() : index);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							return trimmed.substring(activator != null && activator.equals(trimmed.charAt(0)) ? 1 : 0, index < 1 ? trimmed.length() : index);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					/**
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * Examines whether a key can be put in the map and logs it with
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * {@code Level.WARNING} if that key violates API constrictions.<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * (allowed chars are <b>a-zA-Z0-9_:!()?.,;-</b>)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * (allowed chars are <b>a-zA-Z0-9_:!/()?.,;-</b>)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * <p>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * The approach to not throw an exception was taken so that an ugly try-catch
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * block for every addition to the system commands map could be avoided, an
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -100,59 +126,86 @@ public final class SystemCommandMap {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						final var valid = commandPattern.matcher(command).matches();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if (!valid) logger.log(Level.WARNING,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								"The command \"" + command
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										+ "\" is not valid. As it will cause problems in execution, it will not be entered into the map. Only the characters "
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										+ "\" is not valid. As it might cause problems when executed, it will not be entered into the map. Only the characters "
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										+ commandPattern + "are allowed");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						return valid;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					/**
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * Takes a 'raw' string (the whole input) and checks if "/" is the first visible
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * character and then checks if a command is present after that "/". If that is
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * the case, it will be executed.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * <p>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * Takes a 'raw' string (the whole input) and checks if the activator is the
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * first visible character and then checks if a command is present after that
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * activator. If that is the case, it will be executed.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 *
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @param raw the raw input string
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @return whether a command could be found
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @return whether a command could be found and successfully executed
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @since Envoy Client v0.2-beta
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					public boolean executeIfAnyPresent(String raw) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					public boolean executeIfPresent(String raw) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						// possibly a command was detected and could be executed
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						final var	raw2			= raw.stripLeading();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						final var	commandFound	= raw2.startsWith("/") ? executeIfPresent(raw2) : false;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						final var	commandFound	= activator == null || raw2.startsWith(activator.toString()) ? executeAvailableCommand(raw2) : false;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						// the command was executed successfully - no further checking needed
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if (commandFound) logger.log(Level.FINE, "executed system command " + getCommand(raw2));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						return commandFound;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					/**
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * Retrieves the recommendations based on the current input entered.<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * The first word is used for the recommendations and
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * it does not matter if the activator is at its beginning or not.<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * If recommendations are present, the given function will be executed on the
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * recommendations.<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * Otherwise nothing will be done.<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 *
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @param input  the input string
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @param action the action that should be taken for the recommendations, if any
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 *               are present
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @since Envoy Client v0.2-beta
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					public void requestRecommendations(String input, Consumer<Set<String>> action) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						final var partialCommand = getCommand(input);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						// Get the expected commands
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						final var recommendations = recommendCommands(partialCommand);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if (recommendations.isEmpty()) return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						// Execute the given action
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						else action.accept(recommendations);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					/**
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * This method checks if the input String is a key in the map and executes the
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * wrapped System command if present.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * Its intended usage is after a "/" has been detected in the input String.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * It will do nothing if the value after the slash is not a key in
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * the map, which is a valid case (i.e. input="3/4" and "4" is not a key in the
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * map).
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * <p>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * Usage example:<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * {@code SystemCommandMap systemCommands = new SystemCommandMap();}<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * {@code SystemCommandMap systemCommands = new SystemCommandMap('*');}<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * {@code Button button = new Button();}<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * {@code systemCommands.add("example", (words)-> button.setText(words.get(0), 1);}<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * {@code systemCommands.add("example", new SystemCommand(text ->
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * {button.setText(text.get(0))}, 1, null,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * ""));}<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * {@code ....}<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * user input: {@code "/example xyz ..."}<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * {@code systemCommands.executeIfPresent("example xyz ...")}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * user input: {@code "*example xyz ..."}<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * {@code systemCommands.executeIfPresent("example xyz ...")} or
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * {@code systemCommands.executeIfPresent("*example xyz ...")}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * result: {@code button.getText()=="xyz"}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 *
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @param input the input string given by the user
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @return whether a command could be found
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @return whether a command could be found and successfully executed
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @since Envoy Client v0.2-beta
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					public boolean executeIfPresent(String input) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					private boolean executeAvailableCommand(String input) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						final var	command			= getCommand(input);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						final var	value			= get(command);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						final var	commandExecuted	= new AtomicBoolean(value.isPresent());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						value.ifPresent(systemCommand -> {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							// Splitting the String so that the leading command including the first " " is
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							// removed and only as many following words as allowed by the system command
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							// persist
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							final var arguments = extractArguments(input, systemCommand);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							// Executing the function
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							try {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								systemCommand.call(arguments);
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -161,11 +214,23 @@ public final class SystemCommandMap {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										String.format(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
												"System command %s could not be performed correctly because the user is a dumbass and could not write a parseable number.",
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
												command));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								Platform.runLater(() -> {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									final var alert = new Alert(AlertType.ERROR);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									alert.setContentText("Please enter a readable number as argument.");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									alert.showAndWait();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								});
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								commandExecuted.set(false);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							} catch (final Exception e) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								logger.log(Level.WARNING, "System command " + command + " threw an exception: ", e);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								Platform.runLater(() -> {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									final var alert = new Alert(AlertType.ERROR);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									alert.setContentText("Could not execute system command: Internal error. Please insult the responsible programmer.");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									alert.showAndWait();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								});
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								commandExecuted.set(false);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						});
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						return value.isPresent();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						return commandExecuted.get();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					/**
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -177,12 +242,15 @@ public final class SystemCommandMap {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @since Envoy Client v0.2-beta
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					private List<String> extractArguments(String input, SystemCommand systemCommand) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						// no more arguments follow after the command (e.g. text = "/DABR")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						final var indexOfSpace = input.indexOf(" ");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if (indexOfSpace < 0) return supplementDefaults(new String[] {}, systemCommand);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						// the arguments behind a system command
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						final var	remainingString		= input.substring(indexOfSpace + 1);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						final var	numberOfArguments	= systemCommand.getNumberOfArguments();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						// splitting those arguments and supplying default values
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						final var	textArguments		= remainingString.split(" ", -1);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						final var	originalArguments	= numberOfArguments >= 0 ? Arrays.copyOfRange(textArguments, 0, numberOfArguments) : textArguments;
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -190,37 +258,17 @@ public final class SystemCommandMap {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						return arguments;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					/**
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * Retrieves the recommendations based on the current input entered.<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * The first word is used for the recommendations and
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * it does not matter if the "/" is at its beginning or not.<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * If none are present, nothing will be done.<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * Otherwise the given function will be executed on the recommendations.<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 *
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @param input  the input string
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @param action the action that should be taken for the recommendations, if any
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 *               are present
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @since Envoy Client v0.2-beta
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					public void requestRecommendations(String input, Consumer<Set<String>> action) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						final var partialCommand = getCommand(input);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						// Get the expected commands
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						final var recommendations = recommendCommands(partialCommand);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if (recommendations.isEmpty()) return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						// Execute the given action
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						else action.accept(recommendations);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					/**
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * Recommends commands based upon the currently entered input.<br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * In the current implementation, all we check is whether a key contains this
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * input. This might be updated later on.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * In the current implementation, all that gets checked is whether a key
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * contains this input. This might be updated later on.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 *
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @param partialCommand the partially entered command
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @return a set of all commands that match this input
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @since Envoy Client v0.2-beta
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					private Set<String> recommendCommands(String partialCommand) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						// current implementation only looks if input is contained within a command,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						// might be updated
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						return systemCommands.keySet()
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -231,11 +279,8 @@ public final class SystemCommandMap {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					/**
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 *
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * Supplies the default values for arguments if none are present in the text for
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * any argument. <br>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * Will only work for {@code SystemCommand}s whose argument counter is bigger
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * than 1.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 *
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @param textArguments the arguments that were parsed from the text
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @param toEvaluate    the system command whose default values should be used
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -253,6 +298,7 @@ public final class SystemCommandMap {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if (toEvaluate.getNumberOfArguments() > 0) for (var index = 0; index < numberOfArguments; index++) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							String textArg = null;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							if (index < textArguments.length) textArg = textArguments[index];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							// Set the argument at position index to the current argument of the text, if it
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							// is present. Otherwise the default for that argument will be taken if present.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							// In the worst case, an empty String will be used.
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -266,4 +312,10 @@ public final class SystemCommandMap {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @since Envoy Client v0.2-beta
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					public Map<String, SystemCommand> getSystemCommands() { return systemCommands; }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					/**
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @return the activator of any command in this map. Can be null.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 * @since Envoy Client v0.3-beta
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					 */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					public Character getActivator() { return activator; }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
	
		
			
				
					
					| 
						 
							
							
							
						 
					 | 
				
			
			 | 
			 | 
			
				 
 |