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

import net.minecraft.Util;
import java.util.HashMap;
import com.google.common.collect.ImmutableList;
import net.minecraft.world.level.Level;
import net.minecraft.resources.ResourceKey;
import net.minecraft.nbt.ListTag;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import java.io.IOException;
import it.unimi.dsi.fastutil.longs.LongList;
import net.minecraft.nbt.Tag;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import java.util.Locale;
import net.minecraft.world.level.levelgen.feature.StructureFeature;
import net.minecraft.world.level.ChunkPos;
import java.util.Iterator;
import com.google.common.collect.Maps;
import javax.annotation.Nullable;
import net.minecraft.world.level.storage.DimensionDataStorage;
import java.util.List;
import net.minecraft.nbt.CompoundTag;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import java.util.Map;

public class LegacyStructureDataHandler {
    private static final Map<String, String> CURRENT_TO_LEGACY_MAP;
    private static final Map<String, String> LEGACY_TO_CURRENT_MAP;
    private final boolean hasLegacyData;
    private final Map<String, Long2ObjectMap<CompoundTag>> dataMap;
    private final Map<String, StructureFeatureIndexSavedData> indexMap;
    private final List<String> legacyKeys;
    private final List<String> currentKeys;
    
    public LegacyStructureDataHandler(@Nullable final DimensionDataStorage daa, final List<String> list2, final List<String> list3) {
        this.dataMap = Maps.newHashMap();
        this.indexMap = Maps.newHashMap();
        this.legacyKeys = list2;
        this.currentKeys = list3;
        this.populateCaches(daa);
        boolean boolean5 = false;
        for (final String string7 : this.currentKeys) {
            boolean5 |= (this.dataMap.get(string7) != null);
        }
        this.hasLegacyData = boolean5;
    }
    
    public void removeIndex(final long long1) {
        for (final String string5 : this.legacyKeys) {
            final StructureFeatureIndexSavedData ctx6 = this.indexMap.get(string5);
            if (ctx6 != null && ctx6.hasUnhandledIndex(long1)) {
                ctx6.removeIndex(long1);
                ctx6.setDirty();
            }
        }
    }
    
    public CompoundTag updateFromLegacy(CompoundTag le) {
        final CompoundTag le2 = le.getCompound("Level");
        final ChunkPos bph4 = new ChunkPos(le2.getInt("xPos"), le2.getInt("zPos"));
        if (this.isUnhandledStructureStart(bph4.x, bph4.z)) {
            le = this.updateStructureStart(le, bph4);
        }
        final CompoundTag le3 = le2.getCompound("Structures");
        final CompoundTag le4 = le3.getCompound("References");
        for (final String string8 : this.currentKeys) {
            final StructureFeature<?> cml9 = StructureFeature.STRUCTURES_REGISTRY.get(string8.toLowerCase(Locale.ROOT));
            if (!le4.contains(string8, 12)) {
                if (cml9 == null) {
                    continue;
                }
                final int integer10 = 8;
                final LongList longList11 = (LongList)new LongArrayList();
                for (int integer11 = bph4.x - 8; integer11 <= bph4.x + 8; ++integer11) {
                    for (int integer12 = bph4.z - 8; integer12 <= bph4.z + 8; ++integer12) {
                        if (this.hasLegacyStart(integer11, integer12, string8)) {
                            longList11.add(ChunkPos.asLong(integer11, integer12));
                        }
                    }
                }
                le4.putLongArray(string8, (List<Long>)longList11);
            }
        }
        le3.put("References", le4);
        le2.put("Structures", le3);
        le.put("Level", le2);
        return le;
    }
    
    private boolean hasLegacyStart(final int integer1, final int integer2, final String string) {
        return this.hasLegacyData && (this.dataMap.get(string) != null && this.indexMap.get(LegacyStructureDataHandler.CURRENT_TO_LEGACY_MAP.get(string)).hasStartIndex(ChunkPos.asLong(integer1, integer2)));
    }
    
    private boolean isUnhandledStructureStart(final int integer1, final int integer2) {
        if (!this.hasLegacyData) {
            return false;
        }
        for (final String string5 : this.currentKeys) {
            if (this.dataMap.get(string5) != null && this.indexMap.get(LegacyStructureDataHandler.CURRENT_TO_LEGACY_MAP.get(string5)).hasUnhandledIndex(ChunkPos.asLong(integer1, integer2))) {
                return true;
            }
        }
        return false;
    }
    
