package net.minecraft.server.commands.data;

import java.util.stream.Collector;
import com.google.common.collect.ImmutableList;
import net.minecraft.network.chat.TranslatableComponent;
import com.mojang.brigadier.Message;
import java.util.Collections;
import net.minecraft.nbt.StringTag;
import net.minecraft.util.Mth;
import net.minecraft.nbt.NumericTag;
import com.mojang.brigadier.context.CommandContext;
import net.minecraft.commands.arguments.NbtTagArgument;
import java.util.function.BiConsumer;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.nbt.CollectionTag;
import net.minecraft.nbt.ListTag;
import java.util.Collection;
import java.util.Iterator;
import java.util.function.Supplier;
import net.minecraft.nbt.CompoundTag;
import com.google.common.collect.Iterables;
import net.minecraft.nbt.Tag;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.arguments.DoubleArgumentType;
import net.minecraft.commands.arguments.NbtPathArgument;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.mojang.brigadier.arguments.ArgumentType;
import net.minecraft.commands.arguments.CompoundTagArgument;
import net.minecraft.commands.Commands;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import net.minecraft.commands.CommandSourceStack;
import com.mojang.brigadier.CommandDispatcher;
import java.util.function.Function;
import java.util.List;
import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;

public class DataCommands {
    private static final SimpleCommandExceptionType ERROR_MERGE_UNCHANGED;
    private static final DynamicCommandExceptionType ERROR_GET_NOT_NUMBER;
    private static final DynamicCommandExceptionType ERROR_GET_NON_EXISTENT;
    private static final SimpleCommandExceptionType ERROR_MULTIPLE_TAGS;
    private static final DynamicCommandExceptionType ERROR_EXPECTED_LIST;
    private static final DynamicCommandExceptionType ERROR_EXPECTED_OBJECT;
    private static final DynamicCommandExceptionType ERROR_INVALID_INDEX;
    public static final List<Function<String, DataProvider>> ALL_PROVIDERS;
    public static final List<DataProvider> TARGET_PROVIDERS;
    public static final List<DataProvider> SOURCE_PROVIDERS;
    
