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

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

import com.hypixel.hytale.server.worldgen.climate.ClimateColor;
import com.hypixel.hytale.server.worldgen.climate.ClimateType;
import com.hypixel.hytale.server.worldgen.climate.ClimateMaskProvider;
import java.util.Set;
import com.hypixel.hytale.server.worldgen.zone.ZoneColorMapping;
import javax.annotation.Nullable;
import com.hypixel.hytale.procedurallib.json.PointGeneratorJsonLoader;
import com.hypixel.hytale.procedurallib.logic.point.IPointGenerator;
import java.util.HashMap;
import com.google.gson.JsonElement;
import java.nio.file.Path;
import javax.annotation.Nonnull;
import com.hypixel.hytale.procedurallib.json.SeedString;
import java.util.Map;
import com.hypixel.hytale.server.worldgen.zone.Zone;
import com.hypixel.hytale.server.worldgen.chunk.MaskProvider;
import com.hypixel.hytale.server.worldgen.zone.ZonePatternProvider;
import com.hypixel.hytale.server.worldgen.SeedStringResource;
import com.hypixel.hytale.procedurallib.json.JsonLoader;

public class ZonePatternProviderJsonLoader extends JsonLoader<SeedStringResource, ZonePatternProvider>
{
    protected final MaskProvider maskProvider;
    protected Zone[] zones;
    protected Map<String, Zone> zoneLookup;
    
    public ZonePatternProviderJsonLoader(@Nonnull final SeedString<SeedStringResource> seed, final Path dataFolder, final JsonElement json, final MaskProvider maskProvider) {
        super(seed.append(".ZonePatternGenerator"), dataFolder, json);
        this.zoneLookup = Map.of();
        this.maskProvider = maskProvider;
    }
    
    public void setZones(final Zone[] zones) {
        this.zones = zones;
        this.zoneLookup = new HashMap<String, Zone>();
        for (final Zone zone : zones) {
            this.zoneLookup.put(zone.name(), zone);
        }
    }
    
    @Nonnull
    @Override
    public ZonePatternProvider load() {
        return new ZonePatternProvider(this.loadGridGenerator(), this.zones, this.loadUniqueZoneCandidates(), this.maskProvider, this.loadColorMapping());
    }
    
    @Nullable
    protected IPointGenerator loadGridGenerator() {
        return new PointGeneratorJsonLoader(this.seed, this.dataFolder, this.get("GridGenerator")).load();
    }
    
    @Nonnull
    protected ZoneColorMapping loadColorMapping() {
        if (!this.has("MaskMapping")) {
            throw new IllegalArgumentException("Could not find mappings for colors in mask file. Keyword: MaskMapping");
        }
        final ZoneColorMapping colorMapping = new ZoneColorMappingJsonLoader((SeedString<SeedStringResource>)this.seed, this.dataFolder, this.get("MaskMapping"), this.zoneLookup).load();
        this.ensureMaskIntegrity(colorMapping);
        return colorMapping;
    }
    
    @Nonnull
    public Set<String> loadZoneRequirement() {
        return new ZoneRequirementJsonLoader((SeedString<SeedStringResource>)this.seed, this.dataFolder, this.json).load();
    }
    
    protected void ensureMaskIntegrity(@Nonnull final ZoneColorMapping zoneColorMapping) {
        final MaskProvider maskProvider = this.maskProvider;
        if (maskProvider instanceof final ClimateMaskProvider climateMask) {
            for (final ClimateType parent : climateMask.getGraph().getParents()) {
                if (parent.children.length == 0) {
                    validateMapping(parent, parent, parent.color, zoneColorMapping, "");
                    validateMapping(parent, parent, parent.island, zoneColorMapping, "Island");
                }
                else {
                    for (final ClimateType child : parent.children) {
                        validateMapping(parent, child, child.color, zoneColorMapping, "");
                        validateMapping(parent, child, child.island, zoneColorMapping, "Island.");
                    }
                }
            }
        }
        else {
            this.maskProvider.getFuzzyZoom().getExactZoom().getDistanceProvider().getColors().forEach(rgb -> {
                if (zoneColorMapping.get(rgb) == null) {
                    throw new NullPointerException(Integer.toHexString(rgb));
                }
            });
        }
    }
    
    protected Zone.UniqueCandidate[] loadUniqueZoneCandidates() {
        final MaskProvider maskProvider = this.maskProvider;
        if (maskProvider instanceof final ClimateMaskProvider climateMask) {
            return climateMask.getUniqueZoneCandidates(this.zoneLookup);
        }
        final Zone.UniqueEntry[] uniqueZones = new UniqueZoneEntryJsonLoader((SeedString<SeedStringResource>)this.seed, this.dataFolder, this.get("UniqueZones"), this.zoneLookup).load();
        return this.maskProvider.generateUniqueZoneCandidates(uniqueZones, 100);
    }
    
    protected static void validateMapping(@Nullable final ClimateType parent, @Nonnull final ClimateType type, @Nonnull final ClimateColor color, final ZoneColorMapping mapping, final String prefix) {
        if (mapping.get(color.land) == null) {
            throw new Error(prefix + "Color is not mapped in climate type: " + ClimateType.name(parent, type));
        }
        if (mapping.get(color.shore) == null) {
            throw new Error(prefix + "Shore is not mapped in climate type: " + ClimateType.name(parent, type));
        }
        if (mapping.get(color.ocean) == null) {
            throw new Error(prefix + "Ocean is not mapped in climate type: " + ClimateType.name(parent, type));
        }
        if (mapping.get(color.shallowOcean) == null) {
            throw new Error(prefix + "ShallowOcean is not mapped in climate type: " + ClimateType.name(parent, type));
        }
    }
    
    public interface Constants
    {
        public static final String KEY_GRID_GENERATOR = "GridGenerator";
        public static final String KEY_UNIQUE_ZONES = "UniqueZones";
        public static final String KEY_MASK_MAPPING = "MaskMapping";
        public static final String ERROR_UNMAPPED_COLOR = "Mask image contains unmapped color! #%s";
        public static final String ERROR_NO_MAPPING = "Could not find mappings for colors in mask file. Keyword: MaskMapping";
        public static final int UNIQUE_ZONE_CANDIDATE_POS_LIMIT = 100;
    }
}
