001package co.aikar.commands;
002
003import co.aikar.commands.annotation.Author;
004import co.aikar.commands.annotation.CrossGuild;
005import co.aikar.commands.annotation.SelfUser;
006import net.dv8tion.jda.api.JDA;
007import net.dv8tion.jda.api.entities.ChannelType;
008import net.dv8tion.jda.api.entities.Guild;
009import net.dv8tion.jda.api.entities.Message;
010import net.dv8tion.jda.api.entities.MessageChannel;
011import net.dv8tion.jda.api.entities.Role;
012import net.dv8tion.jda.api.entities.TextChannel;
013import net.dv8tion.jda.api.entities.User;
014import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
015
016import java.util.List;
017
018// TODO: Message Keys !!!
019public class JDACommandContexts extends CommandContexts<JDACommandExecutionContext> {
020    private final JDACommandManager manager;
021    private final JDA jda;
022
023    public JDACommandContexts(JDACommandManager manager) {
024        super(manager);
025        this.manager = manager;
026        this.jda = this.manager.getJDA();
027        this.registerIssuerOnlyContext(JDACommandEvent.class, CommandExecutionContext::getIssuer);
028        this.registerIssuerOnlyContext(MessageReceivedEvent.class, c -> c.getIssuer().getIssuer());
029        this.registerIssuerOnlyContext(Message.class, c -> c.issuer.getIssuer().getMessage());
030        this.registerIssuerOnlyContext(ChannelType.class, c -> c.issuer.getIssuer().getChannelType());
031        this.registerIssuerOnlyContext(JDA.class, c -> jda);
032        this.registerIssuerOnlyContext(Guild.class, c -> {
033            MessageReceivedEvent event = c.getIssuer().getIssuer();
034            if (event.isFromType(ChannelType.PRIVATE) && !c.isOptional()) {
035                throw new InvalidCommandArgument("This command can only be executed in a Guild.", false);
036            } else {
037                return event.getGuild();
038            }
039        });
040        this.registerIssuerAwareContext(MessageChannel.class, c -> {
041            if (c.hasAnnotation(Author.class)) {
042                return c.issuer.getIssuer().getChannel();
043            }
044            boolean isCrossGuild = c.hasAnnotation(CrossGuild.class);
045            String argument = c.popFirstArg(); // we pop because we are only issuer aware if we are annotated
046            MessageChannel channel = null;
047            if (argument.startsWith("<#")) {
048                String id = argument.substring(2, argument.length() - 1);
049                channel = isCrossGuild ? jda.getTextChannelById(id) : c.issuer.getIssuer().getGuild().getTextChannelById(id);
050            } else {
051                List<TextChannel> channelList = isCrossGuild ? jda.getTextChannelsByName(argument, true) :
052                        c.issuer.getEvent().getGuild().getTextChannelsByName(argument, true);
053                if (channelList.size() > 1) {
054                    throw new InvalidCommandArgument("Too many channels were found with the given name. Try with the `#channelname` syntax.", false);
055                } else if (channelList.size() == 1) {
056                    channel = channelList.get(0);
057                }
058            }
059            if (channel == null) {
060                throw new InvalidCommandArgument("Couldn't find a channel with that name or ID.");
061            }
062            return channel;
063        });
064        this.registerIssuerAwareContext(User.class, c -> {
065            if (c.hasAnnotation(SelfUser.class)) {
066                return jda.getSelfUser();
067            }
068            String arg = c.getFirstArg();
069            if (c.isOptional() && (arg == null || arg.isEmpty())) {
070                return null;
071            }
072            arg = c.popFirstArg(); // we pop because we are only issuer aware if we are annotated
073            User user = null;
074            if (arg.startsWith("<@!")) { // for some reason a ! is added when @'ing and clicking their name.
075                user = jda.getUserById(arg.substring(3, arg.length() - 1));
076            } else if (arg.startsWith("<@")) { // users can /also/ be mentioned like this...
077                user = jda.getUserById(arg.substring(2, arg.length() - 1));
078            } else {
079                List<User> users = jda.getUsersByName(arg, true);
080                if (users.size() > 1) {
081                    throw new InvalidCommandArgument("Too many users were found with the given name. Try with the `@username#0000` syntax.", false);
082                }
083                if (!users.isEmpty()) {
084                    user = users.get(0);
085                }
086            }
087            if (user == null) {
088                throw new InvalidCommandArgument("Could not find a user with that name or ID.");
089            }
090            return user;
091        });
092        this.registerContext(Role.class, c -> {
093            boolean isCrossGuild = c.hasAnnotation(CrossGuild.class);
094            String arg = c.popFirstArg();
095            Role role = null;
096            if (arg.startsWith("<@&")) {
097                String id = arg.substring(3, arg.length() - 1);
098                role = isCrossGuild ? jda.getRoleById(id) : c.issuer.getIssuer().getGuild().getRoleById(id);
099            } else {
100                List<Role> roles = isCrossGuild ? jda.getRolesByName(arg, true)
101                        : c.issuer.getIssuer().getGuild().getRolesByName(arg, true);
102                if (roles.size() > 1) {
103                    throw new InvalidCommandArgument("Too many roles were found with the given name. Try with the `@role` syntax.", false);
104                }
105                if (!roles.isEmpty()) {
106                    role = roles.get(0);
107                }
108            }
109            if (role == null) {
110                throw new InvalidCommandArgument("Could not find a role with that name or ID.");
111            }
112            return role;
113        });
114    }
115}