    public static void register(final CommandDispatcher<CommandSourceStack> commandDispatcher) {
        final LiteralArgumentBuilder<CommandSourceStack> literalArgumentBuilder2 = (LiteralArgumentBuilder<CommandSourceStack>)Commands.literal("data").requires(cq -> cq.hasPermission(2));
        for (final DataProvider c4 : DataCommands.TARGET_PROVIDERS) {
            final Object o;
            final int integer5;
            final Collection<Tag> collection5;
            int integer6;
            final Iterator<Tag> iterator2;
            Tag kj8;
            CompoundTag jt2;
            CompoundTag jt3;
            final Iterator<Tag> iterator3;
            Tag kj9;
            ((LiteralArgumentBuilder)((LiteralArgumentBuilder)((LiteralArgumentBuilder)literalArgumentBuilder2.then((ArgumentBuilder)c4.wrap(Commands.literal("merge"), argumentBuilder -> argumentBuilder.then(Commands.argument("nbt", (com.mojang.brigadier.arguments.ArgumentType<Object>)CompoundTagArgument.compoundTag()).executes(commandContext -> mergeData((CommandSourceStack)commandContext.getSource(), c4.access((CommandContext<CommandSourceStack>)commandContext), CompoundTagArgument.getCompoundTag((com.mojang.brigadier.context.CommandContext<Object>)commandContext, "nbt"))))))).then((ArgumentBuilder)c4.wrap(Commands.literal("get"), argumentBuilder -> argumentBuilder.executes(commandContext -> getData((CommandSourceStack)commandContext.getSource(), ((DataProvider)o).access((CommandContext<CommandSourceStack>)commandContext))).then(((RequiredArgumentBuilder)Commands.argument("path", (com.mojang.brigadier.arguments.ArgumentType<Object>)NbtPathArgument.nbtPath()).executes(commandContext -> getData((CommandSourceStack)commandContext.getSource(), ((DataProvider)o).access((CommandContext<CommandSourceStack>)commandContext), NbtPathArgument.getPath((CommandContext<CommandSourceStack>)commandContext, "path")))).then(Commands.argument("scale", (com.mojang.brigadier.arguments.ArgumentType<Object>)DoubleArgumentType.doubleArg()).executes(commandContext -> getNumeric((CommandSourceStack)commandContext.getSource(), ((DataProvider)o).access((CommandContext<CommandSourceStack>)commandContext), NbtPathArgument.getPath((CommandContext<CommandSourceStack>)commandContext, "path"), DoubleArgumentType.getDouble(commandContext, "scale")))))))).then((ArgumentBuilder)c4.wrap(Commands.literal("remove"), argumentBuilder -> argumentBuilder.then(Commands.argument("path", (com.mojang.brigadier.arguments.ArgumentType<Object>)NbtPathArgument.nbtPath()).executes(commandContext -> removeData((CommandSourceStack)commandContext.getSource(), c4.access((CommandContext<CommandSourceStack>)commandContext), NbtPathArgument.getPath((CommandContext<CommandSourceStack>)commandContext, "path"))))))).then((ArgumentBuilder)decorateModification((argumentBuilder, b) -> argumentBuilder.then(Commands.literal("insert").then(Commands.argument("index", (com.mojang.brigadier.arguments.ArgumentType<Object>)IntegerArgumentType.integer()).then((ArgumentBuilder)b.create((commandContext, jt, h, list) -> {
                integer5 = IntegerArgumentType.getInteger(commandContext, "index");
                return insertAtIndex(integer5, jt, h, list);
            })))).then(Commands.literal("prepend").then((ArgumentBuilder)b.create((commandContext, jt, h, list) -> insertAtIndex(0, jt, h, list)))).then(Commands.literal("append").then((ArgumentBuilder)b.create((commandContext, jt, h, list) -> insertAtIndex(-1, jt, h, list)))).then(Commands.literal("set").then((ArgumentBuilder)b.create((commandContext, jt, h, list) -> h.set(jt, (Tag)Iterables.<Tag>getLast(list)::copy)))).then(Commands.literal("merge").then((ArgumentBuilder)b.create((commandContext, jt, h, list) -> {
                collection5 = h.getOrCreate(jt, (Supplier<Tag>)CompoundTag::new);
                integer6 = 0;
                collection5.iterator();
                while (iterator2.hasNext()) {
                    kj8 = iterator2.next();
                    if (!(kj8 instanceof CompoundTag)) {
                        throw DataCommands.ERROR_EXPECTED_OBJECT.create(kj8);
                    }
                    else {
                        jt2 = (CompoundTag)kj8;
                        jt3 = jt2.copy();
                        list.iterator();
                        while (iterator3.hasNext()) {
                            kj9 = iterator3.next();
                            if (!(kj9 instanceof CompoundTag)) {
                                throw DataCommands.ERROR_EXPECTED_OBJECT.create(kj9);
                            }
                            else {
                                jt2.merge((CompoundTag)kj9);
                            }
                        }
                        integer6 += (jt3.equals(jt2) ? 0 : 1);
                    }
                }
                return integer6;
            })))));
        }
        commandDispatcher.register((LiteralArgumentBuilder)literalArgumentBuilder2);
    }
    
    private static int insertAtIndex(final int integer, final CompoundTag jt, final NbtPathArgument.NbtPath h, final List<Tag> list) throws CommandSyntaxException {
        final Collection<Tag> collection5 = h.getOrCreate(jt, (Supplier<Tag>)ListTag::new);
        int integer2 = 0;
        for (final Tag kj8 : collection5) {
            if (!(kj8 instanceof CollectionTag)) {
                throw DataCommands.ERROR_EXPECTED_LIST.create(kj8);
            }
            boolean boolean9 = false;
            final CollectionTag<?> js10 = kj8;
            int integer3 = (integer < 0) ? (js10.size() + integer + 1) : integer;
            for (final Tag kj9 : list) {
                try {
                    if (!js10.addTag(integer3, kj9.copy())) {
                        continue;
                    }
                    ++integer3;
                    boolean9 = true;
                }
                catch (IndexOutOfBoundsException indexOutOfBoundsException14) {
                    throw DataCommands.ERROR_INVALID_INDEX.create(integer3);
                }
            }
            integer2 += (boolean9 ? 1 : 0);
        }
        return integer2;
    }
    
