package net.minecraft.commands.synchronization;

import com.google.common.collect.Maps;
import org.apache.logging.log4j.LogManager;
import java.util.Collection;
import java.util.Iterator;
import com.google.gson.JsonArray;
import com.mojang.brigadier.tree.ArgumentCommandNode;
import com.mojang.brigadier.tree.LiteralCommandNode;
import com.mojang.brigadier.tree.RootCommandNode;
import com.mojang.brigadier.tree.CommandNode;
import com.mojang.brigadier.CommandDispatcher;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import net.minecraft.network.FriendlyByteBuf;
import javax.annotation.Nullable;
import net.minecraft.gametest.framework.TestClassNameArgument;
import net.minecraft.gametest.framework.TestFunctionArgument;
import net.minecraft.SharedConstants;
import net.minecraft.commands.arguments.UuidArgument;
import net.minecraft.commands.arguments.TimeArgument;
import net.minecraft.commands.arguments.DimensionArgument;
import net.minecraft.commands.arguments.EntitySummonArgument;
import net.minecraft.commands.arguments.ItemEnchantmentArgument;
import net.minecraft.commands.arguments.RangeArgument;
import net.minecraft.commands.arguments.EntityAnchorArgument;
import net.minecraft.commands.arguments.item.FunctionArgument;
import net.minecraft.commands.arguments.MobEffectArgument;
import net.minecraft.commands.arguments.ResourceLocationArgument;
import net.minecraft.commands.arguments.SlotArgument;
import net.minecraft.commands.arguments.TeamArgument;
import net.minecraft.commands.arguments.coordinates.SwizzleArgument;
import net.minecraft.commands.arguments.ScoreHolderArgument;
import net.minecraft.commands.arguments.ScoreboardSlotArgument;
import net.minecraft.commands.arguments.coordinates.RotationArgument;
import net.minecraft.commands.arguments.ParticleArgument;
import net.minecraft.commands.arguments.OperationArgument;
import net.minecraft.commands.arguments.ObjectiveCriteriaArgument;
import net.minecraft.commands.arguments.ObjectiveArgument;
import net.minecraft.commands.arguments.NbtPathArgument;
import net.minecraft.commands.arguments.NbtTagArgument;
import net.minecraft.commands.arguments.CompoundTagArgument;
import net.minecraft.commands.arguments.MessageArgument;
import net.minecraft.commands.arguments.ComponentArgument;
import net.minecraft.commands.arguments.ColorArgument;
import net.minecraft.commands.arguments.item.ItemPredicateArgument;
import net.minecraft.commands.arguments.item.ItemArgument;
import net.minecraft.commands.arguments.blocks.BlockPredicateArgument;
import net.minecraft.commands.arguments.blocks.BlockStateArgument;
import net.minecraft.commands.arguments.coordinates.Vec2Argument;
import net.minecraft.commands.arguments.coordinates.Vec3Argument;
import net.minecraft.commands.arguments.coordinates.ColumnPosArgument;
import net.minecraft.commands.arguments.coordinates.BlockPosArgument;
import java.util.function.Supplier;
import net.minecraft.commands.arguments.GameProfileArgument;
import net.minecraft.commands.arguments.EntityArgument;
import net.minecraft.commands.synchronization.brigadier.BrigadierArgumentSerializers;
import com.mojang.brigadier.arguments.ArgumentType;
import net.minecraft.resources.ResourceLocation;
import java.util.Map;
import org.apache.logging.log4j.Logger;

public class ArgumentTypes {
    private static final Logger LOGGER;
    private static final Map<Class<?>, Entry<?>> BY_CLASS;
    private static final Map<ResourceLocation, Entry<?>> BY_NAME;
    
    public static <T extends ArgumentType<?>> void register(final String string, final Class<T> class2, final ArgumentSerializer<T> fg) {
        final ResourceLocation uh4 = new ResourceLocation(string);
        if (ArgumentTypes.BY_CLASS.containsKey(class2)) {
            throw new IllegalArgumentException("Class " + class2.getName() + " already has a serializer!");
        }
        if (ArgumentTypes.BY_NAME.containsKey(uh4)) {
            throw new IllegalArgumentException("'" + uh4 + "' is already a registered serializer!");
        }
        final Entry<T> a5 = new Entry<T>((Class)class2, (ArgumentSerializer)fg, uh4);
        ArgumentTypes.BY_CLASS.put(class2, a5);
        ArgumentTypes.BY_NAME.put(uh4, a5);
    }
    
