package net.minecraft.command.construction;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import org.apache.commons.collections4.trie.PatriciaTrie;
import org.apache.commons.lang3.tuple.Pair;
import net.minecraft.command.IPermission;
import net.minecraft.command.ParsingUtilities;
import net.minecraft.command.SyntaxErrorException;
import net.minecraft.command.arg.ArgWrapper;
import net.minecraft.command.arg.CommandArg;
import net.minecraft.command.arg.PermissionWrapper;
import net.minecraft.command.arg.PermissionWrapper.Command;
import net.minecraft.command.arg.Setter;
import net.minecraft.command.arg.Setter.SetterProvider;
import net.minecraft.command.completion.ITabCompletion;
import net.minecraft.command.completion.TabCompletion;
import net.minecraft.command.construction.CommandDescriptorDefault.CParserData;
import net.minecraft.command.descriptors.CommandDescriptor;
import net.minecraft.command.descriptors.ICommandDescriptor;
import net.minecraft.command.parser.Parser;
import net.minecraft.command.type.IExParse;
import net.minecraft.command.type.custom.TypeLabelDeclaration.LabelRegistration;
import net.minecraft.command.type.custom.command.ParserKeyword;
import net.minecraft.command.type.management.TypeID;
public abstract class CommandDescriptorDefault extends CommandDescriptor<CParserData>
{
public static class CParserData
{
public final Parser parser;
public final List<ArgWrapper<?>> params;
public final List<String> path = new ArrayList<>();
public List<SetterProvider<?>> labels = null;
private List<LabelRegistration<?>> labelRegistrations = null;
public CParserData(final Parser parser, final int count)
{
this.parser = parser;
this.params = new ArrayList<>(count);
}
public void add(final ArgWrapper<?> item)
{
this.params.add(item);
}
public void add(final String keyword)
{
this.path.add(keyword);
}
private int index = 0;
public ArgWrapper<?> get()
{
if (this.index >= this.params.size())
return null;
return this.params.get(this.index++);
}
public ArgWrapper<?> get(final int id)
{
this.index = id;
return this.get();
}
public <T> CommandArg<T> get(final TypeID<T> type, final int id)
{
return ArgWrapper.get(type, this.get(id));
}
public <T> CommandArg<T> get(final TypeID<T> type)
{
return ArgWrapper.get(type, this.get());
}
private int pathIndex = 0;
public String getPath()
{
if (this.pathIndex >= this.path.size())
return null;
return this.path.get(this.pathIndex++);
}
public String getPath(final int id)
{
this.pathIndex = id;
return this.getPath();
}
public int size()
{
return this.params.size();
}
public boolean isEmpty()
{
return this.params.isEmpty();
}
public void addLabel(final SetterProvider<?> label)
{
if (this.labels == null)
this.labels = new ArrayList<>();
this.labels.add(label);
}
private int labelIndex = 0;
public <T> Setter<T> getLabel(final TypeID<T> type)
{
if (this.labels == null)
return null;
if (this.labelIndex >= this.labels.size())
return null;
return this.labels.get(this.labelIndex++).getSetter(type);
}
public <T> Setter<T> getLabel(final TypeID<T> type, final int index)
{
this.labelIndex = index;
return this.getLabel(type);
}
public void addLabelRegistration(final LabelRegistration<?> registration)
{
if (this.labelRegistrations == null)
this.labelRegistrations = new ArrayList<>();
this.labelRegistrations.add(registration);
}
private int labelRegistrationIndex = 0;
public void registerLabel(final Parser parser) throws SyntaxErrorException
{
if (this.labelRegistrations == null || this.labelRegistrationIndex >= this.labelRegistrations.size())
throw new IllegalArgumentException("Trying to register non-existing label");
this.addLabel(this.labelRegistrations.get(this.labelRegistrationIndex++).register(parser));
}
public void registerLabel(final Parser parser, final int index) throws SyntaxErrorException
{
this.labelRegistrationIndex = index;
this.registerLabel(parser);
}
}
private final PatriciaTrie<ICommandDescriptor<? super CParserData>> keywords = new PatriciaTrie<>();
private final Set<ITabCompletion> keywordCompletions = new HashSet<>();
private final ParserKeyword kp = new ParserKeyword(this);
private final List<IExParse<Void, ? super CParserData>> types;
public CommandDescriptorDefault(final IPermission permission, final UsageProvider usage, final List<IExParse<Void, ? super CParserData>> types)
{
super(permission, usage);
this.types = types;
}
public CommandDescriptorDefault(final IPermission permission, final UsageProvider usage, final Map<String, CommandDescriptor<? super CParserData>> keywords, final List<IExParse<Void, ? super CParserData>> types)
{
super(permission, usage);
this.addSubDescriptors(keywords);
this.types = types;
}
public CommandDescriptorDefault(final IPermission permission, final UsageProvider usage, final Set<Pair<Set<String>, CommandDescriptor<? super CParserData>>> descriptors, final List<IExParse<Void, ? super CParserData>> types)
{
super(permission, usage);
this.addSubDescriptors(descriptors);
this.types = types;
}
@Override
public void parse(final Parser parser, final CParserData parserData, final UsageProvider usage) throws SyntaxErrorException
{
for (final IExParse<Void, ? super CParserData> type : this.types)
{
if (!parser.checkSpace())
throw usage.createException(parser, parserData.path);
type.parse(parser, parserData);
}
}
@Override
public Command parse(final Parser parser) throws SyntaxErrorException
{
ICommandDescriptor<? super CParserData> currDescriptor = this;
IPermission permission = this.permission;
UsageProvider usage = this.usage;
final Matcher endingMatcher = parser.getMatcher(ParsingUtilities.endingMatcher);
final CParserData data = new CParserData(parser, this.types.size());
while (true)
{
currDescriptor.parse(parser, data, usage);
if (parser.find(endingMatcher))
{
// CommandsParser REQUIRES that endingMatcher is in the following state: whitespaces processed + found match
parser.incIndex(endingMatcher.group(1).length());
final CommandArg<Integer> command = currDescriptor.construct(data);
if (command == null)
throw usage.createException(parser, data.path);
return new PermissionWrapper.Command(command, permission);
}
if (!parser.checkSpace() || (currDescriptor = currDescriptor.getSubDescriptor(parser, data)) == null)
throw usage.createException(parser, data.path);
if (currDescriptor.permission != null)
permission = currDescriptor.permission;
if (currDescriptor.usage != null)
usage = currDescriptor.usage;
}
}
@Override
public void addSubDescriptor(final String key, final ICommandDescriptor<? super CParserData> descriptor)
{
if (this.keywords.put(key, descriptor) != null)
throw new IllegalArgumentException("Keyword '" + key + "' already registered");
if ("".equals(key))
return;
this.keywordCompletions.add(new TabCompletion(key));
}
@Override
public ICommandDescriptor<? super CParserData> getSubDescriptor(final String keyword)
{
return this.keywords.get(keyword);
}
@Override
public ICommandDescriptor<? super CParserData> getSubDescriptor(final Parser parser, final CParserData data) throws SyntaxErrorException
{
return this.kp.parse(parser, data);
}
public final Set<ITabCompletion> getKeywordCompletions()
{
return this.keywordCompletions;
}
}