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 java.util.stream.Stream;
import org.apache.logging.log4j.util.Supplier;
import net.minecraft.util.Unit;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.Collections;
import com.google.common.collect.ImmutableSet;
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 com.google.common.collect.Sets;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import net.minecraft.server.packs.PackType;
import net.minecraft.server.packs.PackResources;
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 List<PackResources> packs;
    private final PackType type;
    
    public SimpleReloadableResourceManager(final PackType aaf) {
        this.namespacedPacks = Maps.newHashMap();
        this.listeners = Lists.newArrayList();
        this.recentlyRegistered = Lists.newArrayList();
        this.namespaces = Sets.newLinkedHashSet();
        this.packs = Lists.newArrayList();
        this.type = aaf;
    }
    
    public void add(final PackResources aae) {
        this.packs.add(aae);
        for (final String string4 : aae.getNamespaces(this.type)) {
            this.namespaces.add(string4);
            FallbackResourceManager aaw5 = this.namespacedPacks.get(string4);
            if (aaw5 == null) {
                aaw5 = new FallbackResourceManager(this.type, string4);
                this.namespacedPacks.put(string4, aaw5);
            }
            aaw5.add(aae);
        }
    }
    
    @Override
    public Set<String> getNamespaces() {
        return this.namespaces;
    }
    
    @Override
    public Resource getResource(final ResourceLocation uh) throws IOException {
        final ResourceManager abc3 = this.namespacedPacks.get(uh.getNamespace());
        if (abc3 != null) {
            return abc3.getResource(uh);
        }
        throw new FileNotFoundException(uh.toString());
    }
    
    @Override
    public boolean hasResource(final ResourceLocation uh) {
        final ResourceManager abc3 = this.namespacedPacks.get(uh.getNamespace());
        return abc3 != null && abc3.hasResource(uh);
    }
    
    @Override
    public List<Resource> getResources(final ResourceLocation uh) throws IOException {
        final ResourceManager abc3 = this.namespacedPacks.get(uh.getNamespace());
        if (abc3 != null) {
            return abc3.getResources(uh);
        }
        throw new FileNotFoundException(uh.toString());
    }
    
    @Override
    public Collection<ResourceLocation> listResources(final ResourceLocation uh, final Predicate<String> predicate) {
        final ResourceManager abc4 = this.namespacedPacks.get(uh.getNamespace());
        if (abc4 != null) {
            return abc4.listResources(uh.getPath(), predicate);
        }
        return ImmutableSet.of();
    }
    
    @Override
    public Collection<ResourceLocation> listResources(final String string, final Predicate<String> predicate) {
        final Set<ResourceLocation> set4 = Sets.newHashSet();
        for (final FallbackResourceManager aaw6 : this.namespacedPacks.values()) {
            set4.addAll(aaw6.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();
        this.packs.forEach(PackResources::close);
        this.packs.clear();
    }
    
    @Override
    public void close() {
        this.clear();
    }
    
    @Override
    public void registerReloadListener(final PreparableReloadListener aax) {
        this.listeners.add(aax);
        this.recentlyRegistered.add(aax);
    }
    
    protected ReloadInstance createReload(final Executor executor1, final Executor executor2, final List<PreparableReloadListener> list, final CompletableFuture<Unit> completableFuture) {
        ReloadInstance aaz6;
        if (SimpleReloadableResourceManager.LOGGER.isDebugEnabled()) {
            aaz6 = new ProfiledReloadInstance(this, Lists.newArrayList(list), executor1, executor2, completableFuture);
        }
        else {
            aaz6 = SimpleReloadInstance.of(this, Lists.newArrayList(list), executor1, executor2, completableFuture);
        }
        this.recentlyRegistered.clear();
        return aaz6;
    }
    
    @Override
    public ReloadInstance createFullReload(final Executor executor1, final Executor executor2, final CompletableFuture<Unit> completableFuture, final List<PackResources> list) {
        this.clear();
        SimpleReloadableResourceManager.LOGGER.info("Reloading ResourceManager: {}", new Supplier[] { () -> list.stream().map(PackResources::getName).collect(Collectors.joining(", ")) });
        for (final PackResources aae7 : list) {
            try {
                this.add(aae7);
            }
            catch (Exception exception8) {
                SimpleReloadableResourceManager.LOGGER.error("Failed to add resource pack {}", aae7.getName(), exception8);
                return new FailingReloadInstance(new ResourcePackLoadingFailure(aae7, exception8));
            }
        }
        return this.createReload(executor1, executor2, this.listeners, completableFuture);
    }
    
    @Override
    public Stream<PackResources> listPacks() {
        return this.packs.stream();
    }
    
    static {
        LOGGER = LogManager.getLogger();
    }
    
    public static class ResourcePackLoadingFailure extends RuntimeException {
        private final PackResources pack;
        
        public ResourcePackLoadingFailure(final PackResources aae, final Throwable throwable) {
            super(aae.getName(), throwable);
            this.pack = aae;
        }
        
        public PackResources 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;
        }
    }
}
