001/*
002 *     Copyright 2021 Siroshun09
003 *
004 *     Licensed under the Apache License, Version 2.0 (the "License");
005 *     you may not use this file except in compliance with the License.
006 *     You may obtain a copy of the License at
007 *
008 *         http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *     Unless required by applicable law or agreed to in writing, software
011 *     distributed under the License is distributed on an "AS IS" BASIS,
012 *     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *     See the License for the specific language governing permissions and
014 *     limitations under the License.
015 */
016
017package com.github.siroshun09.mccommand.paper;
018
019import com.github.siroshun09.mccommand.common.Command;
020import com.github.siroshun09.mccommand.common.context.CommandContext;
021import com.github.siroshun09.mccommand.common.context.SimpleCommandContext;
022import com.github.siroshun09.mccommand.paper.sender.PaperSender;
023import org.bukkit.command.CommandExecutor;
024import org.bukkit.command.CommandSender;
025import org.bukkit.command.PluginCommand;
026import org.bukkit.command.TabCompleter;
027import org.bukkit.plugin.Plugin;
028import org.bukkit.plugin.java.JavaPlugin;
029import org.jetbrains.annotations.NotNull;
030import org.jetbrains.annotations.Nullable;
031
032import java.util.List;
033import java.util.concurrent.Executor;
034import java.util.concurrent.Executors;
035
036public final class PaperCommandFactory {
037
038    private PaperCommandFactory() {
039        throw new UnsupportedOperationException();
040    }
041
042    /**
043     * Registers the command.
044     *
045     * @param target  the {@link PluginCommand}
046     * @param command the command to register
047     */
048    public static void register(@NotNull PluginCommand target, @NotNull Command command) {
049        PaperCommandImpl paperCommand = new PaperCommandImpl(command);
050
051        target.setExecutor(paperCommand);
052        target.setTabCompleter(paperCommand);
053    }
054
055    /**
056     * Searches for {@link PluginCommand} that is named as {@link Command#getName()}
057     * and register the command if it exists.
058     *
059     * @param sourcePlugin the plugin to search for the command
060     * @param command      the command to register
061     */
062    public static void registerIfExists(@NotNull JavaPlugin sourcePlugin, @NotNull Command command) {
063        PluginCommand pluginCommand = sourcePlugin.getCommand(command.getName());
064
065        if (pluginCommand != null) {
066            register(pluginCommand, command);
067        }
068    }
069
070    /**
071     * Registers the command.
072     * <p>
073     * If you register a command with this method, it will be executed asynchronously.
074     * <p>
075     * Note:
076     * <p>
077     * The tab completion will execute on main thread.
078     * <p>
079     * If you want the tab completion to be executed asynchronously, use
080     * {@link com.github.siroshun09.mccommand.paper.listener.AsyncTabCompleteListener#register(Plugin, Command)}.
081     *
082     * @param target  the {@link PluginCommand}
083     * @param command the command to register
084     */
085    public static void registerAsync(@NotNull PluginCommand target, @NotNull Command command) {
086        registerAsync(target, command, Executors.newSingleThreadExecutor());
087    }
088
089    /**
090     * Searches for {@link PluginCommand} that is named as {@link Command#getName()}
091     * and register the command if it exists.
092     *
093     * @param sourcePlugin the plugin to search for the command
094     * @param command      the command to register
095     * @see PaperCommandFactory#registerAsync(PluginCommand, Command)
096     */
097    public static void registerAsyncIfExists(@NotNull JavaPlugin sourcePlugin, @NotNull Command command) {
098        PluginCommand pluginCommand = sourcePlugin.getCommand(command.getName());
099
100        if (pluginCommand != null) {
101            registerAsync(pluginCommand, command);
102        }
103    }
104
105    /**
106     * Registers the command.
107     * <p>
108     * If you register a command with this method, it will be executed asynchronously.
109     * <p>
110     * Note:
111     * <p>
112     * The tab completion will execute on main thread.
113     * <p>
114     * If you want the tab completion to be executed asynchronously, use {@link com.github.siroshun09.mccommand.paper.listener.AsyncTabCompleteListener#register(Plugin, Command)}.
115     *
116     * @param target   the {@link PluginCommand}
117     * @param command  the command to register
118     * @param executor the executor to run command
119     */
120    public static void registerAsync(@NotNull PluginCommand target, @NotNull Command command, @NotNull Executor executor) {
121        AsyncPaperCommandImpl paperCommand = new AsyncPaperCommandImpl(command, executor);
122
123        target.setExecutor(paperCommand);
124        target.setTabCompleter(paperCommand);
125    }
126
127    /**
128     * Searches for {@link PluginCommand} that is named as {@link Command#getName()}
129     * and register the command if it exists.
130     *
131     * @param sourcePlugin the plugin to search for the command
132     * @param command      the command to register
133     * @param executor     the executor to run command
134     * @see PaperCommandFactory#registerAsync(PluginCommand, Command)
135     */
136    public static void registerAsyncIfExists(@NotNull JavaPlugin sourcePlugin, @NotNull Command command,
137                                             @NotNull Executor executor) {
138        PluginCommand pluginCommand = sourcePlugin.getCommand(command.getName());
139
140        if (pluginCommand != null) {
141            registerAsync(pluginCommand, command, executor);
142        }
143    }
144
145    private static class PaperCommandImpl implements CommandExecutor, TabCompleter {
146
147        private final Command command;
148
149        private PaperCommandImpl(@NotNull Command command) {
150            this.command = command;
151        }
152
153        @Override
154        public boolean onCommand(@NotNull CommandSender sender, org.bukkit.command.@NotNull Command cmd,
155                                 @NotNull String label, @NotNull String[] args) {
156            command.onExecution(
157                    createContext(sender, label, args)
158            );
159
160            return true;
161        }
162
163        @Override
164        public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, org.bukkit.command.@NotNull Command cmd,
165                                                    @NotNull String label, @NotNull String[] args) {
166            return command.onTabCompletion(
167                    createContext(sender, label, args)
168            );
169        }
170
171        private CommandContext createContext(@NotNull CommandSender sender, @NotNull String label, @NotNull String[] args) {
172            return SimpleCommandContext.newBuilder()
173                    .setCommand(command)
174                    .setSender(new PaperSender(sender))
175                    .setArguments(args)
176                    .setLabel(label)
177                    .build();
178        }
179    }
180
181    private static class AsyncPaperCommandImpl implements CommandExecutor, TabCompleter {
182
183        private final Command command;
184        private final Executor executor;
185
186        private AsyncPaperCommandImpl(@NotNull Command command, @NotNull Executor executor) {
187            this.command = command;
188            this.executor = executor;
189        }
190
191        @Override
192        public boolean onCommand(@NotNull CommandSender sender, org.bukkit.command.@NotNull Command cmd,
193                                 @NotNull String label, @NotNull String[] args) {
194            executor.execute(() ->
195                    command.onExecution(
196                            createContext(sender, label, args)
197                    ));
198
199            return true;
200        }
201
202        @Override
203        public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, org.bukkit.command.@NotNull Command cmd,
204                                                    @NotNull String label, @NotNull String[] args) {
205            return command.onTabCompletion(
206                    createContext(sender, label, args)
207            );
208        }
209
210        private CommandContext createContext(@NotNull CommandSender sender, @NotNull String label, @NotNull String[] args) {
211            return SimpleCommandContext.newBuilder()
212                    .setCommand(command)
213                    .setSender(new PaperSender(sender))
214                    .setArguments(args)
215                    .setLabel(label)
216                    .build();
217        }
218    }
219}