package net.minecraft.advancements.critereon;

import com.google.gson.JsonSyntaxException;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.GsonHelper;
import net.minecraft.core.Registry;
import net.minecraft.world.level.levelgen.feature.Feature;
import com.google.gson.JsonObject;
import com.google.gson.JsonNull;
import com.google.gson.JsonElement;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.dimension.DimensionType;
import net.minecraft.world.level.levelgen.feature.StructureFeature;
import javax.annotation.Nullable;
import net.minecraft.world.level.biome.Biome;

public class LocationPredicate {
    public static final LocationPredicate ANY;
    private final MinMaxBounds.Floats x;
    private final MinMaxBounds.Floats y;
    private final MinMaxBounds.Floats z;
    @Nullable
    private final Biome biome;
    @Nullable
    private final StructureFeature<?> feature;
    @Nullable
    private final DimensionType dimension;
    private final LightPredicate light;
    private final BlockPredicate block;
    private final FluidPredicate fluid;
    
    public LocationPredicate(final MinMaxBounds.Floats c1, final MinMaxBounds.Floats c2, final MinMaxBounds.Floats c3, @Nullable final Biome bkt, @Nullable final StructureFeature<?> cfl, @Nullable final DimensionType cbi, final LightPredicate bo, final BlockPredicate aj, final FluidPredicate bf) {
        this.x = c1;
        this.y = c2;
        this.z = c3;
        this.biome = bkt;
        this.feature = cfl;
        this.dimension = cbi;
        this.light = bo;
        this.block = aj;
        this.fluid = bf;
    }
    
    public static LocationPredicate inBiome(final Biome bkt) {
        return new LocationPredicate(MinMaxBounds.Floats.ANY, MinMaxBounds.Floats.ANY, MinMaxBounds.Floats.ANY, bkt, null, null, LightPredicate.ANY, BlockPredicate.ANY, FluidPredicate.ANY);
    }
    
    public static LocationPredicate inDimension(final DimensionType cbi) {
        return new LocationPredicate(MinMaxBounds.Floats.ANY, MinMaxBounds.Floats.ANY, MinMaxBounds.Floats.ANY, null, null, cbi, LightPredicate.ANY, BlockPredicate.ANY, FluidPredicate.ANY);
    }
    
    public static LocationPredicate inFeature(final StructureFeature<?> cfl) {
        return new LocationPredicate(MinMaxBounds.Floats.ANY, MinMaxBounds.Floats.ANY, MinMaxBounds.Floats.ANY, null, cfl, null, LightPredicate.ANY, BlockPredicate.ANY, FluidPredicate.ANY);
    }
    
    public boolean matches(final ServerLevel xd, final double double2, final double double3, final double double4) {
        return this.matches(xd, (float)double2, (float)double3, (float)double4);
    }
    
    public boolean matches(final ServerLevel xd, final float float2, final float float3, final float float4) {
        if (!this.x.matches(float2)) {
            return false;
        }
        if (!this.y.matches(float3)) {
            return false;
        }
        if (!this.z.matches(float4)) {
            return false;
        }
        if (this.dimension != null && this.dimension != xd.dimension.getType()) {
            return false;
        }
        final BlockPos fk6 = new BlockPos(float2, float3, float4);
        final boolean boolean7 = xd.isLoaded(fk6);
        return (this.biome == null || (boolean7 && this.biome == xd.getBiome(fk6))) && (this.feature == null || (boolean7 && this.feature.isInsideFeature(xd, fk6))) && this.light.matches(xd, fk6) && this.block.matches(xd, fk6) && this.fluid.matches(xd, fk6);
    }
    
