// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.server.worldgen.chunk;

import com.hypixel.hytale.server.worldgen.loader.WorldGenPrefabLoader;
import com.hypixel.hytale.server.core.prefab.selection.buffer.impl.PrefabBuffer;
import com.hypixel.hytale.server.core.prefab.selection.buffer.impl.IPrefabBuffer;
import java.util.logging.Level;
import com.hypixel.hytale.server.worldgen.util.LogUtil;
import com.hypixel.hytale.logger.HytaleLogger;
import com.hypixel.hytale.server.worldgen.loader.WorldGenPrefabSupplier;
import com.hypixel.hytale.common.map.IWeightedMap;
import com.hypixel.hytale.server.worldgen.cave.prefab.CavePrefabContainer;
import com.hypixel.hytale.server.worldgen.cave.CaveNodeType;
import com.hypixel.hytale.server.worldgen.container.PrefabContainer;
import java.util.Set;
import com.hypixel.hytale.server.worldgen.cave.CaveType;
import com.hypixel.hytale.server.worldgen.biome.Biome;
import com.hypixel.hytale.server.worldgen.prefab.unique.UniquePrefabGenerator;
import java.util.HashSet;
import com.hypixel.hytale.server.worldgen.zone.Zone;
import java.util.concurrent.CompletableFuture;
import java.util.Deque;
import java.util.ArrayDeque;
import java.util.concurrent.Executor;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.worldgen.zone.ZonePatternProvider;

public class ValidationUtil
{
    public static boolean isInvalid(@Nonnull final ZonePatternProvider zonePatternProvider, @Nonnull final Executor executor) {
        return CompletableFuture.supplyAsync(() -> {
            final ArrayDeque<String> trace = new ArrayDeque<String>();
            boolean invalid = false;
            final Zone[] arr$ = zonePatternProvider.getZones();
            for (int len$ = arr$.length, i$ = 0; i$ < len$; ++i$) {
                final Zone zone = arr$[i$];
                trace.push("Zone[\"" + zone.name() + "\"]");
                try {
                    invalid |= isZoneInvalid(zone, trace);
                }
                finally {
                    trace.pop();
                }
            }
            return invalid;
        }, executor).join();
    }
    
    private static boolean isZoneInvalid(@Nonnull final Zone zone, @Nonnull final Deque<String> trace) {
        boolean invalid = false;
        final UniquePrefabGenerator[] generators = zone.uniquePrefabContainer().getGenerators();
        for (int length = generators.length, i = 0; i < length; ++i) {
            final UniquePrefabGenerator uniquePrefabGenerator = generators[i];
            trace.push("UniquePrefabs[\"" + uniquePrefabGenerator.getName() + "\"]");
            try {
                invalid |= arePrefabsInvalid(uniquePrefabGenerator.getPrefabs(), trace);
            }
            finally {
                trace.pop();
            }
        }
        final Biome[] biomes = zone.biomePatternGenerator().getBiomes();
        for (int length2 = biomes.length, j = 0; j < length2; ++j) {
            final Biome biome = biomes[j];
            trace.push("Biome[\"" + biome.getName() + "\"]");
            try {
                invalid |= isBiomeInvalid(biome, trace);
            }
            finally {
                trace.pop();
            }
        }
        if (zone.caveGenerator() != null) {
            final CaveType[] caveTypes = zone.caveGenerator().getCaveTypes();
            for (int length3 = caveTypes.length, k = 0; k < length3; ++k) {
                final CaveType caveType = caveTypes[k];
                trace.push("Cave[\"" + caveType.getName() + "\"].Entry");
                try {
                    final Set<String> encounteredNodes = new HashSet<String>();
                    invalid |= isCaveNodeInvalid(caveType.getEntryNode(), encounteredNodes, trace);
                }
                finally {
                    trace.pop();
                }
            }
        }
        return invalid;
    }
    
    private static boolean isBiomeInvalid(@Nonnull final Biome biome, @Nonnull final Deque<String> trace) {
        boolean invalid = false;
        if (biome.getPrefabContainer() != null) {
            final PrefabContainer.PrefabContainerEntry[] prefabContainerEntries = biome.getPrefabContainer().getEntries();
            for (int i = 0; i < prefabContainerEntries.length; ++i) {
                trace.push("Prefabs[" + i);
                try {
                    invalid |= arePrefabsInvalid(prefabContainerEntries[i].getPrefabs(), trace);
                }
                finally {
                    trace.pop();
                }
            }
        }
        return invalid;
    }
    
