package net.minecraft.world.level.levelgen;

import org.apache.logging.log4j.LogManager;
import com.mojang.datafixers.kinds.Applicative;
import java.util.function.Function;
import com.mojang.datafixers.kinds.App;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import java.util.OptionalLong;
import com.google.gson.JsonElement;
import java.util.function.Consumer;
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
import com.mojang.serialization.DynamicOps;
import com.mojang.serialization.Dynamic;
import com.mojang.serialization.JsonOps;
import net.minecraft.util.GsonHelper;
import com.google.gson.JsonObject;
import java.util.Locale;
import java.util.Objects;
import com.google.common.base.MoreObjects;
import java.util.Properties;
import java.util.stream.Collector;
import net.minecraft.world.level.Level;
import com.google.common.collect.ImmutableSet;
import java.util.Iterator;
import net.minecraft.resources.ResourceKey;
import java.util.Map;
import net.minecraft.core.Registry;
import java.util.function.Supplier;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.biome.OverworldBiomeSource;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.dimension.DimensionType;
import java.util.Random;
import com.mojang.serialization.Lifecycle;
import com.mojang.serialization.DataResult;
import java.util.Optional;
import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.core.MappedRegistry;
import org.apache.logging.log4j.Logger;
import com.mojang.serialization.Codec;

public class WorldGenSettings {
    public static final Codec<WorldGenSettings> CODEC;
    private static final Logger LOGGER;
    private static final int DEMO_SEED;
    public static final WorldGenSettings DEMO_SETTINGS;
    private final long seed;
    private final boolean generateFeatures;
    private final boolean generateBonusChest;
    private final MappedRegistry<LevelStem> dimensions;
    private final Optional<String> legacyCustomOptions;
    
    private DataResult<WorldGenSettings> guardExperimental() {
        if (this.stable()) {
            return (DataResult<WorldGenSettings>)DataResult.success(this, Lifecycle.stable());
        }
        return (DataResult<WorldGenSettings>)DataResult.success(this);
    }
    
    private boolean stable() {
        return LevelStem.stable(this.seed, this.dimensions);
    }
    
    public WorldGenSettings(final long long1, final boolean boolean2, final boolean boolean3, final MappedRegistry<LevelStem> gh) {
        this(long1, boolean2, boolean3, gh, Optional.<String>empty());
    }
    
    private WorldGenSettings(final long long1, final boolean boolean2, final boolean boolean3, final MappedRegistry<LevelStem> gh, final Optional<String> optional) {
        this.seed = long1;
        this.generateFeatures = boolean2;
        this.generateBonusChest = boolean3;
        this.dimensions = gh;
        this.legacyCustomOptions = optional;
    }
    
    public static WorldGenSettings makeDefault() {
        final long long1 = new Random().nextLong();
        return new WorldGenSettings(long1, true, false, withOverworld(DimensionType.defaultDimensions(long1), makeDefaultOverworld(long1)));
    }
    
    public static NoiseBasedChunkGenerator makeDefaultOverworld(final long long1) {
        return new NoiseBasedChunkGenerator(new OverworldBiomeSource(long1, false, false), long1, NoiseGeneratorSettings.Preset.OVERWORLD.settings());
    }
    
    public long seed() {
        return this.seed;
    }
    
    public boolean generateFeatures() {
        return this.generateFeatures;
    }
    
    public boolean generateBonusChest() {
        return this.generateBonusChest;
    }
    
    public static MappedRegistry<LevelStem> withOverworld(final MappedRegistry<LevelStem> gh, final ChunkGenerator cha) {
        final LevelStem cig3 = gh.get(LevelStem.OVERWORLD);
        final LevelStem levelStem;
        final Supplier<DimensionType> supplier4 = () -> (levelStem == null) ? DimensionType.defaultOverworld() : levelStem.type();
        return withOverworld(gh, supplier4, cha);
    }
    
