package cc.warlock.core.stormfront.script.wsl;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import cc.warlock.core.client.IProperty;
import cc.warlock.core.client.IStream;
import cc.warlock.core.client.ICharacterStatus.StatusType;
import cc.warlock.core.script.IMatch;
import cc.warlock.core.script.configuration.ScriptConfiguration;
import cc.warlock.core.script.internal.RegexMatch;
import cc.warlock.core.script.internal.TextMatch;
public class WSLScriptCommands {
private static final String argSeparator = "\\s+";
private static WSLScriptCommands instance;
private HashMap<String, IWSLCommandDefinition> wslCommands =
new HashMap<String, IWSLCommandDefinition>();
public static synchronized WSLScriptCommands instance() {
if(instance == null)
instance = new WSLScriptCommands();
return instance;
}
public static IWSLCommandDefinition getCommand(String name) {
return instance().wslCommands.get(name);
}
private WSLScriptCommands() {
// add command handlers
addCommandDefinition("counter", new WSLCommandCounter());
addCommandDefinition("deletevariable", new WSLCommandDeleteVariable());
addCommandDefinition("deletelocalvariable", new WSLCommandDeleteLocalVariable());
addCommandDefinition("debug", new WSLCommandDebug());
addCommandDefinition("delay", new WSLCommandDelay());
addCommandDefinition("echo", new WSLCommandEcho());
addCommandDefinition("else", new WSLCommandElse());
addCommandDefinition("exit", new WSLCommandExit());
addCommandDefinition("getcomponent", new WSLCommandGetComponent());
addCommandDefinition("getstatus", new WSLCommandGetStatus());
addCommandDefinition("gettime", new WSLCommandGetTime());
addCommandDefinition("gettitle", new WSLCommandGetTitle());
addCommandDefinition("getvital", new WSLCommandGetVital());
addCommandDefinition("gosub", new WSLCommandGosub());
addCommandDefinition("goto", new WSLCommandGoto());
for(int i = 0; i <= 9; i++) {
addCommandDefinition("if_" + i, new WSLCommandIf_(String.valueOf(i)));
}
addCommandDefinition("match", new WSLCommandMatch());
addCommandDefinition("matchre", new WSLCommandMatchRe());
addCommandDefinition("matchwait", new WSLCommandMatchWait());
addCommandDefinition("math", new WSLCommandMath());
addCommandDefinition("move", new WSLCommandMove());
addCommandDefinition("nextroom", new WSLCommandNextRoom());
addCommandDefinition("pause", new WSLCommandPause());
addCommandDefinition("put", new WSLCommandPut());
addCommandDefinition("playsound", new WSLCommandPlaySound());
addCommandDefinition("random", new WSLCommandRandom());
addCommandDefinition("return", new WSLCommandReturn());
addCommandDefinition("run", new WSLCommandRun());
addCommandDefinition("save", new WSLCommandSave());
addCommandDefinition("setlocalvariable", new WSLCommandSetLocalVariable());
addCommandDefinition("setvariable", new WSLCommandSetVariable());
addCommandDefinition("shift", new WSLCommandShift());
addCommandDefinition("timer", new WSLCommandTimer());
addCommandDefinition("wait", new WSLCommandWait());
addCommandDefinition("waitfor", new WSLCommandWaitFor());
addCommandDefinition("waitforre", new WSLCommandWaitForRe());
}
private void addCommandDefinition (String name, IWSLCommandDefinition command) {
wslCommands.put(name, command);
}
protected class WSLCommandSave implements IWSLCommandDefinition {
public void execute(WSLScript script, String arguments) {
script.setSpecialVariable("s", arguments);
}
}
protected class WSLCommandDebug implements IWSLCommandDefinition {
private Pattern format = Pattern.compile("(\\w+)");
public void execute(WSLScript script, String arguments) {
if (arguments == null || arguments.length() == 0) {
if(script.getDebugLevel() < 1)
script.setDebugLevel(1);
return;
}
Matcher m = format.matcher(arguments);
if (!m.matches()) {
script.scriptWarning("Invalid arguments to command \"debug\"");
return;
}
String arg = m.group(1);
if(arg.equalsIgnoreCase("on") || arg.equalsIgnoreCase("true")) {
if(script.getDebugLevel() < 1)
script.setDebugLevel(1);
} else if(arg.equalsIgnoreCase("off") || arg.equalsIgnoreCase("false")) {
script.setDebugLevel(0);
} else {
try {
int level = Integer.parseInt(arg);
script.setDebugLevel(level);
} catch(NumberFormatException e) {
script.scriptWarning("Invalid argument to command \"debug\": " + arg);
}
}
}
}
protected class WSLCommandDelay implements IWSLCommandDefinition {
public void execute(WSLScript script, String arguments) {
try {
script.setDelay(Double.parseDouble(arguments));
} catch(NumberFormatException e) {
script.scriptWarning("Invalid arguments to delay");
}
}
}
protected class WSLCommandShift implements IWSLCommandDefinition {
public void execute (WSLScript script, String arguments) {
boolean local = arguments.equalsIgnoreCase("local");
StringBuffer allArgs = new StringBuffer();
for (int i = 1; ; i++) {
String nextVar = Integer.toString(i + 1);
boolean exists = local ? script.localVariableExists(nextVar)
: script.variableExists(nextVar);
if (!exists)
{
if (local) {
script.setLocalVariable("0", allArgs.toString());
script.deleteLocalVariable(Integer.toString(i));
} else {
script.setSpecialVariable("0", allArgs.toString());
script.setSpecialVariable(Integer.toString(i), "");
}
break;
}
else
{
String arg = local ? script.getLocalVariable(nextVar).toString()
: script.getVariable(nextVar).toString();
if (arg == null)
script.scriptError("String error in arguments.");
if(allArgs.length() > 0)
allArgs.append(" ");
allArgs.append(arg);
if (local) {
script.setLocalVariable(Integer.toString(i), arg);
} else {
script.setSpecialVariable(Integer.toString(i), arg);
}
}
}
}
}
protected class WSLCommandDeleteVariable implements IWSLCommandDefinition {
public void execute (WSLScript script, String arguments) {
String name = arguments.split(argSeparator)[0];
script.deleteVariable(name);
}
}
protected class WSLCommandDeleteLocalVariable implements IWSLCommandDefinition {
public void execute (WSLScript script, String arguments) {
String name = arguments.split(argSeparator)[0];
script.deleteLocalVariable(name);
}
}
protected class WSLCommandSetVariable implements IWSLCommandDefinition {
private Pattern format = Pattern.compile("^([^\\s]+)(\\s+(.+)?)?$");
public void execute (WSLScript script, String arguments) {
Matcher m = format.matcher(arguments);
if (m.find())
{
String name = m.group(1);
String value = m.group(3);
if(value == null)
value = " ";
script.scriptDebug(1, "setVariable: " + name + "=" + value);
script.setGlobalVariable(name, value);
} else {
script.scriptWarning("Invalid arguments to setvariable");
}
}
}
protected class WSLCommandSetLocalVariable implements IWSLCommandDefinition {
private Pattern format = Pattern.compile("^([^\\s]+)(\\s+(.+)?)?$");
public void execute (WSLScript script, String arguments) {
Matcher m = format.matcher(arguments);
if (m.find())
{
String name = m.group(1);
String value = m.group(3);
if(value == null)
value = " ";
script.scriptDebug(1, "setLocalVariable: " + name + "=" + value);
script.setLocalVariable(name, value);
} else {
script.scriptError("Invalid arguments to setLocalVariable");
}
}
}
protected class WSLCommandGoto implements IWSLCommandDefinition {
public void execute (WSLScript script, String arguments) {
if(arguments.length() > 0) {
String[] args = arguments.split(argSeparator);
String label = args[0];
script.gotoLabel(label);
} else {
script.scriptError("Invalid arguments to goto");
}
}
}
protected class WSLCommandGosub implements IWSLCommandDefinition {
private Pattern format = Pattern.compile("^([^\\s]+)\\s*(.*)?$");
public void execute (WSLScript script, String arguments) {
Matcher m = format.matcher(arguments);
if (m.find()) {
script.gosub(m.group(1), m.group(2));
} else {
script.scriptError("Invalid arguments to gosub");
}
}
}
protected class WSLCommandMatchWait implements IWSLCommandDefinition {
public void execute (WSLScript script, String arguments) throws InterruptedException {
double time;
if(arguments.length() > 0) {
String[] args = arguments.split(argSeparator);
try {
time = Double.parseDouble(args[0]);
} catch(NumberFormatException e) {
script.scriptError("Non-numeral \"" + args[0] + "\" passed to matchwait");
return;
}
} else {
time = 0;
}
script.matchWait(time);
}
}
protected class WSLCommandMatchRe implements IWSLCommandDefinition {
private Pattern format = Pattern.compile("^([^\\s]+)\\s+/(.*)/(\\w*)");
public void execute (WSLScript script, String arguments) {
Matcher m = format.matcher(arguments);
if (m.find()) {
String label = m.group(1);
String regex = m.group(2);
boolean caseInsensitive = m.group(3).contains("i");
script.addMatchRe(label,
new RegexMatch(regex, caseInsensitive));
} else {
script.scriptError("Invalid arguments to matchre");
}
}
}
protected class WSLCommandMatch implements IWSLCommandDefinition {
private Pattern format = Pattern.compile("^([^\\s]+)\\s+(.*)$");
public void execute (WSLScript script, String arguments) {
Matcher m = format.matcher(arguments);
if (m.find()) {
String label = m.group(1);
String text = m.group(2);
script.addMatch(label, new TextMatch(text));
} else {
script.scriptError("Invalid arguments to match");
}
}
}
protected class WSLCommandCounter implements IWSLCommandDefinition {
public void execute (WSLScript script, String arguments) {
if (arguments.length() == 0) {
script.scriptError("You must provide an argument to counter");
return;
}
doMath(script, "c", arguments);
}
}
protected class WSLCommandMath implements IWSLCommandDefinition {
public void execute (WSLScript script, String arguments) {
String[] args = arguments.split(argSeparator, 2);
if (args.length < 2) {
script.scriptError("Not enough arguments to math");
return;
}
doMath(script, args[0], args[1]);
}
}
protected class WSLCommandWaitForRe implements IWSLCommandDefinition {
private Pattern format = Pattern.compile("^/(.*)/(\\w*)");
public void execute (WSLScript script, String arguments) throws InterruptedException {
Matcher m = format.matcher(arguments);
if (m.find()) {
String regex = m.group(1);
String flags = m.group(2);
boolean ignoreCase = flags != null && flags.contains("i");
RegexMatch match = new RegexMatch(regex, ignoreCase);
script.scriptCommands.waitFor(match);
script.setVariablesFromMatch(match);
} else {
script.scriptError("Invalid arguments to waitforre");
}
}
}
protected class WSLCommandWaitFor implements IWSLCommandDefinition {
public void execute (WSLScript script, String arguments) throws InterruptedException {
if (arguments.length() >= 1)
{
IMatch match = new TextMatch(arguments);
script.scriptCommands.waitFor(match);
} else {
script.scriptError("Invalid arguments to waitfor");
}
}
}
protected class WSLCommandWait implements IWSLCommandDefinition {
public void execute (WSLScript script, String arguments) throws InterruptedException {
script.scriptCommands.waitForPrompt();
}
}
protected class WSLCommandPut implements IWSLCommandDefinition {
public void execute(WSLScript script, String arguments) throws InterruptedException {
script.scriptCommands.put(arguments);
// Quit this script if we're starting another one
if(arguments.startsWith(ScriptConfiguration.instance().getScriptPrefix())) {
script.stop();
}
}
}
protected class WSLCommandPlaySound implements IWSLCommandDefinition {
public void execute(WSLScript script, String arguments) throws InterruptedException {
File file = new File(arguments);
if (file.exists()) {
try {
script.scriptCommands.playSound(new FileInputStream(file));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
script.scriptError("Sound file \"" + file + "\" not found.");
}
}
}
protected class WSLCommandRun implements IWSLCommandDefinition {
public void execute(WSLScript script, String arguments) throws InterruptedException {
script.getSFClient().runScript(arguments);
}
}
protected class WSLCommandEcho implements IWSLCommandDefinition {
public void execute (WSLScript script, String arguments)
{
script.scriptCommands.echo(arguments);
}
}
protected class WSLCommandPause implements IWSLCommandDefinition {
public void execute (WSLScript script, String arguments) throws InterruptedException
{
double time;
if(arguments.length() > 0) {
String[] args = arguments.split(argSeparator);
try {
time = Double.parseDouble(args[0]);
} catch(NumberFormatException e) {
script.scriptError("Non-numeral \"" + args[0] + "\" passed to pause");
return;
}
} else {
time = 1;
}
script.scriptCommands.pause(time);
}
}
protected class WSLCommandMove implements IWSLCommandDefinition {
public void execute (WSLScript script, String arguments) throws InterruptedException
{
script.scriptCommands.move(arguments);
}
}
protected class WSLCommandNextRoom implements IWSLCommandDefinition {
public void execute (WSLScript script, String arguments) throws InterruptedException
{
script.scriptCommands.waitNextRoom();
}
}
protected class WSLCommandExit implements IWSLCommandDefinition {
public void execute (WSLScript script, String arguments) {
// TODO figure out if we should make this call here or elsewhere
script.stop();
}
}
protected class WSLCommandIf_ implements IWSLCommandDefinition {
private String variableName;
public WSLCommandIf_ (String variableName) {
this.variableName = variableName;
}
public void execute (WSLScript script, String arguments) throws InterruptedException {
if (script.variableExists(variableName) &&
script.getVariable(variableName).toString().length() > 0)
script.execute(arguments);
}
}
private Pattern getFormat = Pattern.compile("^([^\\s]+)(\\s+(.*))?");
private class WSLCommandGetVital implements IWSLCommandDefinition {
public void execute(WSLScript script, String arguments) {
Matcher m = getFormat.matcher(arguments);
if(m.find()) {
String var = m.group(1);
// If we have more words after the variable, use that for the vital name
String vital = m.group(3);
if(vital == null)
vital = var;
script.setGlobalVariable(var, script.getSFClient().getVital(vital));
} else {
script.scriptError("Invalid arguments to random");
}
}
}
private class WSLCommandGetTitle implements IWSLCommandDefinition {
public void execute(WSLScript script, String arguments) {
Matcher m = getFormat.matcher(arguments);
if(m.find()) {
String var = m.group(1);
// If we have more words after the variable, use that for the stream name
String streamName = m.group(3);
if(streamName == null)
streamName = var;
IStream stream = script.getSFClient().getStream(streamName);
if(stream == null)
script.scriptWarning("Stream \"" + streamName + "\" does not exist.");
else
script.setGlobalVariable(var, stream.getFullTitle());
} else {
script.scriptError("Invalid arguments to random");
}
}
}
private class WSLCommandGetTime implements IWSLCommandDefinition {
private Pattern format = Pattern.compile("^([^\\s]+)");
public void execute(WSLScript script, String arguments) {
Matcher m = format.matcher(arguments);
if(m.find()) {
String varName = m.group(1);
script.setGlobalVariable(varName, new WSLNumber(System.currentTimeMillis() / 100));
} else {
script.scriptError("Invalid arguments to random");
}
}
}
private class WSLCommandGetStatus implements IWSLCommandDefinition {
public void execute(WSLScript script, String arguments) {
Matcher m = getFormat.matcher(arguments);
if(m.find()) {
String var = m.group(1);
// If we have more words after the variable, use that for the status name
String statusName = m.group(3);
if(statusName == null)
statusName = var;
boolean status = false;
for(Map.Entry<StatusType, Boolean> statusEntry
: script.getSFClient().getCharacterStatus().getStatus().entrySet()) {
if(statusEntry.getKey().name().equalsIgnoreCase(statusName)) {
status = statusEntry.getValue();
break;
}
}
script.setGlobalVariable(var, new WSLBoolean(status));
} else {
script.scriptError("Invalid arguments to random");
}
}
}
private class WSLCommandGetComponent implements IWSLCommandDefinition {
public void execute(WSLScript script, String arguments) {
Matcher m = getFormat.matcher(arguments);
if(m.find()) {
String var = m.group(1);
// If we have more words after the variable, use that for the vital name
String componentName = m.group(3);
if(componentName == null)
componentName = var;
IProperty<String> component = script.getSFClient().getComponent(componentName);
if(component != null)
script.setGlobalVariable(var, component.get());
else
script.scriptDebug(0, "Component (" + componentName + ") does not exist.");
} else {
script.scriptError("Invalid arguments to random");
}
}
}
private class WSLCommandRandom implements IWSLCommandDefinition {
private Pattern format = Pattern.compile("^(\\d+)\\s+(\\d+)");
public void execute(WSLScript script, String arguments) {
Matcher m = format.matcher(arguments);
if(m.find()) {
int min = Integer.parseInt(m.group(1));
int max = Integer.parseInt(m.group(2));
int r = min + new Random().nextInt(max - min + 1);
script.setSpecialVariable("r", Integer.toString(r));
} else {
script.scriptError("Invalid arguments to random");
}
}
}
private class WSLCommandTimer implements IWSLCommandDefinition {
private Pattern format = Pattern.compile("^(\\w+)(\\s+([^\\s]+))?");
public void execute(WSLScript script, String arguments) {
Matcher m = format.matcher(arguments);
if(m.find()) {
String command = m.group(1);
String timerName = m.group(3);
if(timerName == null)
timerName = "t";
IWSLValue var = script.getVariable(timerName);
if(var instanceof ScriptTimer || var == null) {
ScriptTimer timer = (ScriptTimer)var;
if(command.equals("start")) {
if(timer == null) {
timer = new ScriptTimer();
script.setSpecialVariable(timerName, timer);
}
timer.start();
} else if(command.equals("stop")) {
if(timer == null) {
script.scriptWarning("Timer \"" + timerName + "\" undefined.");
} else {
timer.stop();
}
} else if(command.equals("clear")) {
if(timer == null) {
script.scriptWarning("Timer \"" + timerName + "\" undefined.");
} else {
timer.clear();
}
} else {
script.scriptError("Invalid command \"" + command + "\" given to timer");
}
} else {
script.scriptError("Variable \"" + timerName + "\" is not a timer.");
}
} else {
script.scriptError("Invalid arguments to timer");
}
}
}
/*protected class WSLCommandAddHighlightString implements IWSLCommandDefinition {
private Pattern format = Pattern.compile("^\"([^\"])\"(\\s*(.*))?");
private Pattern optionFormat = Pattern.compile("(\\w+)=(.*)");
public void execute (WSLScript script, String arguments)
{
Matcher m = format.matcher(arguments);
if(m.find()) {
String text = m.group(1);
String optionString = m.group(3);
String[] options = optionString.split(argSeparator);
WarlockStyle style = new WarlockStyle();
for(String option : options) {
Matcher optionMatcher = optionFormat.matcher(option);
if(optionMatcher.find()) {
String key = optionMatcher.group(1);
String value = optionMatcher.group(2);
if(key.equalsIgnoreCase("forecolor")) {
}
}
}
}
}
}*/
private class WSLCommandElse implements IWSLCommandDefinition {
public void execute (WSLScript script, String arguments) throws InterruptedException {
if (!script.getLastCondition())
{
script.execute(arguments);
}
}
}
protected class WSLCommandReturn implements IWSLCommandDefinition {
public void execute (WSLScript script, String arguments) {
script.gosubReturn();
}
}
private class ScriptTimer extends WSLAbstractNumber {
private long timerStart = -1L;
private long timePast = 0L;
public double toDouble() {
if(timerStart < 0) return timePast / 1000;
return (System.currentTimeMillis() - timerStart) / 1000;
}
public void start() {
if(timerStart < 0)
timerStart = System.currentTimeMillis() - timePast;
}
public void stop() {
if(timerStart >= 0) {
timePast = timerStart - System.currentTimeMillis();
timerStart = -1L;
}
}
public void clear() {
timerStart = -1L;
timePast = 0L;
}
}
private void doMath(WSLScript script, String targetVar, String arguments) {
String[] args = arguments.split(argSeparator);
if (args.length < 1) {
script.scriptError("No operator for math");
return;
}
String operator = args[0].trim().toLowerCase();
double operand;
if (args.length > 1) {
try {
operand = Double.parseDouble(args[1].trim());
} catch (NumberFormatException e) {
script.scriptError("Operand must be a number");
return;
}
} else
operand = 1;
if ("set".equalsIgnoreCase(operator))
{
script.setGlobalVariable(targetVar, new WSLNumber(operand));
return;
}
double value;
if(script.variableExists(targetVar)) {
try {
value = script.getVariable(targetVar).toDouble();
} catch(NumberFormatException e) {
script.scriptError("The variable \"" + targetVar + "\" must be a number to do math with it");
return;
}
} else
value = 0;
if ("add".equalsIgnoreCase(operator))
{
double newValue = value + operand;
script.setGlobalVariable(targetVar, new WSLNumber(newValue));
}
else if ("subtract".equalsIgnoreCase(operator))
{
double newValue = value - operand;
script.setGlobalVariable(targetVar, new WSLNumber(newValue));
}
else if ("multiply".equalsIgnoreCase(operator))
{
double newValue = value * operand;
script.setGlobalVariable(targetVar, new WSLNumber(newValue));
}
else if ("divide".equalsIgnoreCase(operator))
{
if (operand == 0) {
script.scriptError("Cannot divide by zero");
return;
}
double newValue = value / operand;
script.setGlobalVariable(targetVar, new WSLNumber(newValue));
}
else if ("modulus".equalsIgnoreCase(operator))
{
double newValue = value % operand;
script.setGlobalVariable(targetVar, new WSLNumber(newValue));
}
else
{
script.scriptError("Unrecognized math command \"" + operator + "\"");
}
}
}