CTCV2/app/src/main/java/cutthecord/commands/CommandHandler.java

218 lines
7.6 KiB
Java

package cutthecord.commands;
import androidx.annotation.Nullable;
import com.discord.models.domain.ModelUser;
import com.discord.stores.StoreMessages;
import com.discord.stores.StoreStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import cutthecord.commands.commands.CmdBold;
import cutthecord.commands.commands.CmdClap;
import cutthecord.commands.commands.CmdCtc;
import cutthecord.commands.commands.CmdFlip;
import cutthecord.commands.commands.CmdFullWidth;
import cutthecord.commands.commands.CmdGordon;
import cutthecord.commands.commands.CmdLenny;
import cutthecord.commands.commands.CmdLower;
import cutthecord.commands.commands.CmdMe;
import cutthecord.commands.commands.CmdMorse;
import cutthecord.commands.commands.CmdOwo;
import cutthecord.commands.commands.CmdSlap;
import cutthecord.commands.commands.CmdSmall;
import cutthecord.commands.commands.CmdSmaller;
import cutthecord.commands.commands.CmdSpoiler;
import cutthecord.commands.commands.CmdSpoilerImg;
import cutthecord.commands.commands.CmdStrikethrough;
import cutthecord.commands.commands.CmdUpper;
import lanchon.dexpatcher.annotation.DexAdd;
// Helper class for additional commands (slashcommands)
@DexAdd
public class CommandHandler {
@DexAdd
private static final HashMap<String, Command> commands = registerCommands();
@DexAdd
public abstract static class Command {
@DexAdd
private final HashMap<String, Command> subcommands = new HashMap<>();
@DexAdd
public void registerSubCommand(String subCmdName, Command command) {
subcommands.put(subCmdName, command);
}
@DexAdd
public Set<String> getSubCommandNames() {
return subcommands.keySet();
}
@DexAdd
public String process(String args) {
// Check for possible subcommands
if (!subcommands.isEmpty()) {
final String[] split = args.split(Pattern.quote(" "));
if (split.length > 0) {
final String possibleSubCmd = split[0].toLowerCase();
for (Map.Entry<String, Command> subCommand : subcommands.entrySet()) {
if (subCommand.getKey().equals(possibleSubCmd)) {
// Account for simple commands with no args
String newArgs = "";
int i = args.indexOf(" ");
if (i == -1) {
newArgs = "";
} else {
// Has args
int newSubPos = i + 1;
newArgs = args.substring(newSubPos);
}
return subCommand.getValue().process(newArgs);
}
}
}
}
// Handle command
return handleCommand(args);
}
@DexAdd
public abstract String handleCommand(String msg);
@DexAdd
@Nullable
public abstract String getPopupInfo();
}
// Like a normal command, but the output is only viewable to the sender
@DexAdd
public abstract static class PrivateCommand extends Command {
}
@DexAdd
public static HashMap<String, Command> registerCommands() {
HashMap<String, Command> cmds = new HashMap<>();
cmds.put("upper", new CmdUpper());
cmds.put("lower", new CmdLower());
cmds.put("bold", new CmdBold());
cmds.put("clap", new CmdClap());
cmds.put("flip", new CmdFlip());
cmds.put("slap", new CmdSlap());
cmds.put("fw", new CmdFullWidth());
cmds.put("gordon", new CmdGordon());
cmds.put("me", new CmdMe());
cmds.put("lenny", new CmdLenny());
cmds.put("morse", new CmdMorse());
cmds.put("owo", new CmdOwo());
cmds.put("spoiler", new CmdSpoiler());
cmds.put("spoilerimg", new CmdSpoilerImg());
cmds.put("small", new CmdSmall());
cmds.put("smaller", new CmdSmaller());
cmds.put("st", new CmdStrikethrough());
// TODO can we add an CTC user that responds for these?
Command ctcCommand = new CmdCtc();
ctcCommand.registerSubCommand("channelleak", new CmdCtc.CmdCtcChannelLeak());
ctcCommand.registerSubCommand("showtyping", new CmdCtc.CmdCtcShowTyping());
ctcCommand.registerSubCommand("token", new CmdCtc.CmdCtcToken());
ctcCommand.registerSubCommand("account", new CmdCtc.CmdCtcAccount());
ctcCommand.registerSubCommand("addaccount", new CmdCtc.CmdCtcAddAccount());
ctcCommand.registerSubCommand("nodelete", new CmdCtc.CmdCtcNoDelete());
ctcCommand.registerSubCommand("gifautoplay", new CmdCtc.CmdCtcGifAutoPlay());
cmds.put("ctc", ctcCommand);
return cmds;
}
@DexAdd
public static HashMap<String, String> getPopupInfo() {
HashMap<String, String> infoPopups = new HashMap<>(); // Static init order makes things a pain so init in here
for (Map.Entry<String, Command> command : commands.entrySet()) {
String name = command.getKey();
Command cmd = command.getValue();
infoPopups.put(name, cmd.getPopupInfo());
registerPopupInfoChildren(infoPopups, name, cmd);
}
return infoPopups;
}
@DexAdd
private static void registerPopupInfoChildren(HashMap<String, String> infoPopups, String parent, Command parentCmd) {
for (Map.Entry<String, Command> subCommand : parentCmd.subcommands.entrySet()) {
String name = parent+" "+subCommand.getKey();
infoPopups.put(name, subCommand.getValue().getPopupInfo());
registerPopupInfoChildren(infoPopups, name, subCommand.getValue());
}
}
@DexAdd
public static String slashCommands(StoreMessages storeMessages, long channelId, String str) {
String msg = str.trim();
// TODO check for edge cases like /meh parsing to /me
// TODO don't allow invalid commaands to end up in chat
// Trim off "/"
msg = msg.substring(1);
for (Map.Entry<String, Command> commandEntry : commands.entrySet()) {
if (msg.startsWith(commandEntry.getKey())) {
String newArgs = msg;
// Account for simple commands with no args
int i = msg.indexOf(" ");
if (i == -1) {
newArgs = "";
} else {
// Has args
int newSubPos = i + 1;
newArgs = msg.substring(newSubPos);
}
String output = commandEntry.getValue().process(newArgs);
if (commandEntry.getValue() instanceof PrivateCommand) {
// Show message from ctcbot
storeMessages.sendCTCBotMessageToChannel(channelId, output);
// This is naughty but discord handles it sanely
return null;
}
return output;
}
}
return str.trim();
}
@DexAdd
public static String interceptEditMessage(StoreMessages storeMessages, long channelId, String str) {
return str.startsWith("/") ? slashCommands(storeMessages, channelId, str) : str;
}
@DexAdd
public static String interceptSendMessage(StoreMessages storeMessages, long channelId, String str) {
StoreStream.getUserSettings().setImageSpoiler(false);
return str.startsWith("/") ? slashCommands(storeMessages, channelId, str) : str;
}
}