package de.steamwar.command; import lombok.AllArgsConstructor; import lombok.Setter; import java.lang.reflect.Array; import java.util.Arrays; import java.util.List; class CommandPart { private static final String[] EMPTY_ARRAY = new String[0]; @AllArgsConstructor private static class CheckArgumentResult { private final boolean success; private final Object value; } private AbstractTypeMapper typeMapper; private AbstractGuardChecker guardChecker; private Class varArgType; private String optional; private GuardCheckType guardCheckType; private CommandPart next = null; @Setter private boolean ignoreAsArgument = false; public CommandPart(AbstractTypeMapper typeMapper, AbstractGuardChecker guardChecker, Class varArgType, String optional, GuardCheckType guardCheckType) { this.typeMapper = typeMapper; this.guardChecker = guardChecker; this.varArgType = varArgType; this.optional = optional; this.guardCheckType = guardCheckType; validatePart(); } public void setNext(CommandPart next) { if (varArgType != null) { throw new IllegalArgumentException("There can't be a next part if this is a vararg part!"); } this.next = next; } private void validatePart() { if (guardCheckType == GuardCheckType.TAB_COMPLETE) { throw new IllegalArgumentException("Tab complete is not allowed as a guard check type!"); } if (optional != null && varArgType != null) { throw new IllegalArgumentException("A vararg part can't have an optional part!"); } if (optional != null) { try { typeMapper.map(null, EMPTY_ARRAY, optional); } catch (Exception e) { throw new IllegalArgumentException("The optional part is not valid!"); } } } public void generateArgumentArray(List current, T sender, String[] args, int startIndex) { if (varArgType != null) { Object array = Array.newInstance(varArgType, args.length - startIndex); for (int i = startIndex; i < args.length; i++) { CheckArgumentResult validArgument = checkArgument(null, sender, args, i); if (!validArgument.success) { throw new CommandParseException(); } Array.set(array, i - startIndex, validArgument.value); } current.add(array); return; } CheckArgumentResult validArgument = checkArgument(null, sender, args, startIndex); if (!validArgument.success && optional == null) { throw new CommandParseException(); } if (!validArgument.success) { if (!ignoreAsArgument) { current.add(typeMapper.map(sender, EMPTY_ARRAY, optional)); } if (next != null) { next.generateArgumentArray(current, sender, args, startIndex); } return; } if (!ignoreAsArgument) { current.add(validArgument.value); } if (next != null) { next.generateArgumentArray(current, sender, args, startIndex + 1); } } public boolean guardCheck(T sender, String[] args, int startIndex) { if (varArgType != null) { for (int i = startIndex; i < args.length; i++) { GuardResult guardResult = checkGuard(guardCheckType, sender, args, i); if (guardResult == GuardResult.DENIED) { throw new CommandNoHelpException(); } if (guardResult == GuardResult.DENIED_WITH_HELP) { return false; } } return true; } GuardResult guardResult = checkGuard(guardCheckType, sender, args, startIndex); if (guardResult == GuardResult.DENIED) { if (optional != null && next != null) { return next.guardCheck(sender, args, startIndex); } throw new CommandNoHelpException(); } if (guardResult == GuardResult.DENIED_WITH_HELP) { if (optional != null && next != null) { return next.guardCheck(sender, args, startIndex); } return false; } if (next != null) { return next.guardCheck(sender, args, startIndex + 1); } return true; } public void generateTabComplete(List current, T sender, String[] args, int startIndex) { if (varArgType != null) { for (int i = startIndex; i < args.length - 1; i++) { CheckArgumentResult validArgument = checkArgument(null, sender, args, i); if (!validArgument.success) { return; } } List strings = typeMapper.tabCompletes(sender, Arrays.copyOf(args, args.length - 1), args[args.length - 1]); if (strings != null) { current.addAll(strings); } return; } if (args.length - 1 > startIndex) { CheckArgumentResult checkArgumentResult = checkArgument(GuardCheckType.TAB_COMPLETE, sender, args, startIndex); if (checkArgumentResult.success && next != null) { next.generateTabComplete(current, sender, args, startIndex + 1); return; } if (optional != null && next != null) { next.generateTabComplete(current, sender, args, startIndex); } return; } List strings = typeMapper.tabCompletes(sender, Arrays.copyOf(args, startIndex), args[startIndex]); if (strings != null) { current.addAll(strings); } if (optional != null && next != null) { next.generateTabComplete(current, sender, args, startIndex); } } private CheckArgumentResult checkArgument(GuardCheckType guardCheckType, T sender, String[] args, int index) { try { Object value = typeMapper.map(sender, Arrays.copyOf(args, index), args[index]); if (value == null) { return new CheckArgumentResult(false, null); } GuardResult guardResult = checkGuard(guardCheckType, sender, args, index); switch (guardResult) { case ALLOWED: return new CheckArgumentResult(true, value); case DENIED: throw new CommandNoHelpException(); case DENIED_WITH_HELP: default: return new CheckArgumentResult(false, null); } } catch (Exception e) { return new CheckArgumentResult(false, null); } } private GuardResult checkGuard(GuardCheckType guardCheckType, T sender, String[] args, int index) { if (guardChecker != null && guardCheckType != null) { return guardChecker.guard(sender, guardCheckType, Arrays.copyOf(args, index), args[index]); } return GuardResult.ALLOWED; } }