package net.minecraft.commands;

import java.util.Optional;
import javax.annotation.Nullable;
import java.util.ArrayDeque;
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 net.minecraft.server.ServerFunctionManager;
import net.minecraft.resources.ResourceLocation;

public class CommandFunction {
    private final Entry[] entries;
    private final ResourceLocation id;
    
    public CommandFunction(final ResourceLocation sm, final Entry[] arr) {
        this.id = sm;
        this.entries = arr;
    }
    
    public ResourceLocation getId() {
        return this.id;
    }
    
    public Entry[] getEntries() {
        return this.entries;
    }
    
    public static CommandFunction fromLines(final ResourceLocation sm, final ServerFunctionManager sy, final List<String> list) {
        final List<Entry> list2 = Lists.newArrayListWithCapacity(list.size());
        for (int integer5 = 0; integer5 < list.size(); ++integer5) {
            final int integer6 = integer5 + 1;
            final String string7 = list.get(integer5).trim();
            final StringReader stringReader8 = new StringReader(string7);
            if (stringReader8.canRead()) {
                if (stringReader8.peek() != '#') {
                    if (stringReader8.peek() == '/') {
                        stringReader8.skip();
                        if (stringReader8.peek() == '/') {
                            throw new IllegalArgumentException("Unknown or invalid command '" + string7 + "' on line " + integer6 + " (if you intended to make a comment, use '#' not '//')");
                        }
                        final String string8 = stringReader8.readUnquotedString();
                        throw new IllegalArgumentException("Unknown or invalid command '" + string7 + "' on line " + integer6 + " (did you mean '" + string8 + "'? Do not use a preceding forwards slash.)");
                    }
                    else {
                        try {
                            final ParseResults<CommandSourceStack> parseResults9 = (ParseResults<CommandSourceStack>)sy.getServer().getCommands().getDispatcher().parse(stringReader8, sy.getCompilationContext());
                            if (parseResults9.getReader().canRead()) {
                                throw Commands.<CommandSourceStack>getParseException(parseResults9);
                            }
                            list2.add(new CommandEntry(parseResults9));
                        }
                        catch (CommandSyntaxException commandSyntaxException9) {
                            throw new IllegalArgumentException("Whilst parsing command on line " + integer6 + ": " + commandSyntaxException9.getMessage());
                        }
                    }
                }
            }
        }
        return new CommandFunction(sm, 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 sy, final CommandSourceStack cq, final ArrayDeque<ServerFunctionManager.QueuedCommand> arrayDeque, final int integer) throws CommandSyntaxException {
            sy.getDispatcher().execute(new ParseResults(this.parse.getContext().withSource(cq), 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 cn) {
            this.function = new CacheableFunction(cn);
        }
        
        @Override
        public void execute(final ServerFunctionManager sy, final CommandSourceStack cq, final ArrayDeque<ServerFunctionManager.QueuedCommand> arrayDeque, final int integer) {
            final Entry[] arr6;
            final int integer2;
            final int integer3;
            int integer4;
            this.function.get(sy).ifPresent(cn -> {
                arr6 = cn.getEntries();
                integer2 = integer - arrayDeque.size();
                integer3 = Math.min(arr6.length, integer2);
                for (integer4 = integer3 - 1; integer4 >= 0; --integer4) {
                    arrayDeque.addFirst(new ServerFunctionManager.QueuedCommand(sy, cq, 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 sm) {
            this.function = Optional.<CommandFunction>empty();
            this.id = sm;
        }
        
        public CacheableFunction(final CommandFunction cn) {
            this.function = Optional.<CommandFunction>empty();
            this.resolved = true;
            this.id = null;
            this.function = Optional.<CommandFunction>of(cn);
        }
        
        public Optional<CommandFunction> get(final ServerFunctionManager sy) {
            if (!this.resolved) {
                if (this.id != null) {
                    this.function = sy.get(this.id);
                }
                this.resolved = true;
            }
            return this.function;
        }
        
        @Nullable
        public ResourceLocation getId() {
            return this.function.<ResourceLocation>map(cn -> cn.id).orElse(this.id);
        }
        
        static {
            NONE = new CacheableFunction((ResourceLocation)null);
        }
    }
    
    public interface Entry {
        void execute(final ServerFunctionManager sy, final CommandSourceStack cq, final ArrayDeque<ServerFunctionManager.QueuedCommand> arrayDeque, final int integer) throws CommandSyntaxException;
    }
}
