package jaci.openrio.toast.core.command;
import jaci.openrio.toast.core.Toast;
import jaci.openrio.toast.core.ToastBootstrap;
import jaci.openrio.toast.core.command.cmd.*;
import java.util.List;
import java.util.Scanner;
import java.util.Vector;
/**
* The main pipeline for commands. This bus handles registering and invocation of commands. This allows for
* robot functions to be triggered remotely, or locally, based on a message.
*
* @see jaci.openrio.toast.core.command.AbstractCommand
* @see jaci.openrio.toast.core.command.FuzzyCommand
*
* @author Jaci
*/
public class CommandBus {
public static List<AbstractCommand> commands = new Vector<>();
public static List<FuzzyCommand> parsers = new Vector<>();
/**
* Start the command bus. This is done by Toast, this shouldn't be triggered by Modules.
* This also starts the Simulation Scanner to listen from an IDE's console
*/
public static void init() {
if (ToastBootstrap.isSimulation)
setupSim();
registerNatives();
}
/**
* Register the default commands that come with Toast by default.
*/
private static void registerNatives() {
registerCommand(new CommandUSB());
registerCommand(new CommandThreadPool());
registerCommand(new CommandInvokeCrash());
registerCommand(new CommandList());
registerCommand(new CommandHelp());
registerCommand(new CommandExit());
registerCommand(new CommandProfiler());
registerCommand(new CommandReloadConfigs());
registerCommand(new CommandJScript());
registerCommand(new CommandEnvironment());
}
/**
* Parse the given message and invoke any commands matching it
*/
public static void parseMessage(String message) {
ln = message;
try {
if (messageRequested()) {
synchronized (requestLock) {
requestLock.notify();
}
return;
}
} catch (Exception e) {
Toast.log().error("Could not do Custom Message implementation -- Falling back to regular command bus");
Toast.log().exception(e);
}
new Thread() {
public void run() {
try {
this.setName("Command-Execution");
inCommand = true;
boolean commandFound = false;
String[] split = message.split(" ");
for (AbstractCommand command : commands) {
boolean alias = false;
String[] aliases = command.getAlias();
if (aliases != null) {
for (String a : aliases)
if (a.equals(split[0])) alias = true;
}
if (split[0].equals(command.getCommandName()) || alias) {
try {
String[] newSplit = new String[split.length - 1];
System.arraycopy(split, 1, newSplit, 0, split.length - 1);
command.invokeCommand(newSplit.length, newSplit, message);
} catch (UsageException e) {
Toast.log().warn(e.getMessage());
} catch (Exception e) {
Toast.log().error("Error while executing command: " + e);
Toast.log().exception(e);
}
commandFound = true;
}
}
for (FuzzyCommand command : parsers) {
if (command.shouldInvoke(message)) {
try {
command.invokeCommand(message);
} catch (UsageException e) {
Toast.log().warn(e.getMessage());
} catch (Exception e) {
Toast.log().error("Error while executing command: " + e);
Toast.log().exception(e);
}
commandFound = true;
}
}
if (!commandFound) {
Toast.log().warn("Command not found");
}
inCommand = false;
} catch (Exception e) {}
}
}.start();
}
/**
* Register a {@link jaci.openrio.toast.core.command.FuzzyCommand} on the bus
*/
public static void registerCommand(FuzzyCommand command) {
parsers.add(command);
}
/**
* Register a {@link jaci.openrio.toast.core.command.AbstractCommand} on the bus
*/
public static void registerCommand(AbstractCommand command) {
commands.add(command);
}
static boolean nextLineRequested = false;
static boolean inCommand = false;
static Scanner scanner;
static String ln;
static final Object requestLock = new Object();
static Thread t;
/**
* Will bypass the CommandBus and give the next Console line or Command Message to you. Use this
* to get data from the user. Keep in mind this is a blocking method.
*
* @throws InterruptedException Something wrong happened. This should never trigger
*/
public static String requestNextMessage() throws InterruptedException {
synchronized (requestLock) {
nextLineRequested = true;
requestLock.wait();
nextLineRequested = false;
return ln;
}
}
/**
* Returns true if the {@link #requestNextMessage} has been called
*/
public static boolean messageRequested() {
return nextLineRequested;
}
/**
* Setup the simulation environment scanner for the IDE's console
*/
private static void setupSim() {
scanner = new Scanner(System.in);
t = new Thread() {
public void run() {
Thread.currentThread().setName("Toast|Sim");
try {
while (Thread.currentThread().isAlive()) {
ln = scanner.nextLine();
parseMessage(ln);
}
} catch (Exception e) {}
};
};
t.start();
}
}