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

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

import com.hypixel.hytale.common.map.IWeightedMap;
import java.util.Iterator;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.hypixel.hytale.server.worldgen.loader.climate.ClimateMaskJsonLoader;
import java.util.Random;
import com.hypixel.hytale.math.util.FastRandom;
import com.hypixel.hytale.common.map.WeightedMap;
import com.hypixel.hytale.common.util.ArrayUtil;
import com.google.gson.JsonParser;
import java.io.Reader;
import com.google.gson.stream.JsonReader;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.worldgen.zone.Zone;
import com.hypixel.hytale.server.worldgen.loader.context.FileLoadingContext;
import com.hypixel.hytale.server.worldgen.loader.zone.ZonePatternProviderJsonLoader;
import com.hypixel.hytale.server.worldgen.prefab.PrefabStoreRoot;
import com.hypixel.hytale.server.worldgen.chunk.MaskProvider;
import com.hypixel.hytale.math.vector.Vector2i;
import com.google.gson.JsonObject;
import com.hypixel.hytale.server.worldgen.loader.context.FileContextLoader;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import com.hypixel.hytale.procedurallib.json.SeedString;
import com.hypixel.hytale.server.worldgen.chunk.ChunkGenerator;
import com.hypixel.hytale.server.worldgen.SeedStringResource;
import com.hypixel.hytale.procedurallib.json.Loader;

public class ChunkGeneratorJsonLoader extends Loader<SeedStringResource, ChunkGenerator>
{
    public ChunkGeneratorJsonLoader(final SeedString<SeedStringResource> seed, final Path dataFolder) {
        super(seed, dataFolder);
    }
    
    @Nonnull
    @Override
    public ChunkGenerator load() {
        final Path worldFile = this.dataFolder.resolve("World.json").toAbsolutePath();
        if (!Files.exists(worldFile, new LinkOption[0])) {
            throw new IllegalArgumentException(String.valueOf(worldFile));
        }
        if (!Files.isReadable(worldFile)) {
            throw new IllegalArgumentException(String.valueOf(worldFile));
        }
        final JsonObject worldJson = this.loadWorldJson(worldFile);
        final Vector2i worldSize = this.loadWorldSize(worldJson);
        final Vector2i worldOffset = this.loadWorldOffset(worldJson);
        final MaskProvider maskProvider = this.loadMaskProvider(worldJson, worldSize, worldOffset);
        final PrefabStoreRoot prefabStore = this.loadPrefabStore(worldJson);
        final Path overrideDataFolder = this.loadOverrideDataFolderPath(worldJson, this.dataFolder);
        ((SeedStringResource)this.seed.get()).setPrefabStore(prefabStore);
        ((SeedStringResource)this.seed.get()).setDataFolder(overrideDataFolder);
        final ZonePatternProviderJsonLoader loader = this.loadZonePatternGenerator(maskProvider);
        final FileLoadingContext loadingContext = new FileContextLoader(overrideDataFolder, loader.loadZoneRequirement()).load();
        final Zone[] zones = new ZonesJsonLoader((SeedString<SeedStringResource>)this.seed, overrideDataFolder, loadingContext).load();
        loader.setZones(zones);
        return new ChunkGenerator(loader.load(), overrideDataFolder);
    }
    
    @Nonnull
    private Path loadOverrideDataFolderPath(@Nonnull final JsonObject worldJson, @Nonnull final Path dataFolder) {
        if (!worldJson.has("OverrideDataFolder")) {
            return dataFolder;
        }
        final Path overrideFolder = dataFolder.resolve(worldJson.get("OverrideDataFolder").getAsString()).normalize();
        final Path parent = dataFolder.getParent();
        if (!overrideFolder.startsWith(parent) || !Files.exists(overrideFolder, new LinkOption[0])) {
            throw new Error(String.format("Override folder '%s' must exist within: '%s'", overrideFolder.getFileName(), parent));
        }
        return overrideFolder;
    }
    
    @Nonnull
    protected JsonObject loadWorldJson(@Nonnull final Path file) {
        JsonObject worldJson;
        try (final JsonReader reader = new JsonReader(Files.newBufferedReader(file))) {
            worldJson = JsonParser.parseReader(reader).getAsJsonObject();
        }
        catch (final Throwable e) {
            throw new Error(String.format("Could not read JSON configuration for world. File: %s", file), e);
        }
        return worldJson;
    }
    
    @Nonnull
    protected Vector2i loadWorldSize(@Nonnull final JsonObject worldJson) {
        int width = 0;
        int height = 0;
        if (worldJson.has("Width")) {
            width = worldJson.get("Width").getAsInt();
        }
        if (worldJson.has("Height")) {
            height = worldJson.get("Height").getAsInt();
        }
        return new Vector2i(width, height);
    }
    
