/* * Copyright 2011 ZerothAngel <zerothangel@tyrannyofheaven.org> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.tyrannyofheaven.bukkit.util.command; import static org.tyrannyofheaven.bukkit.util.ToHStringUtils.hasText; import java.util.ArrayList; import java.util.List; import java.util.Set; import org.bukkit.command.CommandSender; /** * Automatically generates a help page for a sub-command. * * @author zerothangel * * @param <T> */ public class HelpBuilder { private final HandlerExecutor<?> handlerExecutor; private final InvocationChain rootInvocationChain; private UsageOptions usageOptions; private CommandSender sender; private Object handler; private final List<String> outputLines = new ArrayList<>(); private final Set<String> possibleCommands; HelpBuilder(HandlerExecutor<?> handlerExecutor, InvocationChain rootInvocationChain, UsageOptions usageOptions, Set<String> possibleCommands) { if (handlerExecutor == null) throw new IllegalArgumentException("handlerExecutor cannot be null"); if (rootInvocationChain == null) throw new IllegalArgumentException("rootInvocationChain cannot be null"); if (usageOptions == null) throw new IllegalArgumentException("usageOptions cannot be null"); this.handlerExecutor = handlerExecutor; this.rootInvocationChain = rootInvocationChain; this.usageOptions = usageOptions; this.possibleCommands = possibleCommands; } /** * Change UsageOptions. By default, the ones in {@link ToHCommandExecutor} * are used. * * @param usageOptions UsageOptions to use * @return this HelpBuilder */ public HelpBuilder withUsageOptions(UsageOptions usageOptions) { if (usageOptions == null) throw new IllegalArgumentException("usageOptions cannot be null"); this.usageOptions = usageOptions; return this; } // Retrives CommandSender, complaining if one hasn't been set yet private CommandSender getCommandSender() { if (sender == null) throw new IllegalStateException("CommandSender has not been set"); return sender; } /** * Set the CommandSender. This can only be called once. * * @param sender the CommandSender * @return this HelpBuilder */ public HelpBuilder withCommandSender(CommandSender sender) { if (sender == null) throw new IllegalArgumentException("sender cannot be null"); if (this.sender != null) throw new IllegalStateException("CommandSender has already been set"); this.sender = sender; return this; } /** * Set the current handler object. * * @param handler the handler object * @return this HelpBuilder */ public HelpBuilder withHandler(Object handler) { if (handler == null) throw new IllegalArgumentException("handler cannot be null"); this.handler = handler; return this; } // Retrieve the current handler object, complaining if one hasn't been set private Object getHandler() { if (handler == null) throw new IllegalStateException("handler has not been set"); return handler; } /** * Generate a usage message for a particular sibling command. * * @param command the sibling command * @param usePermissions true if permissions should be checked. If the current * sender fails the check, no usage is generated. * @return this HelpBuilder */ public HelpBuilder forSiblingCommand(String command, boolean usePermissions) { if (!hasText(command)) throw new IllegalArgumentException("command must have a value"); if (possibleCommands != null) return this; // can't tab-complete siblings anyway // Remove last invocation (from a copy) InvocationChain invChain = rootInvocationChain.copy(); invChain.pop(); // Fill with sibling invocation handlerExecutor.fillInvocationChain(invChain, command); if (!usePermissions || invChain.canBeExecutedBy(getCommandSender())) { outputLines.add(invChain.getUsageString(usageOptions, true)); } return this; } /** * Generate a usage message for a particular sibling command. Permissions are used. * * @param command the sibling command * @param usePermissions true if permissions should be checked. If the current * sender fails the check, no usage is generated. * @return this HelpBuilder */ public HelpBuilder forSiblingCommand(String command) { return forSiblingCommand(command, true); } /** * Generate a usage message for a particular sub-command. * * @param handler the handler in which the command resides * @param command the command * @param usePermissions true if permissions should be checked. If the current * sender fails the check, no usage is generated. * @return this HelpBuilder */ public HelpBuilder forHandlerAndCommand(Object handler, String command, boolean usePermissions) { if (handler == null) throw new IllegalArgumentException("handler cannot be null"); if (!hasText(command)) throw new IllegalArgumentException("command must have a value"); HandlerExecutor<?> he = handlerExecutor.handlerExecutorFor(handler); InvocationChain invChain = rootInvocationChain.copy(); he.fillInvocationChain(invChain, command); if (!usePermissions || invChain.canBeExecutedBy(getCommandSender())) { if (possibleCommands != null) possibleCommands.add(command); else outputLines.add(invChain.getUsageString(usageOptions, true)); } return this; } /** * Generate a usage message for a particular sub-command. Permissions are used. * * @param handler the handler in which the command resides * @param command the command * @return this HelpBuilder */ public HelpBuilder forHandlerAndCommand(Object handler, String command) { return forHandlerAndCommand(handler, command, true); } /** * Generate a usage message for a particular sub-command. The current handler * object is referenced. * * @param command the command * @param usePermissions true if permissions should be checked. If the current * sender fails the check, no usage is generated. * @return this HelpBuilder */ public HelpBuilder forCommand(String command, boolean usePermissions) { return forHandlerAndCommand(getHandler(), command, usePermissions); } /** * Generate a usage message for a particular sub-command. The current handler * object is referenced. Permissions are used. * * @param command the command * @return this HelpBuilder */ public HelpBuilder forCommand(String command) { return forCommand(command, true); } /** * Outputs all sub-command usage messages. */ public void show() { if (possibleCommands == null) { for (String line : outputLines) { getCommandSender().sendMessage(line); } } } /** * Retrieves the raw sub-command usage messages. * * @return the sub-command usage messages */ public String[] getLines() { return outputLines.toArray(new String[outputLines.size()]); } }