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

package com.hypixel.hytale.server.worldgen.loader.biome;

import com.hypixel.hytale.server.worldgen.loader.context.FileLoadingContext;
import java.util.Iterator;
import java.util.Map;
import com.hypixel.hytale.server.worldgen.loader.context.FileContext;
import com.hypixel.hytale.server.worldgen.loader.context.BiomeFileContext;
import com.google.gson.JsonArray;
import it.unimi.dsi.fastutil.ints.IntSet;
import java.util.function.Supplier;
import com.hypixel.hytale.server.worldgen.util.condition.IntConditionBuilder;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import com.hypixel.hytale.procedurallib.condition.ConstantIntCondition;
import com.hypixel.hytale.server.worldgen.loader.util.FileMaskCache;
import com.google.gson.JsonElement;
import java.nio.file.Path;
import javax.annotation.Nonnull;
import com.hypixel.hytale.procedurallib.json.SeedString;
import javax.annotation.Nullable;
import com.hypixel.hytale.server.worldgen.loader.context.ZoneFileContext;
import com.hypixel.hytale.procedurallib.condition.IIntCondition;
import com.hypixel.hytale.server.worldgen.SeedStringResource;
import com.hypixel.hytale.procedurallib.json.JsonLoader;

public class BiomeMaskJsonLoader extends JsonLoader<SeedStringResource, IIntCondition>
{
    private final ZoneFileContext zoneContext;
    @Nullable
    private String fileName;
    
    public BiomeMaskJsonLoader(@Nonnull final SeedString<SeedStringResource> seed, final Path dataFolder, final JsonElement json, final String maskName, final ZoneFileContext zoneContext) {
        super(seed.append(".BiomeMask-" + maskName), dataFolder, json);
        this.fileName = null;
        this.zoneContext = zoneContext;
    }
    
    @Nullable
    @Override
    public IIntCondition load() {
        final FileMaskCache<IIntCondition> biomeMaskRegistry = ((SeedStringResource)this.seed.get()).getBiomeMaskRegistry();
        if (this.fileName != null) {
            final IIntCondition mask = biomeMaskRegistry.getIfPresentFileMask(this.fileName);
            if (mask != null) {
                return mask;
            }
        }
        final IIntCondition mask = this.loadMask();
        if (this.fileName != null) {
            biomeMaskRegistry.putFileMask(this.fileName, mask);
        }
        return mask;
    }
    
    protected IIntCondition loadMask() {
        IIntCondition mask = ConstantIntCondition.DEFAULT_TRUE;
        if (this.json.isJsonArray()) {
            final IntConditionBuilder builder = new IntConditionBuilder((Supplier<IntSet>)IntOpenHashSet::new, -1);
            final JsonArray array = this.json.getAsJsonArray();
            for (int i = 0; i < array.size(); ++i) {
                final JsonElement element = array.get(i);
                final String rule = element.getAsString();
                this.parseRule(rule, builder);
            }
            mask = builder.buildOrDefault(ConstantIntCondition.DEFAULT_TRUE);
        }
        return mask;
    }
    
    protected void parseRule(@Nonnull final String rule, @Nonnull final IntConditionBuilder builder) {
        final int zoneMarker = rule.indexOf(46);
        final int typeMarker = rule.indexOf(35);
        final ZoneFileContext zone = parseZone(rule, zoneMarker, this.zoneContext);
        final String biomeName = parseBiomeName(rule, zoneMarker, typeMarker);
        final BiomeFileContext.Type biomeType = parseBiomeType(rule, typeMarker + 1);
        boolean result;
        if (biomeType == null) {
            result = collectBiomes(zone.getTileBiomes(), biomeName, builder);
            result |= collectBiomes(zone.getCustomBiomes(), biomeName, builder);
        }
        else {
            result = collectBiomes(zone.getBiomes(biomeType), biomeName, builder);
        }
        if (!result) {
            throw new Error(String.format("Failed to parse BiomeMask rule '%s'. Unable to find a %s called %s in %s", rule, getDisplayName(biomeType), biomeName, zone.getName()));
        }
    }
    
    @Override
    protected JsonElement loadFileConstructor(final String filePath) {
        this.fileName = filePath;
        return ((SeedStringResource)this.seed.get()).getBiomeMaskRegistry().cachedFile(filePath, x$0 -> super.loadFileConstructor(x$0));
    }
    
    private static boolean collectBiomes(@Nonnull final FileContext.Registry<BiomeFileContext> registry, @Nonnull final String biomeName, @Nonnull final IntConditionBuilder builder) {
        if (biomeName.equals("*")) {
            for (final Map.Entry<String, BiomeFileContext> biomeEntry : registry) {
                builder.add(biomeEntry.getValue().getId());
            }
            return true;
        }
        if (registry.contains(biomeName)) {
            final BiomeFileContext biome = registry.get(biomeName);
            builder.add(biome.getId());
            return true;
        }
        return false;
    }
    
    @Nonnull
    private static ZoneFileContext parseZone(@Nonnull final String rule, final int marker, @Nonnull final ZoneFileContext context) {
        if (marker <= 0) {
            return context;
        }
        final String zoneName = rule.substring(0, marker);
        return context.getParentContext().getZones().get(zoneName);
    }
    
    @Nullable
    private static BiomeFileContext.Type parseBiomeType(@Nonnull final String rule, final int marker) {
        if (marker <= 0) {
            return null;
        }
        final String typeName = rule.substring(marker);
        return BiomeFileContext.Type.valueOf(typeName);
    }
    
    @Nonnull
    private static String parseBiomeName(@Nonnull final String rule, final int zoneMarker, final int typeMarker) {
        final int nameStart = zoneMarker + 1;
        final int nameEnd = (typeMarker > zoneMarker) ? typeMarker : rule.length();
        if (nameStart == nameEnd) {
            return "*";
        }
        return rule.substring(nameStart, nameEnd);
    }
    
    @Nonnull
    private static String getDisplayName(@Nullable final BiomeFileContext.Type type) {
        return (type == null) ? "Biome" : type.getDisplayName();
    }
    
    public interface Constants
    {
        public static final char ZONE_MARKER = '.';
        public static final char TYPE_MARKER = '#';
        public static final int NULL_BIOME_ID = -1;
        public static final String WILDCARD_BIOME_NAME = "*";
        public static final String BIOME_TYPE_ANY_DISPLAY_NAME = "Biome";
        public static final String ERROR_PARSE_RULE = "Failed to parse BiomeMask rule '%s'. Unable to find a %s called %s in %s";
    }
}
