package net.minecraft.world.level.levelgen.flat;

import net.minecraft.world.level.levelgen.placement.ChanceDecoratorConfiguration;
import net.minecraft.world.level.levelgen.placement.FeatureDecorator;
import net.minecraft.world.level.levelgen.feature.configurations.BlockStateConfiguration;
import org.apache.logging.log4j.LogManager;
import com.mojang.datafixers.kinds.Applicative;
import com.mojang.serialization.MapCodec;
import net.minecraft.util.Codecs;
import net.minecraft.Util;
import net.minecraft.core.Registry;
import java.util.function.Function;
import com.mojang.datafixers.kinds.App;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.world.level.levelgen.feature.configurations.MineshaftConfiguration;
import net.minecraft.world.level.biome.BiomeDefaultFeatures;
import java.util.HashMap;
import com.google.common.collect.Maps;
import net.minecraft.world.level.levelgen.feature.configurations.JigsawConfiguration;
import com.google.common.collect.ImmutableMap;
import net.minecraft.world.level.levelgen.feature.configurations.StrongholdConfiguration;
import java.util.Optional;
import net.minecraft.world.level.block.Blocks;
import java.util.Arrays;
import net.minecraft.world.level.levelgen.feature.configurations.LayerConfiguration;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.biome.Biomes;
import net.minecraft.world.level.levelgen.feature.configurations.StructureFeatureConfiguration;
import net.minecraft.world.level.levelgen.GenerationStep;
import java.util.Iterator;
import com.google.common.collect.Lists;
import java.util.Collection;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.biome.Biome;
import java.util.List;
import net.minecraft.world.level.levelgen.StructureSettings;
import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
import net.minecraft.world.level.levelgen.feature.StructureFeature;
import java.util.Map;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import com.mojang.serialization.Codec;
import org.apache.logging.log4j.Logger;

public class FlatLevelGeneratorSettings {
    private static final Logger LOGGER;
    public static final Codec<FlatLevelGeneratorSettings> CODEC;
    private static final ConfiguredFeature<?, ?> WATER_LAKE_COMPOSITE_FEATURE;
    private static final ConfiguredFeature<?, ?> LAVA_LAKE_COMPOSITE_FEATURE;
    private static final Map<StructureFeature<?>, ConfiguredStructureFeature<?, ?>> STRUCTURE_FEATURES;
    private final StructureSettings structureSettings;
    private final List<FlatLayerInfo> layersInfo;
    private Biome biome;
    private final BlockState[] layers;
    private boolean voidGen;
    private boolean decoration;
    private boolean addLakes;
    
    public FlatLevelGeneratorSettings(final StructureSettings ciw, final List<FlatLayerInfo> list, final boolean boolean3, final boolean boolean4, final Biome bre) {
        this(ciw);
        if (boolean3) {
            this.setAddLakes();
        }
        if (boolean4) {
            this.setDecoration();
        }
        this.layersInfo.addAll(list);
        this.updateLayers();
        this.biome = bre;
    }
    
    public FlatLevelGeneratorSettings(final StructureSettings ciw) {
        this.layersInfo = Lists.newArrayList();
        this.layers = new BlockState[256];
        this.decoration = false;
        this.addLakes = false;
        this.structureSettings = ciw;
    }
    
    public FlatLevelGeneratorSettings withStructureSettings(final StructureSettings ciw) {
        return this.withLayers(this.layersInfo, ciw);
    }
    
    public FlatLevelGeneratorSettings withLayers(final List<FlatLayerInfo> list, final StructureSettings ciw) {
        final FlatLevelGeneratorSettings cra4 = new FlatLevelGeneratorSettings(ciw);
        for (final FlatLayerInfo cqz6 : list) {
            cra4.layersInfo.add(new FlatLayerInfo(cqz6.getHeight(), cqz6.getBlockState().getBlock()));
            cra4.updateLayers();
        }
        cra4.setBiome(this.biome);
        if (this.decoration) {
            cra4.setDecoration();
        }
        if (this.addLakes) {
            cra4.setAddLakes();
        }
        return cra4;
    }
    
    public void setDecoration() {
        this.decoration = true;
    }
    
    public void setAddLakes() {
        this.addLakes = true;
    }
    