    public JsonElement serializeToJson() {
        if (this == LocationPredicate.ANY) {
            return JsonNull.INSTANCE;
        }
        final JsonObject jsonObject2 = new JsonObject();
        if (!this.x.isAny() || !this.y.isAny() || !this.z.isAny()) {
            final JsonObject jsonObject3 = new JsonObject();
            jsonObject3.add("x", this.x.serializeToJson());
            jsonObject3.add("y", this.y.serializeToJson());
            jsonObject3.add("z", this.z.serializeToJson());
            jsonObject2.add("position", jsonObject3);
        }
        if (this.dimension != null) {
            jsonObject2.addProperty("dimension", DimensionType.getName(this.dimension).toString());
        }
        if (this.feature != null) {
            jsonObject2.addProperty("feature", Feature.STRUCTURES_REGISTRY.inverse().get(this.feature));
        }
        if (this.biome != null) {
            jsonObject2.addProperty("biome", Registry.BIOME.getKey(this.biome).toString());
        }
        jsonObject2.add("light", this.light.serializeToJson());
        jsonObject2.add("block", this.block.serializeToJson());
        jsonObject2.add("fluid", this.fluid.serializeToJson());
        return jsonObject2;
    }
    
    public static LocationPredicate fromJson(@Nullable final JsonElement jsonElement) {
        if (jsonElement == null || jsonElement.isJsonNull()) {
            return LocationPredicate.ANY;
        }
        final JsonObject jsonObject2 = GsonHelper.convertToJsonObject(jsonElement, "location");
        final JsonObject jsonObject3 = GsonHelper.getAsJsonObject(jsonObject2, "position", new JsonObject());
        final MinMaxBounds.Floats c4 = MinMaxBounds.Floats.fromJson(jsonObject3.get("x"));
        final MinMaxBounds.Floats c5 = MinMaxBounds.Floats.fromJson(jsonObject3.get("y"));
        final MinMaxBounds.Floats c6 = MinMaxBounds.Floats.fromJson(jsonObject3.get("z"));
        final DimensionType cbi7 = jsonObject2.has("dimension") ? DimensionType.getByName(new ResourceLocation(GsonHelper.getAsString(jsonObject2, "dimension"))) : null;
        final StructureFeature<?> cfl8 = jsonObject2.has("feature") ? Feature.STRUCTURES_REGISTRY.get(GsonHelper.getAsString(jsonObject2, "feature")) : null;
        Biome bkt9 = null;
        if (jsonObject2.has("biome")) {
            final ResourceLocation sm10 = new ResourceLocation(GsonHelper.getAsString(jsonObject2, "biome"));
            final Object o;
            final Object obj;
            bkt9 = Registry.BIOME.getOptional(sm10).<Throwable>orElseThrow(() -> {
                new JsonSyntaxException("Unknown biome '" + obj + "'");
                return o;
            });
        }
        final LightPredicate bo10 = LightPredicate.fromJson(jsonObject2.get("light"));
        final BlockPredicate aj11 = BlockPredicate.fromJson(jsonObject2.get("block"));
        final FluidPredicate bf12 = FluidPredicate.fromJson(jsonObject2.get("fluid"));
        return new LocationPredicate(c4, c5, c6, bkt9, cfl8, cbi7, bo10, aj11, bf12);
    }
    
    static {
        ANY = new LocationPredicate(MinMaxBounds.Floats.ANY, MinMaxBounds.Floats.ANY, MinMaxBounds.Floats.ANY, null, null, null, LightPredicate.ANY, BlockPredicate.ANY, FluidPredicate.ANY);
    }
    
    public static class Builder {
        private MinMaxBounds.Floats x;
        private MinMaxBounds.Floats y;
        private MinMaxBounds.Floats z;
        @Nullable
        private Biome biome;
        @Nullable
        private StructureFeature<?> feature;
        @Nullable
        private DimensionType dimension;
        private LightPredicate light;
        private BlockPredicate block;
        private FluidPredicate fluid;
        
        public Builder() {
            this.x = MinMaxBounds.Floats.ANY;
            this.y = MinMaxBounds.Floats.ANY;
            this.z = MinMaxBounds.Floats.ANY;
            this.light = LightPredicate.ANY;
            this.block = BlockPredicate.ANY;
            this.fluid = FluidPredicate.ANY;
        }
        
        public static Builder location() {
            return new Builder();
        }
        
        public Builder setBiome(@Nullable final Biome bkt) {
            this.biome = bkt;
            return this;
        }
        
        public LocationPredicate build() {
            return new LocationPredicate(this.x, this.y, this.z, this.biome, this.feature, this.dimension, this.light, this.block, this.fluid);
        }
    }
}
