/**
* PermissionsEx
* Copyright (C) zml and PermissionsEx contributors
*
* 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 ninja.leaping.permissionsex.util.command.args;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import ninja.leaping.permissionsex.PermissionsEx;
import ninja.leaping.permissionsex.subject.SubjectType;
import ninja.leaping.permissionsex.util.GuavaStartsWithPredicate;
import ninja.leaping.permissionsex.util.Translatable;
import ninja.leaping.permissionsex.util.command.CommandContext;
import ninja.leaping.permissionsex.util.command.Commander;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import static ninja.leaping.permissionsex.util.Translations.t;
/**
* Contains command elements for parts of the game
*/
public class GameArguments {
private GameArguments() {
}
public static CommandElement subjectType(Translatable key, PermissionsEx pex) {
return new SubjectTypeElement(key, pex);
}
private static class SubjectTypeElement extends CommandElement {
private final PermissionsEx pex;
protected SubjectTypeElement(Translatable key, PermissionsEx pex) {
super(key);
this.pex = pex;
}
@Override
protected Object parseValue(CommandArgs args) throws ArgumentParseException {
final String next = args.next();
Set<String> subjectTypes = pex.getRegisteredSubjectTypes();
if (!subjectTypes.contains(next)) {
throw args.createError(t("Subject type %s was not valid!", next));
}
return next;
}
@Override
public <TextType> List<String> tabComplete(Commander<TextType> src, CommandArgs args, CommandContext context) {
String nextOpt = args.nextIfPresent().orElse("");
return ImmutableList.copyOf(Iterables.filter(pex.getRegisteredSubjectTypes(), new GuavaStartsWithPredicate(nextOpt)));
}
}
/**
* Expect the provided argument to specify a subject. Subject is of one of the forms:
* <ul>
* <li><type>:<identifier></li>
* <li><type> <identifier></li>
* </ul>
* @param key The key to store the parsed argument under
* @param pex The PermissionsEx instance to fetch known subjects from
* @return the element to match the input
*/
public static CommandElement subject(Translatable key, PermissionsEx pex) {
return new SubjectElement(key, pex, null);
}
public static CommandElement subject(Translatable key, PermissionsEx pex, String group) {
return new SubjectElement(key, pex, group);
}
private static class SubjectElement extends CommandElement {
private final PermissionsEx pex;
private final String defaultType;
protected SubjectElement(Translatable key, PermissionsEx pex, String defaultType) {
super(key);
this.pex = pex;
this.defaultType = defaultType;
}
@Override
protected Object parseValue(CommandArgs args) throws ArgumentParseException {
String type = args.next();
String identifier;
if (type.contains(":")) {
String[] typeSplit = type.split(":", 2);
type = typeSplit[0];
identifier = typeSplit[1];
} else if (!args.hasNext() && this.defaultType != null) {
identifier = type;
type = this.defaultType;
} else {
identifier = args.next();
}
SubjectType subjType = pex.getSubjects(type);
//if (!subjType.isRegistered(identifier)) { // TODO: Async command elements
final Optional<String> newIdentifier = subjType.getTypeInfo().getAliasForName(identifier);
if (newIdentifier.isPresent()) {
identifier = newIdentifier.get();
}
//}
if (!subjType.getTypeInfo().isNameValid(identifier)) {
throw args.createError(t("Name '%s' is invalid for subjects of type %s", identifier, type));
}
return Maps.immutableEntry(type, identifier);
}
@Override
public <TextType> List<String> tabComplete(Commander<TextType> src, CommandArgs args, CommandContext context) {
final Optional<String> typeSegment = args.nextIfPresent();
if (!typeSegment.isPresent()) {
return ImmutableList.copyOf(pex.getRegisteredSubjectTypes());
}
String type = typeSegment.get();
Optional<String> identifierSegment = args.nextIfPresent();
if (!identifierSegment.isPresent()) { // TODO: Correct tab completion logic
if (type.contains(":")) {
final String[] argSplit = type.split(":", 2);
type = argSplit[0];
identifierSegment = Optional.of(argSplit[1]);
final SubjectType typeObj = pex.getSubjects(type);
final Iterable<String> allIdents = typeObj.getAllIdentifiers();
final Iterable<String> ret = Iterables.filter(Iterables.concat(allIdents, Iterables.filter(Iterables.transform(allIdents, k -> typeObj.getTypeInfo().getAliasForName(k).orElse(k)), v -> v != null)),
new GuavaStartsWithPredicate(identifierSegment.get())
);
return ImmutableList.copyOf(Iterables.transform(ret, input -> typeObj.getTypeInfo().getTypeName() + ":" + input));
} else {
return ImmutableList.copyOf(Iterables.filter(pex.getRegisteredSubjectTypes(), new GuavaStartsWithPredicate(type)));
}
}
final Iterable<String> allIdents = pex.getSubjects(type).getAllIdentifiers();
final SubjectType typeObj = pex.getSubjects(type);
final Iterable<String> ret = Iterables.filter(Iterables.concat(allIdents, Iterables.filter(Iterables.transform(allIdents, k -> typeObj.getTypeInfo().getAliasForName(k).orElse(k)), v -> v != null)),
new GuavaStartsWithPredicate(identifierSegment.get())
);
return ImmutableList.copyOf(ret);
}
}
public static CommandElement context(Translatable key) {
return new ContextCommandElement(key);
}
private static class ContextCommandElement extends CommandElement {
protected ContextCommandElement(Translatable key) {
super(key);
}
@Override
protected Object parseValue(CommandArgs args) throws ArgumentParseException {
final String context = args.next(); // TODO: Allow multi-word contexts (<key> <value>)
final String[] contextSplit = context.split("=", 2);
if (contextSplit.length != 2) {
throw args.createError(t("Context must be of the form <key>=<value>!"));
}
return Maps.immutableEntry(contextSplit[0], contextSplit[1]);
}
@Override
public <TextType> List<String> tabComplete(Commander<TextType> src, CommandArgs args, CommandContext context) {
return Collections.emptyList();
}
}
public static CommandElement rankLadder(Translatable key, PermissionsEx pex) {
return new RankLadderCommandElement(key, pex);
}
private static class RankLadderCommandElement extends CommandElement {
private final PermissionsEx pex;
protected RankLadderCommandElement(Translatable key, PermissionsEx pex) {
super(key);
this.pex = pex;
}
@Override
protected Object parseValue(CommandArgs args) throws ArgumentParseException {
return pex.getLadders().get(args.next(), null);
}
@Override
public <TextType> List<String> tabComplete(Commander<TextType> src, CommandArgs args, CommandContext context) {
return ImmutableList.copyOf(Iterables.filter(pex.getLadders().getAll(), new GuavaStartsWithPredicate(args.nextIfPresent().orElse(""))));
}
}
public static CommandElement permission(Translatable key, PermissionsEx pex) {
return GenericArguments.suggestibleString(key, () -> pex.getRecordingNotifier().getKnownPermissions());
}
public static CommandElement option(Translatable key, PermissionsEx pex) {
return GenericArguments.suggestibleString(key, () -> pex.getRecordingNotifier().getKnownOptions());
}
}