    public Biome getBiomeFromSettings() {
        final Biome bre2 = this.getBiome();
        final Biome bre3 = new Biome(new Biome.BiomeBuilder().surfaceBuilder(bre2.getSurfaceBuilder()).precipitation(bre2.getPrecipitation()).biomeCategory(bre2.getBiomeCategory()).depth(bre2.getDepth()).scale(bre2.getScale()).temperature(bre2.getTemperature()).downfall(bre2.getDownfall()).specialEffects(bre2.getSpecialEffects()).parent(bre2.getParent())) {};
        if (this.addLakes) {
            bre3.addFeature(GenerationStep.Decoration.LAKES, FlatLevelGeneratorSettings.WATER_LAKE_COMPOSITE_FEATURE);
            bre3.addFeature(GenerationStep.Decoration.LAKES, FlatLevelGeneratorSettings.LAVA_LAKE_COMPOSITE_FEATURE);
        }
        for (final Map.Entry<StructureFeature<?>, StructureFeatureConfiguration> entry5 : this.structureSettings.structureConfig().entrySet()) {
            bre3.addStructureStart(bre2.withBiomeConfig(FlatLevelGeneratorSettings.STRUCTURE_FEATURES.get(entry5.getKey())));
        }
        final boolean boolean4 = (!this.voidGen || bre2 == Biomes.THE_VOID) && this.decoration;
        if (boolean4) {
            final List<GenerationStep.Decoration> list5 = Lists.newArrayList();
            list5.add(GenerationStep.Decoration.UNDERGROUND_STRUCTURES);
            list5.add(GenerationStep.Decoration.SURFACE_STRUCTURES);
            for (final GenerationStep.Decoration b9 : GenerationStep.Decoration.values()) {
                if (!list5.contains(b9)) {
                    for (final ConfiguredFeature<?, ?> ckb11 : bre2.getFeaturesForStep(b9)) {
                        bre3.addFeature(b9, ckb11);
                    }
                }
            }
        }
        final BlockState[] arr5 = this.getLayers();
        for (int integer6 = 0; integer6 < arr5.length; ++integer6) {
            final BlockState cfj7 = arr5[integer6];
            if (cfj7 != null && !Heightmap.Types.MOTION_BLOCKING.isOpaque().test(cfj7)) {
                this.layers[integer6] = null;
                bre3.addFeature(GenerationStep.Decoration.TOP_LAYER_MODIFICATION, Feature.FILL_LAYER.configured(new LayerConfiguration(integer6, cfj7)));
            }
        }
        return bre3;
    }
    
    public StructureSettings structureSettings() {
        return this.structureSettings;
    }
    
    public Biome getBiome() {
        return this.biome;
    }
    
    public void setBiome(final Biome bre) {
        this.biome = bre;
    }
    
    public List<FlatLayerInfo> getLayersInfo() {
        return this.layersInfo;
    }
    
    public BlockState[] getLayers() {
        return this.layers;
    }
    
    public void updateLayers() {
        Arrays.fill(this.layers, 0, this.layers.length, null);
        int integer2 = 0;
        for (final FlatLayerInfo cqz4 : this.layersInfo) {
            cqz4.setStart(integer2);
            integer2 += cqz4.getHeight();
        }
        this.voidGen = true;
        for (final FlatLayerInfo cqz5 : this.layersInfo) {
            for (int integer3 = cqz5.getStart(); integer3 < cqz5.getStart() + cqz5.getHeight(); ++integer3) {
                final BlockState cfj5 = cqz5.getBlockState();
                if (!cfj5.is(Blocks.AIR)) {
                    this.voidGen = false;
                    this.layers[integer3] = cfj5;
                }
            }
        }
    }
    
    public static FlatLevelGeneratorSettings getDefault() {
        final StructureSettings ciw1 = new StructureSettings(Optional.<StrongholdConfiguration>of(StructureSettings.DEFAULT_STRONGHOLD), Maps.newHashMap(ImmutableMap.<StructureFeature<JigsawConfiguration>, StructureFeatureConfiguration>of(StructureFeature.VILLAGE, StructureSettings.DEFAULTS.get(StructureFeature.VILLAGE))));
        final FlatLevelGeneratorSettings cra2 = new FlatLevelGeneratorSettings(ciw1);
        cra2.setBiome(Biomes.PLAINS);
        cra2.getLayersInfo().add(new FlatLayerInfo(1, Blocks.BEDROCK));
        cra2.getLayersInfo().add(new FlatLayerInfo(2, Blocks.DIRT));
        cra2.getLayersInfo().add(new FlatLayerInfo(1, Blocks.GRASS_BLOCK));
        cra2.updateLayers();
        return cra2;
    }
    