    private static ArgumentBuilder<CommandSourceStack, ?> decorateModification(final BiConsumer<ArgumentBuilder<CommandSourceStack, ?>, DataManipulatorDecorator> biConsumer) {
        final LiteralArgumentBuilder<CommandSourceStack> literalArgumentBuilder2 = Commands.literal("modify");
        for (final DataProvider c4 : DataCommands.TARGET_PROVIDERS) {
            final ArgumentBuilder<CommandSourceStack, ?> argumentBuilder2;
            final Iterator<DataProvider> iterator2;
            DataProvider c5;
            final DataProvider dataProvider;
            final Object o;
            final Object o2;
            final Object o3;
            c4.wrap(literalArgumentBuilder2, argumentBuilder -> {
                argumentBuilder2 = Commands.argument("targetPath", (com.mojang.brigadier.arguments.ArgumentType<Object>)NbtPathArgument.nbtPath());
                DataCommands.SOURCE_PROVIDERS.iterator();
                while (iterator2.hasNext()) {
                    c5 = iterator2.next();
                    biConsumer.accept(argumentBuilder2, a -> dataProvider.wrap(Commands.literal("from"), argumentBuilder -> argumentBuilder.executes(commandContext -> {
                        final List<Tag> list5 = Collections.singletonList(((DataProvider)o).access((CommandContext<CommandSourceStack>)commandContext).getData());
                        return manipulateData((CommandContext<CommandSourceStack>)commandContext, o2, a, list5);
                    }).then(Commands.argument("sourcePath", (com.mojang.brigadier.arguments.ArgumentType<Object>)NbtPathArgument.nbtPath()).executes(commandContext -> {
                        final DataAccessor vw5 = ((DataProvider)o).access((CommandContext<CommandSourceStack>)commandContext);
                        final NbtPathArgument.NbtPath h6 = NbtPathArgument.getPath((CommandContext<CommandSourceStack>)commandContext, "sourcePath");
                        final List<Tag> list7 = h6.get(vw5.getData());
                        return manipulateData((CommandContext<CommandSourceStack>)commandContext, o2, a, list7);
                    }))));
                }
                biConsumer.accept(argumentBuilder2, a -> (LiteralArgumentBuilder)Commands.literal("value").then(Commands.argument("value", (com.mojang.brigadier.arguments.ArgumentType<Object>)NbtTagArgument.nbtTag()).executes(commandContext -> {
                    final List<Tag> list4 = Collections.<Tag>singletonList(NbtTagArgument.getNbtTag((com.mojang.brigadier.context.CommandContext<Object>)commandContext, "value"));
                    return manipulateData((CommandContext<CommandSourceStack>)commandContext, o3, a, list4);
                })));
                return argumentBuilder.then((ArgumentBuilder)argumentBuilder2);
            });
        }
        return literalArgumentBuilder2;
    }
    
    private static int manipulateData(final CommandContext<CommandSourceStack> commandContext, final DataProvider c, final DataManipulator a, final List<Tag> list) throws CommandSyntaxException {
        final DataAccessor vw5 = c.access(commandContext);
        final NbtPathArgument.NbtPath h6 = NbtPathArgument.getPath(commandContext, "targetPath");
        final CompoundTag jt7 = vw5.getData();
        final int integer8 = a.modify(commandContext, jt7, h6, list);
        if (integer8 == 0) {
            throw DataCommands.ERROR_MERGE_UNCHANGED.create();
        }
        vw5.setData(jt7);
        ((CommandSourceStack)commandContext.getSource()).sendSuccess(vw5.getModifiedSuccess(), true);
        return integer8;
    }
    
    private static int removeData(final CommandSourceStack cq, final DataAccessor vw, final NbtPathArgument.NbtPath h) throws CommandSyntaxException {
        final CompoundTag jt4 = vw.getData();
        final int integer5 = h.remove(jt4);
        if (integer5 == 0) {
            throw DataCommands.ERROR_MERGE_UNCHANGED.create();
        }
        vw.setData(jt4);
        cq.sendSuccess(vw.getModifiedSuccess(), true);
        return integer5;
    }
    
    private static Tag getSingleTag(final NbtPathArgument.NbtPath h, final DataAccessor vw) throws CommandSyntaxException {
        final Collection<Tag> collection3 = h.get(vw.getData());
        final Iterator<Tag> iterator4 = collection3.iterator();
        final Tag kj5 = iterator4.next();
        if (iterator4.hasNext()) {
            throw DataCommands.ERROR_MULTIPLE_TAGS.create();
        }
        return kj5;
    }
    
    private static int getData(final CommandSourceStack cq, final DataAccessor vw, final NbtPathArgument.NbtPath h) throws CommandSyntaxException {
        final Tag kj4 = getSingleTag(h, vw);
        int integer5;
        if (kj4 instanceof NumericTag) {
            integer5 = Mth.floor(((NumericTag)kj4).getAsDouble());
        }
        else if (kj4 instanceof CollectionTag) {
            integer5 = ((CollectionTag)kj4).size();
        }
        else if (kj4 instanceof CompoundTag) {
            integer5 = ((CompoundTag)kj4).size();
        }
        else {
            if (!(kj4 instanceof StringTag)) {
                throw DataCommands.ERROR_GET_NON_EXISTENT.create(h.toString());
            }
            integer5 = kj4.getAsString().length();
        }
        cq.sendSuccess(vw.getPrintSuccess(kj4), false);
        return integer5;
    }
    