    private static boolean isCaveNodeInvalid(@Nonnull final CaveNodeType caveNodeType, @Nonnull final Set<String> encounteredNodes, @Nonnull final Deque<String> trace) {
        if (!encounteredNodes.add(caveNodeType.getName())) {
            return false;
        }
        boolean invalid = false;
        if (caveNodeType.getPrefabContainer() != null) {
            final CavePrefabContainer.CavePrefabEntry[] cavePrefabEntries = caveNodeType.getPrefabContainer().getEntries();
            for (int i = 0; i < cavePrefabEntries.length; ++i) {
                trace.push("Prefabs[" + i);
                try {
                    invalid |= arePrefabsInvalid(cavePrefabEntries[i].getPrefabs(), trace);
                }
                finally {
                    trace.pop();
                }
            }
        }
        final CaveNodeType.CaveNodeChildEntry[] children = caveNodeType.getChildren();
        for (int i = 0; i < children.length; ++i) {
            final CaveNodeType[] nodes = children[i].getTypes().internalKeys();
            for (int n = 0; n < nodes.length; ++n) {
                trace.push("Children[" + i + "].Node[" + n);
                try {
                    invalid |= isCaveNodeInvalid(nodes[n], encounteredNodes, trace);
                }
                finally {
                    trace.pop();
                }
            }
        }
        return invalid;
    }
    
    private static boolean arePrefabsInvalid(@Nonnull final IWeightedMap<WorldGenPrefabSupplier> prefabs, @Nonnull final Deque<String> trace) {
        boolean invalid = false;
        final WorldGenPrefabSupplier[] suppliers = prefabs.internalKeys();
        for (int i = 0; i < suppliers.length; ++i) {
            trace.push("Prefabs[" + i);
            try {
                IPrefabBuffer prefab;
                try {
                    prefab = suppliers[i].get();
                }
                catch (final Throwable e) {
                    invalid = true;
                    LogUtil.getLogger().at(Level.SEVERE).withCause(e).log("Failed to load prefab: %s loaded from %s", suppliers[i].getName(), String.join(".", trace));
                    continue;
                }
                trace.push("{" + suppliers[i].getName());
                try {
                    final PrefabBuffer.ChildPrefab[] childPrefabs = prefab.getChildPrefabs();
                    for (int length = childPrefabs.length, j = 0; j < length; ++j) {
                        final PrefabBuffer.ChildPrefab childMarker = childPrefabs[j];
                        trace.push("(" + childMarker.getX() + "," + childMarker.getY() + "," + childMarker.getZ());
                        try {
                            invalid |= isChildPrefabInvalid(childMarker, suppliers[i].getLoader(), trace);
                        }
                        finally {
                            trace.pop();
                        }
                    }
                }
                finally {
                    trace.pop();
                }
            }
            finally {
                trace.pop();
            }
        }
        return invalid;
    }
    
    private static boolean isChildPrefabInvalid(@Nonnull final PrefabBuffer.ChildPrefab childMarker, @Nonnull final WorldGenPrefabLoader loader, @Nonnull final Deque<String> trace) {
        WorldGenPrefabSupplier[] suppliers;
        try {
            suppliers = loader.get(childMarker.getPath());
        }
        catch (final Throwable e) {
            LogUtil.getLogger().at(Level.SEVERE).withCause(e).log("Failed to resolve child prefab: %s loaded from %s", childMarker.getPath(), String.join(".", trace));
            return true;
        }
        boolean invalid = false;
        for (final WorldGenPrefabSupplier childSupplier : suppliers) {
            try {
                childSupplier.get();
            }
            catch (final Throwable e2) {
                invalid = true;
                LogUtil.getLogger().at(Level.SEVERE).withCause(e2).log("Failed to load child prefab: %s loaded from %s", childSupplier.getName(), String.join(".", trace));
            }
        }
        return invalid;
    }
}