    static {
        LOGGER = LogManager.getLogger();
        CODEC = RecordCodecBuilder.create(instance -> ((RecordCodecBuilder.Instance)instance).group((App)StructureSettings.CODEC.fieldOf("structures").forGetter((Function)FlatLevelGeneratorSettings::structureSettings), (App)FlatLayerInfo.CODEC.listOf().fieldOf("layers").forGetter((Function)FlatLevelGeneratorSettings::getLayersInfo), (App)Codec.BOOL.fieldOf("lakes").withDefault(false).forGetter(cra -> cra.addLakes), (App)Codec.BOOL.fieldOf("features").withDefault(false).forGetter(cra -> cra.decoration), (App)Codecs.withDefault((com.mojang.serialization.MapCodec<Object>)Registry.BIOME.fieldOf("biome"), Util.prefix("Unknown biome, defaulting to plains", FlatLevelGeneratorSettings.LOGGER::error), () -> Biomes.PLAINS).forGetter(cra -> cra.biome)).apply(instance, FlatLevelGeneratorSettings::new)).stable();
        WATER_LAKE_COMPOSITE_FEATURE = Feature.LAKE.configured(new BlockStateConfiguration(Blocks.WATER.defaultBlockState())).decorated(FeatureDecorator.WATER_LAKE.configured(new ChanceDecoratorConfiguration(4)));
        LAVA_LAKE_COMPOSITE_FEATURE = Feature.LAKE.configured(new BlockStateConfiguration(Blocks.LAVA.defaultBlockState())).decorated(FeatureDecorator.LAVA_LAKE.configured(new ChanceDecoratorConfiguration(80)));
        STRUCTURE_FEATURES = Util.<Map<StructureFeature<?>, ConfiguredStructureFeature<?, ?>>>make(Maps.newHashMap(), hashMap -> {
            hashMap.put(StructureFeature.MINESHAFT, BiomeDefaultFeatures.MINESHAFT);
            hashMap.put((StructureFeature<MineshaftConfiguration>)StructureFeature.VILLAGE, BiomeDefaultFeatures.VILLAGE_PLAINS);
            hashMap.put((StructureFeature<MineshaftConfiguration>)StructureFeature.STRONGHOLD, BiomeDefaultFeatures.STRONGHOLD);
            hashMap.put((StructureFeature<MineshaftConfiguration>)StructureFeature.SWAMP_HUT, BiomeDefaultFeatures.SWAMP_HUT);
            hashMap.put((StructureFeature<MineshaftConfiguration>)StructureFeature.DESERT_PYRAMID, BiomeDefaultFeatures.DESERT_PYRAMID);
            hashMap.put((StructureFeature<MineshaftConfiguration>)StructureFeature.JUNGLE_TEMPLE, BiomeDefaultFeatures.JUNGLE_TEMPLE);
            hashMap.put((StructureFeature<MineshaftConfiguration>)StructureFeature.IGLOO, BiomeDefaultFeatures.IGLOO);
            hashMap.put((StructureFeature<MineshaftConfiguration>)StructureFeature.OCEAN_RUIN, BiomeDefaultFeatures.OCEAN_RUIN_COLD);
            hashMap.put((StructureFeature<MineshaftConfiguration>)StructureFeature.SHIPWRECK, BiomeDefaultFeatures.SHIPWRECK);
            hashMap.put((StructureFeature<MineshaftConfiguration>)StructureFeature.OCEAN_MONUMENT, BiomeDefaultFeatures.OCEAN_MONUMENT);
            hashMap.put((StructureFeature<MineshaftConfiguration>)StructureFeature.END_CITY, BiomeDefaultFeatures.END_CITY);
            hashMap.put((StructureFeature<MineshaftConfiguration>)StructureFeature.WOODLAND_MANSION, BiomeDefaultFeatures.WOODLAND_MANSION);
            hashMap.put((StructureFeature<MineshaftConfiguration>)StructureFeature.NETHER_BRIDGE, BiomeDefaultFeatures.NETHER_BRIDGE);
            hashMap.put((StructureFeature<MineshaftConfiguration>)StructureFeature.PILLAGER_OUTPOST, BiomeDefaultFeatures.PILLAGER_OUTPOST);
            hashMap.put((StructureFeature<MineshaftConfiguration>)StructureFeature.RUINED_PORTAL, BiomeDefaultFeatures.RUINED_PORTAL_STANDARD);
            hashMap.put((StructureFeature<MineshaftConfiguration>)StructureFeature.BASTION_REMNANT, BiomeDefaultFeatures.BASTION_REMNANT);
        });
    }
}
