package net.minecraft.commands;

import java.util.Optional;
import javax.annotation.Nullable;
import java.util.ArrayDeque;
import net.minecraft.server.ServerFunctionManager;
import com.mojang.brigadier.ParseResults;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.StringReader;
import com.google.common.collect.Lists;
import java.util.List;
import com.mojang.brigadier.CommandDispatcher;
import net.minecraft.resources.ResourceLocation;

public class CommandFunction {
    private final Entry[] entries;
    private final ResourceLocation id;
    
    public CommandFunction(final ResourceLocation uh, final Entry[] arr) {
        this.id = uh;
        this.entries = arr;
    }
    
    public ResourceLocation getId() {
        return this.id;
    }
    
    public Entry[] getEntries() {
        return this.entries;
    }
    
    public static CommandFunction fromLines(final ResourceLocation uh, final CommandDispatcher<CommandSourceStack> commandDispatcher, final CommandSourceStack cz, final List<String> list) {
        final List<Entry> list2 = Lists.newArrayListWithCapacity(list.size());
        for (int integer6 = 0; integer6 < list.size(); ++integer6) {
            final int integer7 = integer6 + 1;
            final String string8 = list.get(integer6).trim();
            final StringReader stringReader9 = new StringReader(string8);
            if (stringReader9.canRead()) {
                if (stringReader9.peek() != '#') {
                    if (stringReader9.peek() == '/') {
                        stringReader9.skip();
                        if (stringReader9.peek() == '/') {
                            throw new IllegalArgumentException("Unknown or invalid command '" + string8 + "' on line " + integer7 + " (if you intended to make a comment, use '#' not '//')");
                        }
                        final String string9 = stringReader9.readUnquotedString();
                        throw new IllegalArgumentException("Unknown or invalid command '" + string8 + "' on line " + integer7 + " (did you mean '" + string9 + "'? Do not use a preceding forwards slash.)");
                    }
                    else {
                        try {
                            final ParseResults<CommandSourceStack> parseResults10 = (ParseResults<CommandSourceStack>)commandDispatcher.parse(stringReader9, cz);
                            if (parseResults10.getReader().canRead()) {
                                throw Commands.<CommandSourceStack>getParseException(parseResults10);
                            }
                            list2.add(new CommandEntry(parseResults10));
                        }
                        catch (CommandSyntaxException commandSyntaxException10) {
                            throw new IllegalArgumentException("Whilst parsing command on line " + integer7 + ": " + commandSyntaxException10.getMessage());
                        }
                    }
                }
            }
        }
        return new CommandFunction(uh, list2.<Entry>toArray(new Entry[0]));
    }
    
    public static class CommandEntry implements Entry {
        private final ParseResults<CommandSourceStack> parse;
        
        public CommandEntry(final ParseResults<CommandSourceStack> parseResults) {
            this.parse = parseResults;
        }
        
        @Override
        public void execute(final ServerFunctionManager uu, final CommandSourceStack cz, final ArrayDeque<ServerFunctionManager.QueuedCommand> arrayDeque, final int integer) throws CommandSyntaxException {
            uu.getDispatcher().execute(new ParseResults(this.parse.getContext().withSource(cz), this.parse.getReader(), this.parse.getExceptions()));
        }
        
        @Override
        public String toString() {
            return this.parse.getReader().getString();
        }
    }
    
    public static class FunctionEntry implements Entry {
        private final CacheableFunction function;
        
        public FunctionEntry(final CommandFunction cw) {
            this.function = new CacheableFunction(cw);
        }
        
        @Override
        public void execute(final ServerFunctionManager uu, final CommandSourceStack cz, final ArrayDeque<ServerFunctionManager.QueuedCommand> arrayDeque, final int integer) {
            final Entry[] arr6;
            final int integer2;
            final int integer3;
            int integer4;
            this.function.get(uu).ifPresent(cw -> {
                arr6 = cw.getEntries();
                integer2 = integer - arrayDeque.size();
                integer3 = Math.min(arr6.length, integer2);
                for (integer4 = integer3 - 1; integer4 >= 0; --integer4) {
                    arrayDeque.addFirst(new ServerFunctionManager.QueuedCommand(uu, cz, arr6[integer4]));
                }
            });
        }
        
        @Override
        public String toString() {
            return "function " + this.function.getId();
        }
    }
    
    public static class CacheableFunction {
        public static final CacheableFunction NONE;
        @Nullable
        private final ResourceLocation id;
        private boolean resolved;
        private Optional<CommandFunction> function;
        
        public CacheableFunction(@Nullable final ResourceLocation uh) {
            this.function = Optional.<CommandFunction>empty();
            this.id = uh;
        }
        
        public CacheableFunction(final CommandFunction cw) {
            this.function = Optional.<CommandFunction>empty();
            this.resolved = true;
            this.id = null;
            this.function = Optional.<CommandFunction>of(cw);
        }
        
        public Optional<CommandFunction> get(final ServerFunctionManager uu) {
            if (!this.resolved) {
                if (this.id != null) {
                    this.function = uu.get(this.id);
                }
                this.resolved = true;
            }
            return this.function;
        }
        
        @Nullable
        public ResourceLocation getId() {
            return this.function.<ResourceLocation>map(cw -> cw.id).orElse(this.id);
        }
        
        static {
            NONE = new CacheableFunction((ResourceLocation)null);
        }
    }
    
    public interface Entry {
        void execute(final ServerFunctionManager uu, final CommandSourceStack cz, final ArrayDeque<ServerFunctionManager.QueuedCommand> arrayDeque, final int integer) throws CommandSyntaxException;
    }
}
