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.dimension.DimensionType;
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.Feature;
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 crl, final List<String> list2, final List<String> list3) {
        this.dataMap = Maps.newHashMap();
        this.indexMap = Maps.newHashMap();
        this.legacyKeys = list2;
        this.currentKeys = list3;
        this.populateCaches(crl);
        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 clt6 = this.indexMap.get(string5);
            if (clt6 != null && clt6.hasUnhandledIndex(long1)) {
                clt6.removeIndex(long1);
                clt6.setDirty();
            }
        }
    }
    
    public CompoundTag updateFromLegacy(CompoundTag jt) {
        final CompoundTag jt2 = jt.getCompound("Level");
        final ChunkPos bjh4 = new ChunkPos(jt2.getInt("xPos"), jt2.getInt("zPos"));
        if (this.isUnhandledStructureStart(bjh4.x, bjh4.z)) {
            jt = this.updateStructureStart(jt, bjh4);
        }
        final CompoundTag jt3 = jt2.getCompound("Structures");
        final CompoundTag jt4 = jt3.getCompound("References");
        for (final String string8 : this.currentKeys) {
            final StructureFeature<?> cfl9 = Feature.STRUCTURES_REGISTRY.get(string8.toLowerCase(Locale.ROOT));
            if (!jt4.contains(string8, 12)) {
                if (cfl9 == null) {
                    continue;
                }
                final int integer10 = cfl9.getLookupRange();
                final LongList longList11 = (LongList)new LongArrayList();
                for (int integer11 = bjh4.x - integer10; integer11 <= bjh4.x + integer10; ++integer11) {
                    for (int integer12 = bjh4.z - integer10; integer12 <= bjh4.z + integer10; ++integer12) {
                        if (this.hasLegacyStart(integer11, integer12, string8)) {
                            longList11.add(ChunkPos.asLong(integer11, integer12));
                        }
                    }
                }
                jt4.putLongArray(string8, (List<Long>)longList11);
            }
        }
        jt3.put("References", jt4);
        jt2.put("Structures", jt3);
        jt.put("Level", jt2);
        return jt;
    }
    
    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 jt, final ChunkPos bjh) {
        final CompoundTag jt2 = jt.getCompound("Level");
        final CompoundTag jt3 = jt2.getCompound("Structures");
        final CompoundTag jt4 = jt3.getCompound("Starts");
        for (final String string8 : this.currentKeys) {
            final Long2ObjectMap<CompoundTag> long2ObjectMap9 = this.dataMap.get(string8);
            if (long2ObjectMap9 == null) {
                continue;
            }
            final long long10 = bjh.toLong();
            if (!this.indexMap.get(LegacyStructureDataHandler.CURRENT_TO_LEGACY_MAP.get(string8)).hasUnhandledIndex(long10)) {
                continue;
            }
            final CompoundTag jt5 = (CompoundTag)long2ObjectMap9.get(long10);
            if (jt5 == null) {
                continue;
            }
            jt4.put(string8, jt5);
        }
        jt3.put("Starts", jt4);
        jt2.put("Structures", jt3);
        jt.put("Level", jt2);
        return jt;
    }
    
    private void populateCaches(@Nullable final DimensionDataStorage crl) {
        if (crl == null) {
            return;
        }
        for (final String string4 : this.legacyKeys) {
            CompoundTag jt5 = new CompoundTag();
            try {
                jt5 = crl.readTagFromDisk(string4, 1493).getCompound("data").getCompound("Features");
                if (jt5.isEmpty()) {
                    continue;
                }
            }
            catch (IOException ex) {}
            for (final String string5 : jt5.getAllKeys()) {
                final CompoundTag jt6 = jt5.getCompound(string5);
                final long long9 = ChunkPos.asLong(jt6.getInt("ChunkX"), jt6.getInt("ChunkZ"));
                final ListTag jz11 = jt6.getList("Children", 10);
                if (!jz11.isEmpty()) {
                    final String string6 = jz11.getCompound(0).getString("id");
                    final String string7 = LegacyStructureDataHandler.LEGACY_TO_CURRENT_MAP.get(string6);
                    if (string7 != null) {
                        jt6.putString("id", string7);
                    }
                }
                final String string6 = jt6.getString("id");
                this.dataMap.computeIfAbsent(string6, string -> new Long2ObjectOpenHashMap()).put(long9, jt6);
            }
            final String string8 = string4 + "_index";
            final StructureFeatureIndexSavedData clt7 = crl.<StructureFeatureIndexSavedData>computeIfAbsent(() -> new StructureFeatureIndexSavedData(string8), string8);
            if (clt7.getAll().isEmpty()) {
                final StructureFeatureIndexSavedData clt8 = new StructureFeatureIndexSavedData(string8);
                this.indexMap.put(string4, clt8);
                for (final String string9 : jt5.getAllKeys()) {
                    final CompoundTag jt7 = jt5.getCompound(string9);
                    clt8.addIndex(ChunkPos.asLong(jt7.getInt("ChunkX"), jt7.getInt("ChunkZ")));
                }
                clt8.setDirty();
            }
            else {
                this.indexMap.put(string4, clt7);
            }
        }
    }
    
    public static LegacyStructureDataHandler getLegacyStructureHandler(final DimensionType cbi, @Nullable final DimensionDataStorage crl) {
        if (cbi == DimensionType.OVERWORLD) {
            return new LegacyStructureDataHandler(crl, 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 (cbi == DimensionType.NETHER) {
            final List<String> list3 = ImmutableList.<String>of("Fortress");
            return new LegacyStructureDataHandler(crl, list3, list3);
        }
        if (cbi == DimensionType.THE_END) {
            final List<String> list3 = ImmutableList.<String>of("EndCity");
            return new LegacyStructureDataHandler(crl, list3, list3);
        }
        throw new RuntimeException(String.format("Unknown dimension type : %s", cbi));
    }
    
    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");
        });
    }
}
