package net.minecraft.client.renderer.texture;

import org.apache.logging.log4j.LogManager;
import com.mojang.realmsclient.RealmsMainScreen;
import java.util.concurrent.CompletionStage;
import java.util.function.Function;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.screens.TitleScreen;
import net.minecraft.util.profiling.ProfilerFiller;
import com.mojang.blaze3d.platform.TextureUtil;
import java.util.Iterator;
import net.minecraft.client.Minecraft;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import javax.annotation.Nullable;
import net.minecraft.CrashReportCategory;
import net.minecraft.ReportedException;
import net.minecraft.CrashReport;
import java.io.IOException;
import com.mojang.blaze3d.systems.RenderSystem;
import com.google.common.collect.Sets;
import com.google.common.collect.Maps;
import net.minecraft.server.packs.resources.ResourceManager;
import java.util.Set;
import java.util.Map;
import net.minecraft.resources.ResourceLocation;
import org.apache.logging.log4j.Logger;
import net.minecraft.server.packs.resources.PreparableReloadListener;

public class TextureManager implements PreparableReloadListener, Tickable, AutoCloseable {
    private static final Logger LOGGER;
    public static final ResourceLocation INTENTIONAL_MISSING_TEXTURE;
    private final Map<ResourceLocation, AbstractTexture> byPath;
    private final Set<Tickable> tickableTextures;
    private final Map<String, Integer> prefixRegister;
    private final ResourceManager resourceManager;
    
    public TextureManager(final ResourceManager abc) {
        this.byPath = Maps.newHashMap();
        this.tickableTextures = Sets.newHashSet();
        this.prefixRegister = Maps.newHashMap();
        this.resourceManager = abc;
    }
    
    public void bind(final ResourceLocation uh) {
        if (!RenderSystem.isOnRenderThread()) {
            RenderSystem.recordRenderCall(() -> this._bind(uh));
        }
        else {
            this._bind(uh);
        }
    }
    
    private void _bind(final ResourceLocation uh) {
        AbstractTexture elj3 = this.byPath.get(uh);
        if (elj3 == null) {
            elj3 = new SimpleTexture(uh);
            this.register(uh, elj3);
        }
        elj3.bind();
    }
    
    public void register(final ResourceLocation uh, AbstractTexture elj) {
        elj = this.loadTexture(uh, elj);
        final AbstractTexture elj2 = this.byPath.put(uh, elj);
        if (elj2 != elj) {
            if (elj2 != null && elj2 != MissingTextureAtlasSprite.getTexture()) {
                elj2.releaseId();
                this.tickableTextures.remove(elj2);
            }
            if (elj instanceof Tickable) {
                this.tickableTextures.add((Tickable)elj);
            }
        }
    }
    
    private AbstractTexture loadTexture(final ResourceLocation uh, final AbstractTexture elj) {
        try {
            elj.load(this.resourceManager);
            return elj;
        }
        catch (IOException iOException4) {
            if (uh != TextureManager.INTENTIONAL_MISSING_TEXTURE) {
                TextureManager.LOGGER.warn("Failed to load texture: {}", uh, iOException4);
            }
            return MissingTextureAtlasSprite.getTexture();
        }
        catch (Throwable throwable4) {
            final CrashReport j5 = CrashReport.forThrowable(throwable4, "Registering texture");
            final CrashReportCategory k6 = j5.addCategory("Resource location being registered");
            final AbstractTexture elj2 = elj;
            k6.setDetail("Resource location", uh);
            k6.setDetail("Texture object class", () -> elj2.getClass().getName());
            throw new ReportedException(j5);
        }
    }
    
    @Nullable
    public AbstractTexture getTexture(final ResourceLocation uh) {
        return this.byPath.get(uh);
    }
    
    public ResourceLocation register(final String string, final DynamicTexture ell) {
        Integer integer4 = this.prefixRegister.get(string);
        if (integer4 == null) {
            integer4 = 1;
        }
        else {
            ++integer4;
        }
        this.prefixRegister.put(string, integer4);
        final ResourceLocation uh5 = new ResourceLocation(String.format("dynamic/%s_%d", string, integer4));
        this.register(uh5, ell);
        return uh5;
    }
    
    public CompletableFuture<Void> preload(final ResourceLocation uh, final Executor executor) {
        if (!this.byPath.containsKey(uh)) {
            final PreloadedTexture elq4 = new PreloadedTexture(this.resourceManager, uh, executor);
            this.byPath.put(uh, elq4);
            return elq4.getFuture().thenRunAsync(() -> this.register(uh, elq4), TextureManager::execute);
        }
        return CompletableFuture.<Void>completedFuture((Void)null);
    }
    
    private static void execute(final Runnable runnable) {
        Minecraft.getInstance().execute(() -> RenderSystem.recordRenderCall(runnable::run));
    }
    
    @Override
    public void tick() {
        for (final Tickable elx3 : this.tickableTextures) {
            elx3.tick();
        }
    }
    
    public void release(final ResourceLocation uh) {
        final AbstractTexture elj3 = this.getTexture(uh);
        if (elj3 != null) {
            TextureUtil.releaseTextureId(elj3.getId());
        }
    }
    
    @Override
    public void close() {
        this.byPath.values().forEach(AbstractTexture::releaseId);
        this.byPath.clear();
        this.tickableTextures.clear();
        this.prefixRegister.clear();
    }
    
    @Override
    public CompletableFuture<Void> reload(final PreparationBarrier a, final ResourceManager abc, final ProfilerFiller ami3, final ProfilerFiller ami4, final Executor executor5, final Executor executor6) {
        final Iterator<Map.Entry<ResourceLocation, AbstractTexture>> iterator5;
        Map.Entry<ResourceLocation, AbstractTexture> entry6;
        ResourceLocation uh7;
        AbstractTexture elj8;
        return CompletableFuture.allOf(TitleScreen.preloadResources(this, executor5), this.preload(AbstractWidget.WIDGETS_LOCATION, executor5)).thenCompose(a::wait).thenAcceptAsync(void3 -> {
            MissingTextureAtlasSprite.getTexture();
            RealmsMainScreen.updateTeaserImages(this.resourceManager);
            iterator5 = this.byPath.entrySet().iterator();
            while (iterator5.hasNext()) {
                entry6 = iterator5.next();
                uh7 = entry6.getKey();
                elj8 = entry6.getValue();
                if (elj8 == MissingTextureAtlasSprite.getTexture() && !uh7.equals(MissingTextureAtlasSprite.getLocation())) {
                    iterator5.remove();
                }
                else {
                    elj8.reset(this, abc, uh7, executor6);
                }
            }
        }, runnable -> RenderSystem.recordRenderCall(runnable::run));
    }
    
    static {
        LOGGER = LogManager.getLogger();
        INTENTIONAL_MISSING_TEXTURE = new ResourceLocation("");
    }
}
