001/*
002 * Copyright (c) 2016-2017 Daniel Ennis (Aikar) - MIT License
003 *
004 *  Permission is hereby granted, free of charge, to any person obtaining
005 *  a copy of this software and associated documentation files (the
006 *  "Software"), to deal in the Software without restriction, including
007 *  without limitation the rights to use, copy, modify, merge, publish,
008 *  distribute, sublicense, and/or sell copies of the Software, and to
009 *  permit persons to whom the Software is furnished to do so, subject to
010 *  the following conditions:
011 *
012 *  The above copyright notice and this permission notice shall be
013 *  included in all copies or substantial portions of the Software.
014 *
015 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
016 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
017 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
018 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
019 *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
020 *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
021 *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
022 */
023
024package co.aikar.commands;
025
026import co.aikar.commands.apachecommonslang.ApacheCommonsExceptionUtil;
027import net.md_5.bungee.api.ChatColor;
028import net.md_5.bungee.api.CommandSender;
029import net.md_5.bungee.api.plugin.Plugin;
030
031import java.lang.reflect.Method;
032import java.lang.reflect.Parameter;
033import java.util.List;
034import java.util.Map;
035import java.util.HashMap;
036import java.util.logging.Level;
037import java.util.logging.Logger;
038
039public class BungeeCommandManager extends CommandManager<CommandSender, ChatColor, BungeeMessageFormatter> {
040
041    protected final Plugin plugin;
042    protected Map<String, BungeeRootCommand> registeredCommands = new HashMap<>();
043    protected BungeeCommandContexts contexts;
044    protected BungeeCommandCompletions completions;
045    protected BungeeLocales locales;
046
047    public BungeeCommandManager(Plugin plugin) {
048        this.plugin = plugin;
049        this.formatters.put(MessageType.ERROR, defaultFormatter = new BungeeMessageFormatter(ChatColor.RED, ChatColor.YELLOW, ChatColor.RED));
050        this.formatters.put(MessageType.SYNTAX, new BungeeMessageFormatter(ChatColor.YELLOW, ChatColor.GREEN, ChatColor.WHITE));
051        this.formatters.put(MessageType.INFO, new BungeeMessageFormatter(ChatColor.BLUE, ChatColor.DARK_GREEN, ChatColor.GREEN));
052        this.formatters.put(MessageType.HELP, new BungeeMessageFormatter(ChatColor.AQUA, ChatColor.GREEN, ChatColor.YELLOW));
053        getLocales(); // auto load locales
054    }
055
056    public Plugin getPlugin() {
057        return this.plugin;
058    }
059
060    @Override
061    public synchronized CommandContexts<BungeeCommandExecutionContext> getCommandContexts() {
062        if (this.contexts == null) {
063            this.contexts = new BungeeCommandContexts(this);
064        }
065        return contexts;
066    }
067
068    @Override
069    public synchronized CommandCompletions<BungeeCommandCompletionContext> getCommandCompletions() {
070        if (this.completions == null) {
071            this.completions = new BungeeCommandCompletions(this);
072        }
073        return completions;
074    }
075
076    @Override
077    public BungeeLocales getLocales() {
078        if (this.locales == null) {
079            this.locales = new BungeeLocales(this);
080            this.locales.loadLanguages();
081        }
082        return locales;
083    }
084
085
086    @Override
087    public void registerCommand(BaseCommand command) {
088        command.onRegister(this);
089        for (Map.Entry<String, RootCommand> entry : command.registeredCommands.entrySet()) {
090            String commandName = entry.getKey().toLowerCase();
091            BungeeRootCommand bungeeCommand = (BungeeRootCommand) entry.getValue();
092            if (!bungeeCommand.isRegistered) {
093                this.plugin.getProxy().getPluginManager().registerCommand(this.plugin, bungeeCommand);
094            }
095            bungeeCommand.isRegistered = true;
096            registeredCommands.put(commandName, bungeeCommand);
097        }
098    }
099
100    public void unregisterCommand(BaseCommand command) {
101        for (Map.Entry<String, RootCommand> entry : command.registeredCommands.entrySet()) {
102            String commandName = entry.getKey().toLowerCase();
103            BungeeRootCommand bungeeCommand = (BungeeRootCommand) entry.getValue();
104            bungeeCommand.getSubCommands().values().removeAll(command.subCommands.values());
105            if (bungeeCommand.getSubCommands().isEmpty() && bungeeCommand.isRegistered)  {
106                unregisterCommand(bungeeCommand);
107                bungeeCommand.isRegistered = false;
108                registeredCommands.remove(commandName);
109            }
110        }
111    }
112
113    public void unregisterCommand(BungeeRootCommand command) {
114        this.plugin.getProxy().getPluginManager().unregisterCommand(command);
115    }
116
117    public void unregisterCommands() {
118        for (Map.Entry<String, BungeeRootCommand> entry : registeredCommands.entrySet()) {
119            unregisterCommand(entry.getValue());
120        }
121    }
122
123    @Override
124    public boolean hasRegisteredCommands() {
125        return !registeredCommands.isEmpty();
126    }
127
128    @Override
129    public boolean isCommandIssuer(Class<?> aClass) {
130        return CommandSender.class.isAssignableFrom(aClass);
131    }
132
133    @Override
134    public CommandIssuer getCommandIssuer(Object issuer) {
135        if (!(issuer instanceof CommandSender)) {
136            throw new IllegalArgumentException(issuer.getClass().getName() + " is not a Command Issuer.");
137        }
138        return new BungeeCommandIssuer(this, (CommandSender) issuer);
139    }
140
141    @Override
142    public RootCommand createRootCommand(String cmd) {
143        return new BungeeRootCommand(this, cmd);
144    }
145
146    @Override
147    public <R extends CommandExecutionContext> R createCommandContext(RegisteredCommand command, Parameter parameter, CommandIssuer sender, List<String> args, int i, Map<String, Object> passedArgs) {
148        //noinspection unchecked
149        return (R) new BungeeCommandExecutionContext(command, parameter, (BungeeCommandIssuer) sender, args, i, passedArgs);
150    }
151
152    @Override
153    public CommandCompletionContext createCompletionContext(RegisteredCommand command, CommandIssuer sender, String input, String config, String[] args) {
154        return new BungeeCommandCompletionContext(command, sender, input, config, args);
155    }
156
157    @Override
158    public RegisteredCommand createRegisteredCommand(BaseCommand command, String cmdName, Method method, String prefSubCommand) {
159        return new RegisteredCommand(command, cmdName, method, prefSubCommand);
160    }
161
162    @Override
163    public void log(LogLevel level, String message, Throwable throwable) {
164        Logger logger = this.plugin.getLogger();
165        Level logLevel = level == LogLevel.INFO ? Level.INFO : Level.SEVERE;
166        logger.log(logLevel, LogLevel.LOG_PREFIX + message);
167        if (throwable != null) {
168            for (String line : ACFPatterns.NEWLINE.split(ApacheCommonsExceptionUtil.getFullStackTrace(throwable))) {
169                logger.log(logLevel, LogLevel.LOG_PREFIX + line);
170            }
171        }
172    }
173}