    private CompoundTag updateStructureStart(final CompoundTag le, final ChunkPos bph) {
        final CompoundTag le2 = le.getCompound("Level");
        final CompoundTag le3 = le2.getCompound("Structures");
        final CompoundTag le4 = le3.getCompound("Starts");
        for (final String string8 : this.currentKeys) {
            final Long2ObjectMap<CompoundTag> long2ObjectMap9 = this.dataMap.get(string8);
            if (long2ObjectMap9 == null) {
                continue;
            }
            final long long10 = bph.toLong();
            if (!this.indexMap.get(LegacyStructureDataHandler.CURRENT_TO_LEGACY_MAP.get(string8)).hasUnhandledIndex(long10)) {
                continue;
            }
            final CompoundTag le5 = (CompoundTag)long2ObjectMap9.get(long10);
            if (le5 == null) {
                continue;
            }
            le4.put(string8, le5);
        }
        le3.put("Starts", le4);
        le2.put("Structures", le3);
        le.put("Level", le2);
        return le;
    }
    
    private void populateCaches(@Nullable final DimensionDataStorage daa) {
        if (daa == null) {
            return;
        }
        for (final String string4 : this.legacyKeys) {
            CompoundTag le5 = new CompoundTag();
            try {
                le5 = daa.readTagFromDisk(string4, 1493).getCompound("data").getCompound("Features");
                if (le5.isEmpty()) {
                    continue;
                }
            }
            catch (IOException ex) {}
            for (final String string5 : le5.getAllKeys()) {
                final CompoundTag le6 = le5.getCompound(string5);
                final long long9 = ChunkPos.asLong(le6.getInt("ChunkX"), le6.getInt("ChunkZ"));
                final ListTag lk11 = le6.getList("Children", 10);
                if (!lk11.isEmpty()) {
                    final String string6 = lk11.getCompound(0).getString("id");
                    final String string7 = LegacyStructureDataHandler.LEGACY_TO_CURRENT_MAP.get(string6);
                    if (string7 != null) {
                        le6.putString("id", string7);
                    }
                }
                final String string6 = le6.getString("id");
                this.dataMap.computeIfAbsent(string6, string -> new Long2ObjectOpenHashMap()).put(long9, le6);
            }
            final String string8 = string4 + "_index";
            final StructureFeatureIndexSavedData ctx7 = daa.<StructureFeatureIndexSavedData>computeIfAbsent(() -> new StructureFeatureIndexSavedData(string8), string8);
            if (ctx7.getAll().isEmpty()) {
                final StructureFeatureIndexSavedData ctx8 = new StructureFeatureIndexSavedData(string8);
                this.indexMap.put(string4, ctx8);
                for (final String string9 : le5.getAllKeys()) {
                    final CompoundTag le7 = le5.getCompound(string9);
                    ctx8.addIndex(ChunkPos.asLong(le7.getInt("ChunkX"), le7.getInt("ChunkZ")));
                }
                ctx8.setDirty();
            }
            else {
                this.indexMap.put(string4, ctx7);
            }
        }
    }
    
    public static LegacyStructureDataHandler getLegacyStructureHandler(final ResourceKey<Level> ug, @Nullable final DimensionDataStorage daa) {
        if (ug == Level.OVERWORLD) {
            return new LegacyStructureDataHandler(daa, ImmutableList.<String>of("Monument", "Stronghold", "Village", "Mineshaft", "Temple", "Mansion"), ImmutableList.<String>of("Village", "Mineshaft", "Mansion", "Igloo", "Desert_Pyramid", "Jungle_Pyramid", "Swamp_Hut", "Stronghold", "Monument"));
        }
        if (ug == Level.NETHER) {
            final List<String> list3 = ImmutableList.<String>of("Fortress");
            return new LegacyStructureDataHandler(daa, list3, list3);
        }
        if (ug == Level.END) {
            final List<String> list3 = ImmutableList.<String>of("EndCity");
            return new LegacyStructureDataHandler(daa, list3, list3);
        }
        throw new RuntimeException(String.format("Unknown dimension type : %s", ug));
    }
    
    static {
        CURRENT_TO_LEGACY_MAP = Util.<Map<String, String>>make(Maps.newHashMap(), hashMap -> {
            hashMap.put("Village", "Village");
            hashMap.put("Mineshaft", "Mineshaft");
            hashMap.put("Mansion", "Mansion");
            hashMap.put("Igloo", "Temple");
            hashMap.put("Desert_Pyramid", "Temple");
            hashMap.put("Jungle_Pyramid", "Temple");
            hashMap.put("Swamp_Hut", "Temple");
            hashMap.put("Stronghold", "Stronghold");
            hashMap.put("Monument", "Monument");
            hashMap.put("Fortress", "Fortress");
            hashMap.put("EndCity", "EndCity");
            return;
        });
        LEGACY_TO_CURRENT_MAP = Util.<Map<String, String>>make(Maps.newHashMap(), hashMap -> {
            hashMap.put("Iglu", "Igloo");
            hashMap.put("TeDP", "Desert_Pyramid");
            hashMap.put("TeJP", "Jungle_Pyramid");
            hashMap.put("TeSH", "Swamp_Hut");
        });
    }
}
