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

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

import it.unimi.dsi.fastutil.ints.IntIterator;
import it.unimi.dsi.fastutil.ints.IntSet;
import com.hypixel.hytale.server.worldgen.util.condition.HashSetIntCondition;
import javax.annotation.Nullable;
import com.google.gson.JsonObject;
import com.hypixel.hytale.procedurallib.condition.IIntCondition;
import javax.annotation.Nonnull;
import java.util.Iterator;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import com.google.gson.JsonElement;
import java.nio.file.Path;
import com.hypixel.hytale.procedurallib.json.SeedString;
import com.hypixel.hytale.server.worldgen.loader.context.ZoneFileContext;
import com.hypixel.hytale.server.worldgen.biome.BiomeInterpolation;
import com.hypixel.hytale.server.worldgen.SeedStringResource;
import com.hypixel.hytale.procedurallib.json.JsonLoader;

public class BiomeInterpolationJsonLoader extends JsonLoader<SeedStringResource, BiomeInterpolation>
{
    protected final ZoneFileContext zoneFileContext;
    
    public BiomeInterpolationJsonLoader(final SeedString<SeedStringResource> seed, final Path dataFolder, final JsonElement json, final ZoneFileContext zoneFileContext) {
        super(seed, dataFolder, json);
        this.zoneFileContext = zoneFileContext;
    }
    
    @Override
    public BiomeInterpolation load() {
        final int defaultRadius = this.loadDefaultRadius();
        final Int2IntMap biomeRadii = this.loadBiomeRadii(defaultRadius);
        return BiomeInterpolation.create(defaultRadius, biomeRadii);
    }
    
    protected int loadDefaultRadius() {
        if (!this.has("DefaultRadius")) {
            return 5;
        }
        final int radius = this.get("DefaultRadius").getAsInt();
        if (radius < 0 || radius > 5) {
            throw new Error(String.format("Default biome interpolation radius %s lies outside the range 0-5", radius));
        }
        return radius;
    }
    
    @Nonnull
    protected Int2IntMap loadBiomeRadii(final int maxRadius) {
        if (!this.has("Biomes")) {
            return BiomeInterpolation.EMPTY_MAP;
        }
        final JsonElement biomes = this.get("Biomes");
        if (!biomes.isJsonArray()) {
            throw new Error("Invalid json-type for Biomes property. Must be an array!");
        }
        final Int2IntOpenHashMap biomeRadii = new Int2IntOpenHashMap();
        for (final JsonElement entry : biomes.getAsJsonArray()) {
            this.loadBiomeEntry(entry, maxRadius, biomeRadii);
        }
        return biomeRadii;
    }
    
    protected void loadBiomeEntry(@Nonnull final JsonElement entry, final int defaultRadius, @Nonnull final Int2IntMap biomeRadii) {
        if (!entry.isJsonObject()) {
            throw new Error("Invalid json-type for biome entry. Must be an object!");
        }
        final int radius = loadBiomeRadius(entry.getAsJsonObject(), defaultRadius);
        if (radius == defaultRadius) {
            return;
        }
        final IIntCondition mask = this.loadBiomeMask(entry.getAsJsonObject());
        addBiomes(mask, radius, biomeRadii);
    }
    
    @Nullable
    protected IIntCondition loadBiomeMask(@Nonnull final JsonObject entry) {
        if (!entry.has("Mask")) {
            throw new Error(String.format("Missing property %s", "Mask"));
        }
        return new BiomeMaskJsonLoader((SeedString<SeedStringResource>)this.seed, this.dataFolder, entry.get("Mask"), "InterpolationMask", this.zoneFileContext).load();
    }
    
    protected static int loadBiomeRadius(@Nonnull final JsonObject entry, final int maxRadius) {
        if (!entry.has("Radius")) {
            throw new Error(String.format("Missing property %s", "Radius"));
        }
        final int radius = entry.get("Radius").getAsInt();
        if (radius < 0 || radius > maxRadius) {
            throw new Error(String.format("Biome interpolation radius %s is outside the range 0-%s", radius, maxRadius));
        }
        return radius;
    }
    
    protected static void addBiomes(final IIntCondition mask, final int radius, @Nonnull final Int2IntMap biomeRadii) {
        if (!(mask instanceof HashSetIntCondition)) {
            return;
        }
        final int radius2 = radius * radius;
        final IntSet biomes = ((HashSetIntCondition)mask).getSet();
        for (final int biome : biomes) {
            if (biomeRadii.containsKey(biome)) {
                throw new Error("Duplicate biome detected in interpolation rules");
            }
            biomeRadii.put(biome, radius2);
        }
    }
    
    public interface Constants
    {
        public static final String KEY_DEFAULT_RADIUS = "DefaultRadius";
        public static final String KEY_RADIUS = "Radius";
        public static final String KEY_BIOMES = "Biomes";
        public static final String KEY_MASK = "Mask";
        public static final String SEED_OFFSET_MASK = "InterpolationMask";
        public static final String ERROR_MISSING_PROPERTY = "Missing property %s";
        public static final String ERROR_INVALID_BIOME_LIST = "Invalid json-type for Biomes property. Must be an array!";
        public static final String ERROR_INVALID_BIOME_ENTRY = "Invalid json-type for biome entry. Must be an object!";
        public static final String ERROR_DUPLICATE_BIOME = "Duplicate biome detected in interpolation rules";
        public static final String ERROR_BIOME_RADIUS = "Biome interpolation radius %s is outside the range 0-%s";
        public static final String ERROR_DEFAULT_RADIUS = "Default biome interpolation radius %s lies outside the range 0-5";
    }
}
