diff --git a/src/main/java/com/intellectualsites/commands/CommandTree.java b/src/main/java/com/intellectualsites/commands/CommandTree.java index 3c099e84..03311385 100644 --- a/src/main/java/com/intellectualsites/commands/CommandTree.java +++ b/src/main/java/com/intellectualsites/commands/CommandTree.java @@ -24,6 +24,7 @@ package com.intellectualsites.commands; import com.google.common.base.Objects; +import com.google.common.collect.Lists; import com.intellectualsites.commands.components.CommandComponent; import com.intellectualsites.commands.components.StaticComponent; import com.intellectualsites.commands.parser.ComponentParseResult; @@ -32,6 +33,7 @@ import com.intellectualsites.commands.sender.CommandSender; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.*; +import java.util.stream.Collectors; /** * Tree containing all commands and command paths @@ -62,6 +64,72 @@ public class CommandTree { private Optional parseCommand(@Nonnull final CommandSender commandSender, @Nonnull final Queue commandQueue, @Nonnull final Node> root) { + + final List>> children = root.getChildren(); + if (children.size() == 1 && !(children.get(0).getValue() instanceof StaticComponent)) { + // The value has to be a variable + final Node> child = children.get(0); + if (child.getValue() != null) { + final ComponentParseResult result = child.getValue().getParser().parse(commandSender, commandQueue); + if (result.getParsedValue().isPresent()) { + /* TODO: Add context */ + if (child.isLeaf()) { + return Optional.ofNullable(child.getValue().getOwningCommand()); + } else { + return this.parseCommand(commandSender, commandQueue, child); + } + } else if (result.getFailure().isPresent()) { + /* TODO: Return error */ + } + } + } + + /* There are 0 or more static components as children. No variable child components are present */ + if (children.isEmpty()) { + /* We are at the bottom. Check if there's a command attached, in which case we're done */ + if (root.getValue() != null && root.getValue().getOwningCommand() != null) { + return Optional.of(root.getValue().getOwningCommand()); + } else { + /* TODO: Indicate that we could not resolve the command here */ + final List> components = this.getChain(root).stream().map(Node::getValue).collect(Collectors.toList()); + } + } else { + final String popped = commandQueue.poll(); + if (popped == null) { + /* Not enough arguments */ + /* TODO: Send correct usage */ + return Optional.empty(); + } + + int low = 0; + int high = children.size() - 1; + + while (low <= high) { + int mid = (low + high) / 2; + + final Node> node = children.get(mid); + assert node.getValue() != null; + + final int comparison = node.getValue().getName().compareToIgnoreCase(popped); + if (comparison < 0) { + low = mid + 1; + } else if (comparison > 0) { + high = mid - 1; + } else { + /* We found a match */ + if (node.isLeaf()) { + return Optional.ofNullable(node.getValue().getOwningCommand()); + } else { + return parseCommand(commandSender, commandQueue, node); + } + } + } + + /* We could not find a match */ + /* TODO: Send "No Such Command" */ + } + + /* final Iterator>> childIterator = root.getChildren().iterator(); if (childIterator.hasNext()) { while (childIterator.hasNext()) { @@ -69,21 +137,14 @@ public class CommandTree { if (child.getValue() != null) { final ComponentParseResult result = child.getValue().getParser().parse(commandSender, commandQueue); if (result.getParsedValue().isPresent()) { - /* TODO: Add to some context */ return this.parseCommand(commandSender, commandQueue, child); } else if (result.getFailure().isPresent() && root.children.size() == 1) { - /* Return the error somehow :D */ } } } - } else { - /* We are at the bottom. Check if there's a command attached, in which case we're done */ - if (root.getValue() != null && root.getValue().getOwningCommand() != null) { - return Optional.of(root.getValue().getOwningCommand()); - } else { - /* TODO: Indicate that we could not resolve the command here */ - } } + */ + return Optional.empty(); } @@ -99,6 +160,9 @@ public class CommandTree { if (tempNode == null) { tempNode = node.addChild(component); } + if (node.children.size() > 0) { + node.children.sort(Comparator.comparing(Node::getValue)); + } node = tempNode; } if (node.getValue() != null) { @@ -154,11 +218,22 @@ public class CommandTree { return leaves; } + private List>> getChain(@Nullable final Node> end) { + final List>> chain = new LinkedList<>(); + Node> tail = end; + while (tail != null) { + chain.add(tail); + tail = end.getParent(); + } + return Lists.reverse(chain); + } + private static final class Node { private final List> children = new LinkedList<>(); private final T value; + private Node parent; private Node(@Nullable final T value) { this.value = value; @@ -208,6 +283,15 @@ public class CommandTree { public int hashCode() { return Objects.hashCode(getChildren(), getValue()); } + + public void setParent(@Nullable final Node parent) { + this.parent = parent; + } + + @Nullable public Node getParent() { + return this.parent; + } + } } diff --git a/src/main/java/com/intellectualsites/commands/components/CommandComponent.java b/src/main/java/com/intellectualsites/commands/components/CommandComponent.java index aea21793..e5b2ebfe 100644 --- a/src/main/java/com/intellectualsites/commands/components/CommandComponent.java +++ b/src/main/java/com/intellectualsites/commands/components/CommandComponent.java @@ -36,7 +36,7 @@ import java.util.regex.Pattern; * * @param The type that the component parses into */ -public class CommandComponent { +public class CommandComponent implements Comparable> { private static final Pattern NAME_PATTERN = Pattern.compile("[A-Za-z0-9]+"); @@ -152,6 +152,23 @@ public class CommandComponent { return com.google.common.base.Objects.hashCode(isRequired(), getName()); } + @Override + public int compareTo(@Nonnull final CommandComponent o) { + if (this instanceof StaticComponent) { + if (o instanceof StaticComponent) { + return (this.getName().compareTo(o.getName())); + } else { + return -1; + } + } else { + if (o instanceof StaticComponent) { + return 1; + } else { + return 0; + } + } + } + public static class Builder {