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.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 java.util.List;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.biome.OverworldBiomeSource;
import net.minecraft.world.level.biome.FixedBiomeSource;
import net.minecraft.world.level.biome.Biomes;
import net.minecraft.world.level.DataPackConfig;
import com.mojang.serialization.DynamicOps;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.RegistryReadOps;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.nbt.NbtOps;
import net.minecraft.core.RegistryAccess;
import java.io.File;
import java.util.Collection;
import net.minecraft.world.level.Level;
import com.google.common.collect.Lists;
import net.minecraft.util.ProgressListener;
import org.apache.logging.log4j.Logger;

public class McRegionUpgrader {
    private static final Logger LOGGER;
    
    static boolean convertLevel(final LevelStorageSource.LevelStorageAccess a, final ProgressListener aed) {
        aed.progressStagePercentage(0);
        final List<File> list3 = Lists.newArrayList();
        final List<File> list4 = Lists.newArrayList();
        final List<File> list5 = Lists.newArrayList();
        final File file6 = a.getDimensionPath(Level.OVERWORLD);
        final File file7 = a.getDimensionPath(Level.NETHER);
        final File file8 = a.getDimensionPath(Level.END);
        McRegionUpgrader.LOGGER.info("Scanning folders...");
        addRegionFiles(file6, list3);
        if (file7.exists()) {
            addRegionFiles(file7, list4);
        }
        if (file8.exists()) {
            addRegionFiles(file8, list5);
        }
        final int integer9 = list3.size() + list4.size() + list5.size();
        McRegionUpgrader.LOGGER.info("Total conversion count is {}", integer9);
        final RegistryAccess.RegistryHolder a2 = RegistryAccess.builtin();
        final RegistryReadOps<Tag> ue11 = RegistryReadOps.<Tag>create((com.mojang.serialization.DynamicOps<Tag>)NbtOps.INSTANCE, ResourceManager.Empty.INSTANCE, a2);
        final WorldData dal12 = a.getDataTag((DynamicOps<Tag>)ue11, DataPackConfig.DEFAULT);
        final long long13 = (dal12 != null) ? dal12.worldGenSettings().seed() : 0L;
        BiomeSource brh15;
        if (dal12 != null && dal12.worldGenSettings().isFlatWorld()) {
            brh15 = new FixedBiomeSource(Biomes.PLAINS);
        }
        else {
            brh15 = new OverworldBiomeSource(long13, false, false);
        }
        convertRegions(new File(file6, "region"), list3, brh15, 0, integer9, aed);
        convertRegions(new File(file7, "region"), list4, new FixedBiomeSource(Biomes.NETHER_WASTES), list3.size(), integer9, aed);
        convertRegions(new File(file8, "region"), list5, new FixedBiomeSource(Biomes.THE_END), list3.size() + list4.size(), integer9, aed);
        makeMcrLevelDatBackup(a);
        a.saveDataTag(a2, dal12);
        return true;
    }
    
    private static void makeMcrLevelDatBackup(final LevelStorageSource.LevelStorageAccess a) {
        final File file2 = a.getLevelPath(LevelResource.LEVEL_DATA_FILE).toFile();
        if (!file2.exists()) {
            McRegionUpgrader.LOGGER.warn("Unable to create level.dat_mcr backup");
            return;
        }
        final File file3 = new File(file2.getParent(), "level.dat_mcr");
        if (!file2.renameTo(file3)) {
            McRegionUpgrader.LOGGER.warn("Unable to create level.dat_mcr backup");
        }
    }
    
    private static void convertRegions(final File file, final Iterable<File> iterable, final BiomeSource brh, int integer4, final int integer5, final ProgressListener aed) {
        for (final File file2 : iterable) {
            convertRegion(file, file2, brh, integer4, integer5, aed);
            ++integer4;
            final int integer6 = (int)Math.round(100.0 * integer4 / integer5);
            aed.progressStagePercentage(integer6);
        }
    }
    
    private static void convertRegion(final File file1, final File file2, final BiomeSource brh, final int integer4, final int integer5, final ProgressListener aed) {
        final String string7 = file2.getName();
        try (final RegionFile cia8 = new RegionFile(file2, file1, true);
             final RegionFile cia9 = new RegionFile(new File(file1, string7.substring(0, string7.length() - ".mcr".length()) + ".mca"), file1, true)) {
            for (int integer6 = 0; integer6 < 32; ++integer6) {
                for (int integer7 = 0; integer7 < 32; ++integer7) {
                    final ChunkPos bph14 = new ChunkPos(integer6, integer7);
                    if (cia8.hasChunk(bph14) && !cia9.hasChunk(bph14)) {
                        CompoundTag le15;
                        try (final DataInputStream dataInputStream16 = cia8.getChunkDataInputStream(bph14)) {
                            if (dataInputStream16 == null) {
                                McRegionUpgrader.LOGGER.warn("Failed to fetch input stream for chunk {}", bph14);
                                continue;
                            }
                            le15 = NbtIo.read(dataInputStream16);
                        }
                        catch (IOException iOException16) {
                            McRegionUpgrader.LOGGER.warn("Failed to read data for chunk {}", bph14, iOException16);
                            continue;
                        }
                        final CompoundTag le16 = le15.getCompound("Level");
                        final OldChunkStorage.OldLevelChunk a17 = OldChunkStorage.load(le16);
                        final CompoundTag le17 = new CompoundTag();
                        final CompoundTag le18 = new CompoundTag();
                        le17.put("Level", le18);
                        OldChunkStorage.convertToAnvilFormat(a17, le18, brh);
                        try (final DataOutputStream dataOutputStream20 = cia9.getChunkDataOutputStream(bph14)) {
                            NbtIo.write(le17, 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) {
                    aed.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();
    }
}
