package net.minecraft.world.level.storage;

import org.apache.logging.log4j.LogManager;
import java.util.Collections;
import java.io.DataOutputStream;
import java.io.DataInputStream;
import java.io.DataOutput;
import net.minecraft.nbt.Tag;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.chunk.storage.OldChunkStorage;
import java.io.IOException;
import net.minecraft.nbt.NbtIo;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.storage.RegionFile;
import java.util.Iterator;
import net.minecraft.world.level.biome.OverworldBiomeSource;
import net.minecraft.world.level.biome.OverworldBiomeSourceSettings;
import net.minecraft.world.level.biome.FixedBiomeSource;
import java.util.List;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.biome.Biomes;
import net.minecraft.world.level.biome.FixedBiomeSourceSettings;
import net.minecraft.world.level.LevelType;
import net.minecraft.world.level.biome.BiomeSourceType;
import java.util.Collection;
import net.minecraft.world.level.dimension.DimensionType;
import java.io.File;
import com.google.common.collect.Lists;
import net.minecraft.util.ProgressListener;
import com.mojang.datafixers.DataFixer;
import java.nio.file.Path;
import org.apache.logging.log4j.Logger;

public class McRegionUpgrader {
    private static final Logger LOGGER;
    
    static boolean convertLevel(final Path path, final DataFixer dataFixer, final String string, final ProgressListener abs) {
        abs.progressStagePercentage(0);
        final List<File> list5 = Lists.newArrayList();
        final List<File> list6 = Lists.newArrayList();
        final List<File> list7 = Lists.newArrayList();
        final File file8 = new File(path.toFile(), string);
        final File file9 = DimensionType.NETHER.getStorageFolder(file8);
        final File file10 = DimensionType.THE_END.getStorageFolder(file8);
        McRegionUpgrader.LOGGER.info("Scanning folders...");
        addRegionFiles(file8, list5);
        if (file9.exists()) {
            addRegionFiles(file9, list6);
        }
        if (file10.exists()) {
            addRegionFiles(file10, list7);
        }
        final int integer11 = list5.size() + list6.size() + list7.size();
        McRegionUpgrader.LOGGER.info("Total conversion count is {}", integer11);
        final LevelData crm12 = LevelStorageSource.getDataTagFor(path, dataFixer, string);
        final BiomeSourceType<FixedBiomeSourceSettings, FixedBiomeSource> bky14 = BiomeSourceType.FIXED;
        final BiomeSourceType<OverworldBiomeSourceSettings, OverworldBiomeSource> bky15 = BiomeSourceType.VANILLA_LAYERED;
        BiomeSource bkw13;
        if (crm12 != null && crm12.getGeneratorType() == LevelType.FLAT) {
            bkw13 = bky14.create(bky14.createSettings(crm12).setBiome(Biomes.PLAINS));
        }
        else {
            bkw13 = bky15.create(bky15.createSettings(crm12));
        }
        convertRegions(new File(file8, "region"), list5, bkw13, 0, integer11, abs);
        convertRegions(new File(file9, "region"), list6, bky14.create(bky14.createSettings(crm12).setBiome(Biomes.NETHER)), list5.size(), integer11, abs);
        convertRegions(new File(file10, "region"), list7, bky14.create(bky14.createSettings(crm12).setBiome(Biomes.THE_END)), list5.size() + list6.size(), integer11, abs);
        crm12.setVersion(19133);
        if (crm12.getGeneratorType() == LevelType.NORMAL_1_1) {
            crm12.setGenerator(LevelType.NORMAL);
        }
        makeMcrLevelDatBackup(path, string);
        final LevelStorage crn16 = LevelStorageSource.selectLevel(path, dataFixer, string, null);
        crn16.saveLevelData(crm12);
        return true;
    }
    
    private static void makeMcrLevelDatBackup(final Path path, final String string) {
        final File file3 = new File(path.toFile(), string);
        if (!file3.exists()) {
            McRegionUpgrader.LOGGER.warn("Unable to create level.dat_mcr backup");
            return;
        }
        final File file4 = new File(file3, "level.dat");
        if (!file4.exists()) {
            McRegionUpgrader.LOGGER.warn("Unable to create level.dat_mcr backup");
            return;
        }
        final File file5 = new File(file3, "level.dat_mcr");
        if (!file4.renameTo(file5)) {
            McRegionUpgrader.LOGGER.warn("Unable to create level.dat_mcr backup");
        }
    }
    
    private static void convertRegions(final File file, final Iterable<File> iterable, final BiomeSource bkw, int integer4, final int integer5, final ProgressListener abs) {
        for (final File file2 : iterable) {
            convertRegion(file, file2, bkw, integer4, integer5, abs);
            ++integer4;
            final int integer6 = (int)Math.round(100.0 * integer4 / integer5);
            abs.progressStagePercentage(integer6);
        }
    }
    
    private static void convertRegion(final File file1, final File file2, final BiomeSource bkw, final int integer4, final int integer5, final ProgressListener abs) {
        final String string7 = file2.getName();
        try (final RegionFile cbc8 = new RegionFile(file2, file1);
             final RegionFile cbc9 = new RegionFile(new File(file1, string7.substring(0, string7.length() - ".mcr".length()) + ".mca"), file1)) {
            for (int integer6 = 0; integer6 < 32; ++integer6) {
                for (int integer7 = 0; integer7 < 32; ++integer7) {
                    final ChunkPos bjh14 = new ChunkPos(integer6, integer7);
                    if (cbc8.hasChunk(bjh14) && !cbc9.hasChunk(bjh14)) {
                        CompoundTag jt15;
                        try (final DataInputStream dataInputStream16 = cbc8.getChunkDataInputStream(bjh14)) {
                            if (dataInputStream16 == null) {
                                McRegionUpgrader.LOGGER.warn("Failed to fetch input stream for chunk {}", bjh14);
                                continue;
                            }
                            jt15 = NbtIo.read(dataInputStream16);
                        }
                        catch (IOException iOException16) {
                            McRegionUpgrader.LOGGER.warn("Failed to read data for chunk {}", bjh14, iOException16);
                            continue;
                        }
                        final CompoundTag jt16 = jt15.getCompound("Level");
                        final OldChunkStorage.OldLevelChunk a17 = OldChunkStorage.load(jt16);
                        final CompoundTag jt17 = new CompoundTag();
                        final CompoundTag jt18 = new CompoundTag();
                        jt17.put("Level", jt18);
                        OldChunkStorage.convertToAnvilFormat(a17, jt18, bkw);
                        try (final DataOutputStream dataOutputStream20 = cbc9.getChunkDataOutputStream(bjh14)) {
                            NbtIo.write(jt17, dataOutputStream20);
                        }
                    }
                }
                int integer7 = (int)Math.round(100.0 * (integer4 * 1024) / (integer5 * 1024));
                final int integer8 = (int)Math.round(100.0 * ((integer6 + 1) * 32 + integer4 * 1024) / (integer5 * 1024));
                if (integer8 > integer7) {
                    abs.progressStagePercentage(integer8);
                }
            }
        }
        catch (IOException iOException17) {
            McRegionUpgrader.LOGGER.error("Failed to upgrade region file {}", file2, iOException17);
        }
    }
    
    private static void addRegionFiles(final File file, final Collection<File> collection) {
        final File file2 = new File(file, "region");
        final File[] arr4 = file2.listFiles((file, string) -> string.endsWith(".mcr"));
        if (arr4 != null) {
            Collections.<File>addAll(collection, arr4);
        }
    }
    
    static {
        LOGGER = LogManager.getLogger();
    }
}
