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

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

import java.util.function.Function;
import java.util.Iterator;
import com.google.gson.JsonElement;
import java.io.BufferedReader;
import java.util.function.BiConsumer;
import com.hypixel.hytale.server.worldgen.prefab.PrefabCategory;
import java.util.Objects;
import java.io.Reader;
import com.google.gson.JsonParser;
import java.nio.file.LinkOption;
import javax.annotation.Nonnull;
import java.util.stream.Stream;
import java.io.IOException;
import com.hypixel.hytale.logger.HytaleLogger;
import java.util.logging.Level;
import com.hypixel.hytale.server.worldgen.util.LogUtil;
import java.nio.file.Files;
import java.nio.file.FileVisitOption;
import java.util.Set;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.function.BiPredicate;
import java.nio.file.Path;
import java.util.Comparator;

public class FileContextLoader
{
    private static final Comparator<Path> ZONES_ORDER;
    private static final Comparator<Path> BIOME_ORDER;
    private static final BiPredicate<Path, BasicFileAttributes> ZONE_FILTER;
    private static final BiPredicate<Path, BasicFileAttributes> BIOME_FILTER;
    private final Path dataFolder;
    private final Set<String> zoneRequirement;
    
    public FileContextLoader(final Path dataFolder, final Set<String> zoneRequirement) {
        this.dataFolder = dataFolder;
        this.zoneRequirement = zoneRequirement;
    }
    
    @Nonnull
    public FileLoadingContext load() {
        final FileLoadingContext context = new FileLoadingContext(this.dataFolder);
        final Path zonesFolder = this.dataFolder.resolve("Zones");
        try (final Stream<Path> stream = Files.find(zonesFolder, 1, FileContextLoader.ZONE_FILTER, new FileVisitOption[0])) {
            stream.sorted(FileContextLoader.ZONES_ORDER).forEach(path -> {
                final String zoneName = path.getFileName().toString();
                if (zoneName.startsWith("!")) {
                    LogUtil.getLogger().at(Level.INFO).log("Zone \"%s\" is disabled. Remove \"!\" from folder name to enable it.", zoneName);
                    return;
                }
                else if (!this.zoneRequirement.contains(zoneName)) {
                    return;
                }
                else {
                    final ZoneFileContext zone = loadZoneContext(zoneName, path, context);
                    context.getZones().register(zoneName, zone);
                    return;
                }
            });
        }
        catch (final IOException e) {
            HytaleLogger.getLogger().at(Level.SEVERE).withCause(e).log("Failed to load zones");
        }
        try {
            validateZones(context, this.zoneRequirement);
        }
        catch (final Error e2) {
            throw new Error("Failed to validate zones!", e2);
        }
        loadPrefabCategories(this.dataFolder, context);
        return context;
    }
    
    protected static void loadPrefabCategories(@Nonnull final Path folder, @Nonnull final FileLoadingContext context) {
        final Path path = folder.resolve("PrefabCategories.json");
        if (!Files.exists(path, new LinkOption[0])) {
            return;
        }
        try (final BufferedReader reader = Files.newBufferedReader(path)) {
            final JsonElement reader2 = JsonParser.parseReader(reader);
            final FileContext.Registry<PrefabCategory> prefabCategories = context.getPrefabCategories();
            Objects.requireNonNull(prefabCategories);
            PrefabCategory.parse(reader2, (BiConsumer<String, PrefabCategory>)prefabCategories::register);
        }
        catch (final IOException e) {
            throw new Error("Failed to open Categories.json", e);
        }
    }
    
    @Nonnull
    protected static ZoneFileContext loadZoneContext(final String name, @Nonnull final Path folder, @Nonnull final FileLoadingContext context) {
        try (final Stream<Path> stream = Files.find(folder, 1, FileContextLoader.BIOME_FILTER, new FileVisitOption[0])) {
            final ZoneFileContext zone = context.createZone(name, folder);
            stream.sorted(FileContextLoader.BIOME_ORDER).forEach(path -> {
                final BiomeFileContext.Type type = BiomeFileContext.getBiomeType(path);
                final String biomeName = parseName(path, type);
                final BiomeFileContext biome = zone.createBiome(biomeName, path, type);
                zone.getBiomes(type).register(biomeName, biome);
                return;
            });
            return zone;
        }
        catch (final IOException e) {
            throw new Error(String.format("Failed to list files in: %s", folder), e);
        }
    }
    
    protected static int compareBiomePaths(@Nonnull final Path a, @Nonnull final Path b) {
        final BiomeFileContext.Type typeA = BiomeFileContext.getBiomeType(a);
        final BiomeFileContext.Type typeB = BiomeFileContext.getBiomeType(b);
        final int result = typeA.compareTo(typeB);
        if (result != 0) {
            return result;
        }
        return a.getFileName().compareTo(b.getFileName());
    }
    
    protected static boolean isValidBiomeFile(@Nonnull final Path path) {
        if (Files.isDirectory(path, new LinkOption[0])) {
            return false;
        }
        final String filename = path.getFileName().toString();
        for (final BiomeFileContext.Type type : BiomeFileContext.Type.values()) {
            if (filename.endsWith(type.getSuffix()) && filename.startsWith(type.getPrefix())) {
                return true;
            }
        }
        return false;
    }
    
    protected static void validateZones(@Nonnull final FileLoadingContext context, @Nonnull final Set<String> zoneRequirement) throws Error {
        for (final String key : zoneRequirement) {
            context.getZones().get(key);
        }
    }
    
    @Nonnull
    private static String parseName(@Nonnull final Path path, @Nonnull final BiomeFileContext.Type type) {
        final String filename = path.getFileName().toString();
        final int start = type.getPrefix().length();
        final int end = filename.length() - type.getSuffix().length();
        return filename.substring(start, end);
    }
    
    static {
        ZONES_ORDER = Comparator.comparing((Function<? super Path, ? extends Comparable>)Path::getFileName);
        BIOME_ORDER = Comparator.comparing((Function<? super Path, ? extends Comparable>)BiomeFileContext::getBiomeType).thenComparing((Function<? super Path, ? extends Comparable>)Path::getFileName);
        ZONE_FILTER = ((path, attributes) -> Files.isDirectory(path, new LinkOption[0]));
        BIOME_FILTER = ((path, attributes) -> isValidBiomeFile(path));
    }
    
    public interface Constants
    {
        public static final int ZONE_SEARCH_DEPTH = 1;
        public static final int BIOME_SEARCH_DEPTH = 1;
        public static final String IDENTIFIER_DISABLE_ZONE = "!";
        public static final String INFO_ZONE_IS_DISABLED = "Zone \"%s\" is disabled. Remove \"!\" from folder name to enable it.";
        public static final String ERROR_LIST_FILES = "Failed to list files in: %s";
        public static final String ERROR_ZONE_VALIDATION = "Failed to validate zones!";
    }
}