    private static int getNumeric(final CommandSourceStack cq, final DataAccessor vw, final NbtPathArgument.NbtPath h, final double double4) throws CommandSyntaxException {
        final Tag kj6 = getSingleTag(h, vw);
        if (!(kj6 instanceof NumericTag)) {
            throw DataCommands.ERROR_GET_NOT_NUMBER.create(h.toString());
        }
        final int integer7 = Mth.floor(((NumericTag)kj6).getAsDouble() * double4);
        cq.sendSuccess(vw.getPrintSuccess(h, double4, integer7), false);
        return integer7;
    }
    
    private static int getData(final CommandSourceStack cq, final DataAccessor vw) throws CommandSyntaxException {
        cq.sendSuccess(vw.getPrintSuccess(vw.getData()), false);
        return 1;
    }
    
    private static int mergeData(final CommandSourceStack cq, final DataAccessor vw, final CompoundTag jt) throws CommandSyntaxException {
        final CompoundTag jt2 = vw.getData();
        final CompoundTag jt3 = jt2.copy().merge(jt);
        if (jt2.equals(jt3)) {
            throw DataCommands.ERROR_MERGE_UNCHANGED.create();
        }
        vw.setData(jt3);
        cq.sendSuccess(vw.getModifiedSuccess(), true);
        return 1;
    }
    
    static {
        ERROR_MERGE_UNCHANGED = new SimpleCommandExceptionType((Message)new TranslatableComponent("commands.data.merge.failed", new Object[0]));
        final TranslatableComponent translatableComponent;
        ERROR_GET_NOT_NUMBER = new DynamicCommandExceptionType(object -> {
            new TranslatableComponent("commands.data.get.invalid", new Object[] { object });
            return translatableComponent;
        });
        final TranslatableComponent translatableComponent2;
        ERROR_GET_NON_EXISTENT = new DynamicCommandExceptionType(object -> {
            new TranslatableComponent("commands.data.get.unknown", new Object[] { object });
            return translatableComponent2;
        });
        ERROR_MULTIPLE_TAGS = new SimpleCommandExceptionType((Message)new TranslatableComponent("commands.data.get.multiple", new Object[0]));
        final TranslatableComponent translatableComponent3;
        ERROR_EXPECTED_LIST = new DynamicCommandExceptionType(object -> {
            new TranslatableComponent("commands.data.modify.expected_list", new Object[] { object });
            return translatableComponent3;
        });
        final TranslatableComponent translatableComponent4;
        ERROR_EXPECTED_OBJECT = new DynamicCommandExceptionType(object -> {
            new TranslatableComponent("commands.data.modify.expected_object", new Object[] { object });
            return translatableComponent4;
        });
        final TranslatableComponent translatableComponent5;
        ERROR_INVALID_INDEX = new DynamicCommandExceptionType(object -> {
            new TranslatableComponent("commands.data.modify.invalid_index", new Object[] { object });
            return translatableComponent5;
        });
        ALL_PROVIDERS = ImmutableList.<Function<String, DataProvider>>of(EntityDataAccessor.PROVIDER, BlockDataAccessor.PROVIDER, StorageDataAccessor.PROVIDER);
        TARGET_PROVIDERS = DataCommands.ALL_PROVIDERS.stream().map(function -> function.apply("target")).collect(ImmutableList.toImmutableList());
        SOURCE_PROVIDERS = DataCommands.ALL_PROVIDERS.stream().map(function -> function.apply("source")).collect(ImmutableList.toImmutableList());
    }
    
    public interface DataProvider {
        DataAccessor access(final CommandContext<CommandSourceStack> commandContext) throws CommandSyntaxException;
        
        ArgumentBuilder<CommandSourceStack, ?> wrap(final ArgumentBuilder<CommandSourceStack, ?> argumentBuilder, final Function<ArgumentBuilder<CommandSourceStack, ?>, ArgumentBuilder<CommandSourceStack, ?>> function);
    }
    
    interface DataManipulatorDecorator {
        ArgumentBuilder<CommandSourceStack, ?> create(final DataManipulator a);
    }
    
    interface DataManipulator {
        int modify(final CommandContext<CommandSourceStack> commandContext, final CompoundTag jt, final NbtPathArgument.NbtPath h, final List<Tag> list) throws CommandSyntaxException;
    }
}