    public static void bootStrap() {
        BrigadierArgumentSerializers.bootstrap();
        ArgumentTypes.<ArgumentType>register("entity", (Class<ArgumentType>)EntityArgument.class, (ArgumentSerializer<ArgumentType>)new EntityArgument.Serializer());
        ArgumentTypes.<ArgumentType>register("game_profile", (Class<ArgumentType>)GameProfileArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)GameProfileArgument::gameProfile));
        ArgumentTypes.<ArgumentType>register("block_pos", (Class<ArgumentType>)BlockPosArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)BlockPosArgument::blockPos));
        ArgumentTypes.<ArgumentType>register("column_pos", (Class<ArgumentType>)ColumnPosArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)ColumnPosArgument::columnPos));
        ArgumentTypes.<ArgumentType>register("vec3", (Class<ArgumentType>)Vec3Argument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)Vec3Argument::vec3));
        ArgumentTypes.<ArgumentType>register("vec2", (Class<ArgumentType>)Vec2Argument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)Vec2Argument::vec2));
        ArgumentTypes.<ArgumentType>register("block_state", (Class<ArgumentType>)BlockStateArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)BlockStateArgument::block));
        ArgumentTypes.<ArgumentType>register("block_predicate", (Class<ArgumentType>)BlockPredicateArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)BlockPredicateArgument::blockPredicate));
        ArgumentTypes.<ArgumentType>register("item_stack", (Class<ArgumentType>)ItemArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)ItemArgument::item));
        ArgumentTypes.<ArgumentType>register("item_predicate", (Class<ArgumentType>)ItemPredicateArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)ItemPredicateArgument::itemPredicate));
        ArgumentTypes.<ArgumentType>register("color", (Class<ArgumentType>)ColorArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)ColorArgument::color));
        ArgumentTypes.<ArgumentType>register("component", (Class<ArgumentType>)ComponentArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)ComponentArgument::textComponent));
        ArgumentTypes.<ArgumentType>register("message", (Class<ArgumentType>)MessageArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)MessageArgument::message));
        ArgumentTypes.<ArgumentType>register("nbt_compound_tag", (Class<ArgumentType>)CompoundTagArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)CompoundTagArgument::compoundTag));
        ArgumentTypes.<ArgumentType>register("nbt_tag", (Class<ArgumentType>)NbtTagArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)NbtTagArgument::nbtTag));
        ArgumentTypes.<ArgumentType>register("nbt_path", (Class<ArgumentType>)NbtPathArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)NbtPathArgument::nbtPath));
        ArgumentTypes.<ArgumentType>register("objective", (Class<ArgumentType>)ObjectiveArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)ObjectiveArgument::objective));
        ArgumentTypes.<ArgumentType>register("objective_criteria", (Class<ArgumentType>)ObjectiveCriteriaArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)ObjectiveCriteriaArgument::criteria));
        ArgumentTypes.<ArgumentType>register("operation", (Class<ArgumentType>)OperationArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)OperationArgument::operation));
        ArgumentTypes.<ArgumentType>register("particle", (Class<ArgumentType>)ParticleArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)ParticleArgument::particle));
        ArgumentTypes.<ArgumentType>register("rotation", (Class<ArgumentType>)RotationArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)RotationArgument::rotation));
        ArgumentTypes.<ArgumentType>register("scoreboard_slot", (Class<ArgumentType>)ScoreboardSlotArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)ScoreboardSlotArgument::displaySlot));
        ArgumentTypes.<ArgumentType>register("score_holder", (Class<ArgumentType>)ScoreHolderArgument.class, (ArgumentSerializer<ArgumentType>)new ScoreHolderArgument.Serializer());
        ArgumentTypes.<ArgumentType>register("swizzle", (Class<ArgumentType>)SwizzleArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)SwizzleArgument::swizzle));
        ArgumentTypes.<ArgumentType>register("team", (Class<ArgumentType>)TeamArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)TeamArgument::team));
        ArgumentTypes.<ArgumentType>register("item_slot", (Class<ArgumentType>)SlotArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)SlotArgument::slot));
        ArgumentTypes.<ArgumentType>register("resource_location", (Class<ArgumentType>)ResourceLocationArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)ResourceLocationArgument::id));
        ArgumentTypes.<ArgumentType>register("mob_effect", (Class<ArgumentType>)MobEffectArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)MobEffectArgument::effect));
        ArgumentTypes.<ArgumentType>register("function", (Class<ArgumentType>)FunctionArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)FunctionArgument::functions));
        ArgumentTypes.<ArgumentType>register("entity_anchor", (Class<ArgumentType>)EntityAnchorArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)EntityAnchorArgument::anchor));
        ArgumentTypes.<ArgumentType>register("int_range", (Class<ArgumentType>)RangeArgument.Ints.class, (ArgumentSerializer<ArgumentType>)new RangeArgument.Ints.Serializer());
        ArgumentTypes.<ArgumentType>register("float_range", (Class<ArgumentType>)RangeArgument.Floats.class, (ArgumentSerializer<ArgumentType>)new RangeArgument.Floats.Serializer());
        ArgumentTypes.<ArgumentType>register("item_enchantment", (Class<ArgumentType>)ItemEnchantmentArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)ItemEnchantmentArgument::enchantment));
        ArgumentTypes.<ArgumentType>register("entity_summon", (Class<ArgumentType>)EntitySummonArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)EntitySummonArgument::id));
        ArgumentTypes.<ArgumentType>register("dimension", (Class<ArgumentType>)DimensionArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)DimensionArgument::dimension));
        ArgumentTypes.<ArgumentType>register("time", (Class<ArgumentType>)TimeArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)TimeArgument::time));
        ArgumentTypes.<ArgumentType>register("uuid", (Class<ArgumentType>)UuidArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)UuidArgument::uuid));
        if (SharedConstants.IS_RUNNING_IN_IDE) {
            ArgumentTypes.<ArgumentType>register("test_argument", (Class<ArgumentType>)TestFunctionArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)TestFunctionArgument::testFunctionArgument));
            ArgumentTypes.<ArgumentType>register("test_class", (Class<ArgumentType>)TestClassNameArgument.class, new EmptyArgumentSerializer<ArgumentType>((Supplier<ArgumentType>)TestClassNameArgument::testClassName));
        }
    }
    
    @Nullable
    private static Entry<?> get(final ResourceLocation uh) {
        return ArgumentTypes.BY_NAME.get(uh);
    }
    
    @Nullable
    private static Entry<?> get(final ArgumentType<?> argumentType) {
        return ArgumentTypes.BY_CLASS.get(argumentType.getClass());
    }
    
    public static <T extends ArgumentType<?>> void serialize(final FriendlyByteBuf mg, final T argumentType) {
        final Entry<T> a3 = (Entry<T>)get(argumentType);
        if (a3 == null) {
            ArgumentTypes.LOGGER.error("Could not serialize {} ({}) - will not be sent to client!", argumentType, argumentType.getClass());
            mg.writeResourceLocation(new ResourceLocation(""));
            return;
        }
        mg.writeResourceLocation(a3.name);
        a3.serializer.serializeToNetwork(argumentType, mg);
    }
    
    @Nullable
    public static ArgumentType<?> deserialize(final FriendlyByteBuf mg) {
        final ResourceLocation uh2 = mg.readResourceLocation();
        final Entry<?> a3 = get(uh2);
        if (a3 == null) {
            ArgumentTypes.LOGGER.error("Could not deserialize {}", uh2);
            return null;
        }
        return a3.serializer.deserializeFromNetwork(mg);
    }
    
    private static <T extends ArgumentType<?>> void serializeToJson(final JsonObject jsonObject, final T argumentType) {
        final Entry<T> a3 = (Entry<T>)get(argumentType);
        if (a3 == null) {
            ArgumentTypes.LOGGER.error("Could not serialize argument {} ({})!", argumentType, argumentType.getClass());
            jsonObject.addProperty("type", "unknown");
        }
        else {
            jsonObject.addProperty("type", "argument");
            jsonObject.addProperty("parser", a3.name.toString());
            final JsonObject jsonObject2 = new JsonObject();
            a3.serializer.serializeToJson(argumentType, jsonObject2);
            if (jsonObject2.size() > 0) {
                jsonObject.add("properties", jsonObject2);
            }
        }
    }
    
    public static <S> JsonObject serializeNodeToJson(final CommandDispatcher<S> commandDispatcher, final CommandNode<S> commandNode) {
        final JsonObject jsonObject3 = new JsonObject();
        if (commandNode instanceof RootCommandNode) {
            jsonObject3.addProperty("type", "root");
        }
        else if (commandNode instanceof LiteralCommandNode) {
            jsonObject3.addProperty("type", "literal");
        }
        else if (commandNode instanceof ArgumentCommandNode) {
            ArgumentTypes.<ArgumentType>serializeToJson(jsonObject3, ((ArgumentCommandNode)commandNode).getType());
        }
        else {
            ArgumentTypes.LOGGER.error("Could not serialize node {} ({})!", commandNode, commandNode.getClass());
            jsonObject3.addProperty("type", "unknown");
        }
        final JsonObject jsonObject4 = new JsonObject();
        for (final CommandNode<S> commandNode2 : commandNode.getChildren()) {
            jsonObject4.add(commandNode2.getName(), ArgumentTypes.serializeNodeToJson((com.mojang.brigadier.CommandDispatcher<Object>)commandDispatcher, (com.mojang.brigadier.tree.CommandNode<Object>)commandNode2));
        }
        if (jsonObject4.size() > 0) {
            jsonObject3.add("children", jsonObject4);
        }
        if (commandNode.getCommand() != null) {
            jsonObject3.addProperty("executable", true);
        }
        if (commandNode.getRedirect() != null) {
            final Collection<String> collection5 = (Collection<String>)commandDispatcher.getPath(commandNode.getRedirect());
            if (!collection5.isEmpty()) {
                final JsonArray jsonArray6 = new JsonArray();
                for (final String string8 : collection5) {
                    jsonArray6.add(string8);
                }
                jsonObject3.add("redirect", jsonArray6);
            }
        }
        return jsonObject3;
    }
    
    static {
        LOGGER = LogManager.getLogger();
        BY_CLASS = Maps.newHashMap();
        BY_NAME = Maps.newHashMap();
    }
    
    static class Entry<T extends ArgumentType<?>> {
        public final Class<T> clazz;
        public final ArgumentSerializer<T> serializer;
        public final ResourceLocation name;
        
        private Entry(final Class<T> class1, final ArgumentSerializer<T> fg, final ResourceLocation uh) {
            this.clazz = class1;
            this.serializer = fg;
            this.name = uh;
        }
    }
}