    @Nonnull
    protected Vector2i loadWorldOffset(@Nonnull final JsonObject worldJson) {
        int offsetX = 0;
        int offsetY = 0;
        if (worldJson.has("OffsetX")) {
            offsetX = worldJson.get("OffsetX").getAsInt();
        }
        if (worldJson.has("OffsetY")) {
            offsetY = worldJson.get("OffsetY").getAsInt();
        }
        return new Vector2i(offsetX, offsetY);
    }
    
    @Nonnull
    protected MaskProvider loadMaskProvider(@Nonnull final JsonObject worldJson, final Vector2i worldSize, final Vector2i worldOffset) {
        final WeightedMap.Builder<String> builder = WeightedMap.builder(ArrayUtil.EMPTY_STRING_ARRAY);
        final JsonElement masks = worldJson.get("Masks");
        if (masks == null) {
            builder.put("Mask.png", 1.0);
        }
        else if (masks.isJsonPrimitive()) {
            builder.put(masks.getAsString(), 1.0);
        }
        else if (masks.isJsonArray()) {
            final JsonArray arr = masks.getAsJsonArray();
            if (arr.isEmpty()) {
                builder.put("Mask.png", 1.0);
            }
            else {
                for (int i = 0; i < arr.size(); ++i) {
                    builder.put(arr.get(i).getAsString(), 1.0);
                }
            }
        }
        else if (masks.isJsonObject()) {
            final JsonObject obj = masks.getAsJsonObject();
            if (obj.size() == 0) {
                builder.put("Mask.png", 1.0);
            }
            else {
                for (final String key : obj.keySet()) {
                    builder.put(key, obj.get(key).getAsDouble());
                }
            }
        }
        final IWeightedMap<String> weightedMap = builder.build();
        final Path maskFile = this.dataFolder.resolve(weightedMap.get(new FastRandom(this.seed.hashCode())));
        if (maskFile.getFileName().endsWith("Mask.json")) {
            return new ClimateMaskJsonLoader(this.seed, this.dataFolder, maskFile).load();
        }
        return new MaskProviderJsonLoader((SeedString<SeedStringResource>)this.seed, this.dataFolder, worldJson.get("Randomizer"), maskFile, worldSize, worldOffset).load();
    }
    
    @Nonnull
    protected PrefabStoreRoot loadPrefabStore(@Nonnull final JsonObject worldJson) {
        if (worldJson.has("PrefabStore")) {
            final JsonElement storeJson = worldJson.get("PrefabStore");
            if (!storeJson.isJsonPrimitive() || !storeJson.getAsJsonPrimitive().isString()) {
                throw new Error("Expected 'PrefabStore' to be a string");
            }
            final String store = storeJson.getAsString();
            try {
                return PrefabStoreRoot.valueOf(store);
            }
            catch (final IllegalArgumentException e) {
                throw new Error("Invalid PrefabStore name: " + store, (Throwable)e);
            }
        }
        return PrefabStoreRoot.DEFAULT;
    }
    
    @Nonnull
    protected ZonePatternProviderJsonLoader loadZonePatternGenerator(final MaskProvider maskProvider) {
        final Path zoneFile = this.dataFolder.resolve("Zones.json");
        try (final JsonReader reader = new JsonReader(Files.newBufferedReader(zoneFile))) {
            final JsonObject zoneJson = JsonParser.parseReader(reader).getAsJsonObject();
            return new ZonePatternProviderJsonLoader((SeedString<SeedStringResource>)this.seed, this.dataFolder, zoneJson, maskProvider);
        }
        catch (final Throwable e) {
            throw new Error(String.format("Failed to read zone configuration file! File: %s", zoneFile.toString()), e);
        }
    }
    
    public interface Constants
    {
        public static final String KEY_WIDTH = "Width";
        public static final String KEY_HEIGHT = "Height";
        public static final String KEY_OFFSET_X = "OffsetX";
        public static final String KEY_OFFSET_Y = "OffsetY";
        public static final String KEY_RANDOMIZER = "Randomizer";
        public static final String KEY_MASKS = "Masks";
        public static final String KEY_PREFAB_STORE = "PrefabStore";
        public static final String OVERRIDE_DATA_FOLDER = "OverrideDataFolder";
        public static final String FILE_WORLD_JSON = "World.json";
        public static final String FILE_ZONES_JSON = "Zones.json";
        public static final String FILE_MASK_JSON = "Mask.json";
        public static final String FILE_MASK_PNG = "Mask.png";
        public static final String ERROR_WORLD_FILE_EXIST = "World configuration file does NOT exist! File not found: %s";
        public static final String ERROR_WORLD_FILE_READ = "World configuration file is NOT readable! File: %s";
        public static final String ERROR_WORLD_JSON_CORRUPT = "Could not read JSON configuration for world. File: %s";
        public static final String ERROR_ZONE_FILE = "Failed to read zone configuration file! File: %s";
    }
}