    public static MappedRegistry<LevelStem> withOverworld(final MappedRegistry<LevelStem> gh, final Supplier<DimensionType> supplier, final ChunkGenerator cha) {
        final MappedRegistry<LevelStem> gh2 = new MappedRegistry<LevelStem>(Registry.LEVEL_STEM_REGISTRY, Lifecycle.experimental());
        gh2.<LevelStem>register(LevelStem.OVERWORLD, new LevelStem(supplier, cha));
        gh2.setPersistent(LevelStem.OVERWORLD);
        for (final Map.Entry<ResourceKey<LevelStem>, LevelStem> entry6 : gh.entrySet()) {
            final ResourceKey<LevelStem> ug7 = entry6.getKey();
            if (ug7 == LevelStem.OVERWORLD) {
                continue;
            }
            gh2.<LevelStem>register(ug7, entry6.getValue());
            if (!gh.persistent(ug7)) {
                continue;
            }
            gh2.setPersistent(ug7);
        }
        return gh2;
    }
    
    public MappedRegistry<LevelStem> dimensions() {
        return this.dimensions;
    }
    
    public ChunkGenerator overworld() {
        final LevelStem cig2 = this.dimensions.get(LevelStem.OVERWORLD);
        if (cig2 == null) {
            return makeDefaultOverworld(new Random().nextLong());
        }
        return cig2.generator();
    }
    
    public ImmutableSet<ResourceKey<Level>> levels() {
        return this.dimensions().entrySet().stream().map(entry -> ResourceKey.<Level>create(Registry.DIMENSION_REGISTRY, entry.getKey().location())).collect(ImmutableSet.toImmutableSet());
    }
    
    public boolean isDebug() {
        return this.overworld() instanceof DebugLevelSource;
    }
    
    public boolean isFlatWorld() {
        return this.overworld() instanceof FlatLevelSource;
    }
    
    public boolean isOldCustomizedWorld() {
        return this.legacyCustomOptions.isPresent();
    }
    
    public WorldGenSettings withBonusChest() {
        return new WorldGenSettings(this.seed, this.generateFeatures, true, this.dimensions, this.legacyCustomOptions);
    }
    
    public WorldGenSettings withFeaturesToggled() {
        return new WorldGenSettings(this.seed, !this.generateFeatures, this.generateBonusChest, this.dimensions);
    }
    
    public WorldGenSettings withBonusChestToggled() {
        return new WorldGenSettings(this.seed, this.generateFeatures, !this.generateBonusChest, this.dimensions);
    }
    
    public WorldGenSettings withDimensions(final MappedRegistry<LevelStem> gh) {
        return new WorldGenSettings(this.seed, this.generateFeatures, this.generateBonusChest, gh);
    }
    
    public static WorldGenSettings create(final Properties properties) {
        final String string2 = MoreObjects.<String>firstNonNull(properties.get("generator-settings"), "");
        properties.put("generator-settings", string2);
        final String string3 = MoreObjects.<String>firstNonNull(properties.get("level-seed"), "");
        properties.put("level-seed", string3);
        final String string4 = (String)properties.get("generate-structures");
        final boolean boolean5 = string4 == null || Boolean.parseBoolean(string4);
        properties.put("generate-structures", Objects.toString(boolean5));
        final String string5 = (String)properties.get("level-type");
        final String string6 = Optional.<String>ofNullable(string5).<String>map(string -> string.toLowerCase(Locale.ROOT)).orElse("default");
        properties.put("level-type", string6);
        long long8 = new Random().nextLong();
        if (!string3.isEmpty()) {
            try {
                final long long9 = Long.parseLong(string3);
                if (long9 != 0L) {
                    long8 = long9;
                }
            }
            catch (NumberFormatException numberFormatException10) {
                long8 = string3.hashCode();
            }
        }
        final MappedRegistry<LevelStem> gh10 = DimensionType.defaultDimensions(long8);
        final String s = string6;
        switch (s) {
            case "flat": {
                final JsonObject jsonObject13 = string2.isEmpty() ? new JsonObject() : GsonHelper.parse(string2);
                final Dynamic<JsonElement> dynamic14 = (Dynamic<JsonElement>)new Dynamic((DynamicOps)JsonOps.INSTANCE, jsonObject13);
                return new WorldGenSettings(long8, boolean5, false, withOverworld(gh10, new FlatLevelSource(FlatLevelGeneratorSettings.CODEC.parse((Dynamic)dynamic14).resultOrPartial((Consumer)WorldGenSettings.LOGGER::error).orElseGet(FlatLevelGeneratorSettings::getDefault))));
            }
            case "debug_all_block_states": {
                return new WorldGenSettings(long8, boolean5, false, withOverworld(gh10, DebugLevelSource.INSTANCE));
            }
            case "amplified": {
                return new WorldGenSettings(long8, boolean5, false, withOverworld(gh10, new NoiseBasedChunkGenerator(new OverworldBiomeSource(long8, false, false), long8, NoiseGeneratorSettings.Preset.AMPLIFIED.settings())));
            }
            case "largebiomes": {
                return new WorldGenSettings(long8, boolean5, false, withOverworld(gh10, new NoiseBasedChunkGenerator(new OverworldBiomeSource(long8, false, true), long8, NoiseGeneratorSettings.Preset.OVERWORLD.settings())));
            }
            default: {
                return new WorldGenSettings(long8, boolean5, false, withOverworld(gh10, makeDefaultOverworld(long8)));
            }
        }
    }
    
