/* * 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.permissions.PermissionUtils.hasPermissions; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import org.bukkit.permissions.Permissible; /** * Holds a chain of CommandInvocations. Used for generating the usage string. * * @author zerothangel */ final class InvocationChain { private final List<CommandInvocation> chain; private InvocationChain(List<CommandInvocation> chain) { this.chain = chain; } InvocationChain() { this(new LinkedList<CommandInvocation>()); } // Adds a new invocation to the chain void addInvocation(String label, CommandMetaData commandMetaData) { chain.add(new CommandInvocation(label, commandMetaData)); } // Generate a usage string String getUsageString(UsageOptions usageOptions) { return getUsageString(usageOptions, false); } // Generate a usage string String getUsageString(UsageOptions usageOptions, boolean withDescription) { boolean first = true; StringBuilder usage = new StringBuilder(); usage.append(usageOptions.getPreamble()); for (Iterator<CommandInvocation> i = chain.iterator(); i.hasNext();) { CommandInvocation ci = i.next(); if (first) { usage.append('/'); first = false; } usage.append(ci.getLabel()); CommandMetaData cmd = ci.getCommandMetaData(); if (!cmd.getFlagOptions().isEmpty() || !cmd.getPositionalArguments().isEmpty()) { usage.append(' '); for (Iterator<OptionMetaData> j = cmd.getFlagOptions().iterator(); j.hasNext();) { OptionMetaData omd = j.next(); usage.append(usageOptions.getFlagStart()); usage.append(omd.getName()); if (omd.getType() != Boolean.class && omd.getType() != Boolean.TYPE) { // Show a value usage.append(usageOptions.getFlagValueStart()); usage.append(omd.getValueName()); usage.append(usageOptions.getFlagValueEnd()); } usage.append(usageOptions.getFlagEnd()); if (j.hasNext()) usage.append(' '); } if (!cmd.getFlagOptions().isEmpty() && !cmd.getPositionalArguments().isEmpty()) usage.append(' '); for (Iterator<OptionMetaData> j = cmd.getPositionalArguments().iterator(); j.hasNext();) { OptionMetaData omd = j.next(); usage.append(usageOptions.getParameterStart(omd.isOptional())); usage.append(omd.getName()); usage.append(usageOptions.getParameterEnd(omd.isOptional())); if (j.hasNext()) usage.append(' '); } } // Add varargs description, if any if (cmd.getRest() != null) { usage.append(usageOptions.getVarargsStart()); usage.append(cmd.getRest()); usage.append(usageOptions.getVarargsEnd()); } if (i.hasNext()) usage.append(' '); } // Attach description if (withDescription && !chain.isEmpty()) { // Pull out last CommandMetaData CommandMetaData cmd = chain.get(chain.size() - 1).getCommandMetaData(); if (cmd.getDescription() != null) { usage.append(usageOptions.getDescriptionDelimiter()); usage.append(cmd.getDescription()); } } usage.append(usageOptions.getPostamble()); return usage.toString(); } // Tests whether the given permissible can execute this entire chain boolean canBeExecutedBy(Permissible permissible) { for (CommandInvocation ci : chain) { if (!hasPermissions(permissible, ci.getCommandMetaData().isRequireAll(), ci.getCommandMetaData().isCheckNegations(), ci.getCommandMetaData().getPermissions())) return false; } return true; } // Returns a copy of this chain InvocationChain copy() { // Feh to clone() return new InvocationChain(new LinkedList<>(chain)); } void pop() { if (chain.isEmpty()) throw new IllegalStateException("InvocationChain is empty"); chain.remove(chain.size() - 1); } boolean isEmpty() { return chain.isEmpty(); } }