package net.minecraft.server.packs.resources;

import org.apache.logging.log4j.LogManager;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.function.Function;
import net.minecraft.util.Unit;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.Collections;
import java.util.Collection;
import java.util.function.Predicate;
import java.io.IOException;
import java.io.FileNotFoundException;
import net.minecraft.resources.ResourceLocation;
import java.util.Iterator;
import net.minecraft.server.packs.Pack;
import com.google.common.collect.Sets;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import net.minecraft.server.packs.PackType;
import java.util.Set;
import java.util.List;
import java.util.Map;
import org.apache.logging.log4j.Logger;

public class SimpleReloadableResourceManager implements ReloadableResourceManager {
    private static final Logger LOGGER;
    private final Map<String, FallbackResourceManager> namespacedPacks;
    private final List<PreparableReloadListener> listeners;
    private final List<PreparableReloadListener> recentlyRegistered;
    private final Set<String> namespaces;
    private final PackType type;
    private final Thread mainThread;
    
    public SimpleReloadableResourceManager(final PackType yf, final Thread thread) {
        this.namespacedPacks = Maps.newHashMap();
        this.listeners = Lists.newArrayList();
        this.recentlyRegistered = Lists.newArrayList();
        this.namespaces = Sets.newLinkedHashSet();
        this.type = yf;
        this.mainThread = thread;
    }
    
    public void add(final Pack ye) {
        for (final String string4 : ye.getNamespaces(this.type)) {
            this.namespaces.add(string4);
            FallbackResourceManager yv5 = this.namespacedPacks.get(string4);
            if (yv5 == null) {
                yv5 = new FallbackResourceManager(this.type, string4);
                this.namespacedPacks.put(string4, yv5);
            }
            yv5.add(ye);
        }
    }
    
    @Override
    public Set<String> getNamespaces() {
        return this.namespaces;
    }
    
    @Override
    public Resource getResource(final ResourceLocation sm) throws IOException {
        final ResourceManager zb3 = this.namespacedPacks.get(sm.getNamespace());
        if (zb3 != null) {
            return zb3.getResource(sm);
        }
        throw new FileNotFoundException(sm.toString());
    }
    
    @Override
    public boolean hasResource(final ResourceLocation sm) {
        final ResourceManager zb3 = this.namespacedPacks.get(sm.getNamespace());
        return zb3 != null && zb3.hasResource(sm);
    }
    
    @Override
    public List<Resource> getResources(final ResourceLocation sm) throws IOException {
        final ResourceManager zb3 = this.namespacedPacks.get(sm.getNamespace());
        if (zb3 != null) {
            return zb3.getResources(sm);
        }
        throw new FileNotFoundException(sm.toString());
    }
    
    @Override
    public Collection<ResourceLocation> listResources(final String string, final Predicate<String> predicate) {
        final Set<ResourceLocation> set4 = Sets.newHashSet();
        for (final FallbackResourceManager yv6 : this.namespacedPacks.values()) {
            set4.addAll(yv6.listResources(string, predicate));
        }
        final List<ResourceLocation> list5 = Lists.newArrayList(set4);
        Collections.<ResourceLocation>sort(list5);
        return list5;
    }
    
    private void clear() {
        this.namespacedPacks.clear();
        this.namespaces.clear();
    }
    
    @Override
    public CompletableFuture<Unit> reload(final Executor executor1, final Executor executor2, final List<Pack> list, final CompletableFuture<Unit> completableFuture) {
        final ReloadInstance yy6 = this.createFullReload(executor1, executor2, completableFuture, list);
        return yy6.done();
    }
    
    @Override
    public void registerReloadListener(final PreparableReloadListener yw) {
        this.listeners.add(yw);
        this.recentlyRegistered.add(yw);
    }
    
    protected ReloadInstance createReload(final Executor executor1, final Executor executor2, final List<PreparableReloadListener> list, final CompletableFuture<Unit> completableFuture) {
        ReloadInstance yy6;
        if (SimpleReloadableResourceManager.LOGGER.isDebugEnabled()) {
            yy6 = new ProfiledReloadInstance(this, Lists.newArrayList(list), executor1, executor2, completableFuture);
        }
        else {
            yy6 = SimpleReloadInstance.of(this, Lists.newArrayList(list), executor1, executor2, completableFuture);
        }
        this.recentlyRegistered.clear();
        return yy6;
    }
    
    @Override
    public ReloadInstance createFullReload(final Executor executor1, final Executor executor2, final CompletableFuture<Unit> completableFuture, final List<Pack> list) {
        this.clear();
        SimpleReloadableResourceManager.LOGGER.info("Reloading ResourceManager: {}", list.stream().map(Pack::getName).collect(Collectors.joining(", ")));
        for (final Pack ye7 : list) {
            try {
                this.add(ye7);
            }
            catch (Exception exception8) {
                SimpleReloadableResourceManager.LOGGER.error("Failed to add resource pack {}", ye7.getName(), exception8);
                return new FailingReloadInstance(new ResourcePackLoadingFailure(ye7, exception8));
            }
        }
        return this.createReload(executor1, executor2, this.listeners, completableFuture);
    }
    
    static {
        LOGGER = LogManager.getLogger();
    }
    
    public static class ResourcePackLoadingFailure extends RuntimeException {
        private final Pack pack;
        
        public ResourcePackLoadingFailure(final Pack ye, final Throwable throwable) {
            super(ye.getName(), throwable);
            this.pack = ye;
        }
        
        public Pack getPack() {
            return this.pack;
        }
    }
    
    static class FailingReloadInstance implements ReloadInstance {
        private final ResourcePackLoadingFailure exception;
        private final CompletableFuture<Unit> failedFuture;
        
        public FailingReloadInstance(final ResourcePackLoadingFailure b) {
            this.exception = b;
            (this.failedFuture = new CompletableFuture<Unit>()).completeExceptionally(b);
        }
        
        @Override
        public CompletableFuture<Unit> done() {
            return this.failedFuture;
        }
        
        @Override
        public float getActualProgress() {
            return 0.0f;
        }
        
        @Override
        public boolean isApplying() {
            return false;
        }
        
        @Override
        public boolean isDone() {
            return true;
        }
        
        @Override
        public void checkExceptions() {
            throw this.exception;
        }
    }
}