    public WorldGenSettings withSeed(final boolean boolean1, final OptionalLong optionalLong) {
        final long long5 = optionalLong.orElse(this.seed);
        MappedRegistry<LevelStem> gh7;
        if (optionalLong.isPresent()) {
            gh7 = new MappedRegistry<LevelStem>(Registry.LEVEL_STEM_REGISTRY, Lifecycle.experimental());
            final long long6 = optionalLong.getAsLong();
            for (final Map.Entry<ResourceKey<LevelStem>, LevelStem> entry11 : this.dimensions.entrySet()) {
                final ResourceKey<LevelStem> ug12 = entry11.getKey();
                gh7.<LevelStem>register(ug12, new LevelStem(entry11.getValue().typeSupplier(), entry11.getValue().generator().withSeed(long6)));
                if (this.dimensions.persistent(ug12)) {
                    gh7.setPersistent(ug12);
                }
            }
        }
        else {
            gh7 = this.dimensions;
        }
        WorldGenSettings cix4;
        if (this.isDebug()) {
            cix4 = new WorldGenSettings(long5, false, false, gh7);
        }
        else {
            cix4 = new WorldGenSettings(long5, this.generateFeatures(), this.generateBonusChest() && !boolean1, gh7);
        }
        return cix4;
    }
    
    static {
        CODEC = RecordCodecBuilder.create(instance -> ((RecordCodecBuilder.Instance)instance).group((App)Codec.LONG.fieldOf("seed").stable().forGetter((Function)WorldGenSettings::seed), (App)Codec.BOOL.fieldOf("generate_features").withDefault(true).stable().forGetter((Function)WorldGenSettings::generateFeatures), (App)Codec.BOOL.fieldOf("bonus_chest").withDefault(false).stable().forGetter((Function)WorldGenSettings::generateBonusChest), (App)MappedRegistry.<LevelStem>dataPackCodec(Registry.LEVEL_STEM_REGISTRY, Lifecycle.stable(), LevelStem.CODEC).xmap((Function)LevelStem::sortMap, (Function)Function.identity()).fieldOf("dimensions").forGetter((Function)WorldGenSettings::dimensions), (App)Codec.STRING.optionalFieldOf("legacy_custom_options").stable().forGetter(cix -> cix.legacyCustomOptions)).apply(instance, ((RecordCodecBuilder.Instance)instance).stable(WorldGenSettings::new))).comapFlatMap((Function)WorldGenSettings::guardExperimental, (Function)Function.identity());
        LOGGER = LogManager.getLogger();
        DEMO_SEED = "North Carolina".hashCode();
        DEMO_SETTINGS = new WorldGenSettings(WorldGenSettings.DEMO_SEED, true, true, withOverworld(DimensionType.defaultDimensions(WorldGenSettings.DEMO_SEED), makeDefaultOverworld(WorldGenSettings.DEMO_SEED)));
    }
}
