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.CommandRouter.CommandRouteResult;
027import co.aikar.commands.CommandRouter.RouteSearch;
028import com.google.common.collect.SetMultimap;
029
030import java.util.ArrayList;
031import java.util.HashSet;
032import java.util.List;
033import java.util.Set;
034
035public interface RootCommand {
036    void addChild(BaseCommand command);
037
038    CommandManager getManager();
039
040    SetMultimap<String, RegisteredCommand> getSubCommands();
041
042    List<BaseCommand> getChildren();
043
044    String getCommandName();
045
046    default void addChildShared(List<BaseCommand> children, SetMultimap<String, RegisteredCommand> subCommands, BaseCommand command) {
047        command.subCommands.entries().forEach(e -> {
048            subCommands.put(e.getKey(), e.getValue());
049        });
050
051        children.add(command);
052    }
053
054    /**
055     * @return If this root command can be summarized to a single required permission node to use it, returns that value. If any RegisteredCommand is permission-less, or has multiple required permission nodes, null is returned.
056     */
057    default String getUniquePermission() {
058        Set<String> permissions = new HashSet<>();
059        for (BaseCommand child : getChildren()) {
060            for (RegisteredCommand<?> value : child.subCommands.values()) {
061                Set<String> requiredPermissions = value.getRequiredPermissions();
062                if (requiredPermissions.isEmpty()) {
063                    return null;
064                } else {
065                    permissions.addAll(requiredPermissions);
066                }
067            }
068        }
069        return permissions.size() == 1 ? permissions.iterator().next() : null;
070    }
071
072    default boolean hasAnyPermission(CommandIssuer issuer) {
073        List<BaseCommand> children = getChildren();
074        if (children.isEmpty()) {
075            return true;
076        }
077
078        for (BaseCommand child : children) {
079            if (!child.hasPermission(issuer)) {
080                continue;
081            }
082            for (RegisteredCommand value : child.getRegisteredCommands()) {
083                if (value.hasPermission(issuer)) {
084                    return true;
085                }
086            }
087        }
088        return false;
089    }
090
091    default BaseCommand execute(CommandIssuer sender, String commandLabel, String[] args) {
092        CommandRouter router = getManager().getRouter();
093        RouteSearch search = router.routeCommand(this, commandLabel, args, false);
094        BaseCommand defCommand = getDefCommand();
095        if (search != null) {
096            CommandRouteResult result = router.matchCommand(search, false);
097            if (result != null) {
098                BaseCommand scope = result.cmd.scope;
099                scope.execute(sender, result);
100                return scope;
101            }
102
103            RegisteredCommand firstElement = ACFUtil.getFirstElement(search.commands);
104            if (firstElement != null) {
105                defCommand = firstElement.scope;
106            }
107        }
108
109        defCommand.help(sender, args);
110        return defCommand;
111    }
112
113    default List<String> getTabCompletions(CommandIssuer sender, String alias, String[] args) {
114        return getTabCompletions(sender, alias, args, false);
115    }
116
117    default List<String> getTabCompletions(CommandIssuer sender, String alias, String[] args, boolean commandsOnly) {
118        return getTabCompletions(sender, alias, args, commandsOnly, false);
119    }
120
121    default List<String> getTabCompletions(CommandIssuer sender, String alias, String[] args, boolean commandsOnly, boolean isAsync) {
122        Set<String> completions = new HashSet<>();
123        getChildren().forEach(child -> {
124            if (!commandsOnly) {
125                completions.addAll(child.tabComplete(sender, this, args, isAsync));
126            }
127            completions.addAll(child.getCommandsForCompletion(sender, args));
128        });
129        return new ArrayList<>(completions);
130    }
131
132
133    default RegisteredCommand getDefaultRegisteredCommand() {
134        BaseCommand defCommand = this.getDefCommand();
135        if (defCommand != null) {
136            return defCommand.getDefaultRegisteredCommand();
137        }
138        return null;
139    }
140
141    default BaseCommand getDefCommand() {
142        return null;
143    }
144
145
146    default String getDescription() {
147        final RegisteredCommand cmd = this.getDefaultRegisteredCommand();
148        if (cmd != null) {
149            return cmd.getHelpText();
150        }
151        BaseCommand defCommand = getDefCommand();
152        if (defCommand != null && defCommand.description != null) {
153            return defCommand.description;
154        }
155        return "";
156    }
157
158
159    default String getUsage() {
160        final RegisteredCommand cmd = this.getDefaultRegisteredCommand();
161        if (cmd != null) {
162            return cmd.syntaxText != null ? cmd.syntaxText : "";
163        }
164        return "";
165    }
166}