package net.minecraft.client.gui.font;

import net.minecraft.client.renderer.texture.AbstractTexture;
import java.util.Set;
import java.util.Iterator;
import it.unimi.dsi.fastutil.ints.IntSet;
import java.util.function.Consumer;
import java.util.function.Predicate;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import net.minecraft.util.Mth;
import com.google.common.collect.Sets;
import it.unimi.dsi.fastutil.ints.IntCollection;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import net.minecraft.client.gui.font.glyphs.WhiteGlyph;
import com.mojang.blaze3d.font.RawGlyph;
import net.minecraft.client.gui.font.glyphs.MissingGlyph;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import com.google.common.collect.Lists;
import it.unimi.dsi.fastutil.ints.IntList;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import com.mojang.blaze3d.font.GlyphProvider;
import java.util.List;
import net.minecraft.client.gui.font.glyphs.BakedGlyph;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.client.renderer.texture.TextureManager;
import java.util.Random;
import com.mojang.blaze3d.font.GlyphInfo;
import net.minecraft.client.gui.font.glyphs.EmptyGlyph;

public class FontSet implements AutoCloseable {
    private static final EmptyGlyph SPACE_GLYPH;
    private static final GlyphInfo SPACE_INFO;
    private static final Random RANDOM;
    private final TextureManager textureManager;
    private final ResourceLocation name;
    private BakedGlyph missingGlyph;
    private BakedGlyph whiteGlyph;
    private final List<GlyphProvider> providers;
    private final Int2ObjectMap<BakedGlyph> glyphs;
    private final Int2ObjectMap<GlyphInfo> glyphInfos;
    private final Int2ObjectMap<IntList> glyphsByWidth;
    private final List<FontTexture> textures;
    
    public FontSet(final TextureManager elw, final ResourceLocation uh) {
        this.providers = Lists.newArrayList();
        this.glyphs = (Int2ObjectMap<BakedGlyph>)new Int2ObjectOpenHashMap();
        this.glyphInfos = (Int2ObjectMap<GlyphInfo>)new Int2ObjectOpenHashMap();
        this.glyphsByWidth = (Int2ObjectMap<IntList>)new Int2ObjectOpenHashMap();
        this.textures = Lists.newArrayList();
        this.textureManager = elw;
        this.name = uh;
    }
    
    public void reload(final List<GlyphProvider> list) {
        this.closeProviders();
        this.closeTextures();
        this.glyphs.clear();
        this.glyphInfos.clear();
        this.glyphsByWidth.clear();
        this.missingGlyph = this.stitch(MissingGlyph.INSTANCE);
        this.whiteGlyph = this.stitch(WhiteGlyph.INSTANCE);
        final IntSet intSet3 = (IntSet)new IntOpenHashSet();
        for (final GlyphProvider dga5 : list) {
            intSet3.addAll((IntCollection)dga5.getSupportedGlyphs());
        }
        final Set<GlyphProvider> set4 = Sets.newHashSet();
        final Iterator<GlyphProvider> iterator2;
        GlyphProvider dga6;
        GlyphInfo dfz7;
        final Set<GlyphProvider> set5;
        intSet3.forEach(integer -> {
            list.iterator();
            while (iterator2.hasNext()) {
                dga6 = iterator2.next();
                dfz7 = ((integer == 32) ? FontSet.SPACE_INFO : dga6.getGlyph(integer));
                if (dfz7 != null) {
                    set5.add(dga6);
                    if (dfz7 != MissingGlyph.INSTANCE) {
                        ((IntList)this.glyphsByWidth.computeIfAbsent(Mth.ceil(dfz7.getAdvance(false)), integer -> new IntArrayList())).add(integer);
                        break;
                    }
                    else {
                        break;
                    }
                }
            }
            return;
        });
        list.stream().filter(set4::contains).forEach(this.providers::add);
    }
    
    @Override
    public void close() {
        this.closeProviders();
        this.closeTextures();
    }
    
    private void closeProviders() {
        for (final GlyphProvider dga3 : this.providers) {
            dga3.close();
        }
        this.providers.clear();
    }
    
    private void closeTextures() {
        for (final FontTexture dou3 : this.textures) {
            dou3.close();
        }
        this.textures.clear();
    }
    
    public GlyphInfo getGlyphInfo(final int integer) {
        return (GlyphInfo)this.glyphInfos.computeIfAbsent(integer, integer -> (integer == 32) ? FontSet.SPACE_INFO : this.getRaw(integer));
    }
    
    private RawGlyph getRaw(final int integer) {
        for (final GlyphProvider dga4 : this.providers) {
            final RawGlyph dgb5 = dga4.getGlyph(integer);
            if (dgb5 != null) {
                return dgb5;
            }
        }
        return MissingGlyph.INSTANCE;
    }
    
    public BakedGlyph getGlyph(final int integer) {
        return (BakedGlyph)this.glyphs.computeIfAbsent(integer, integer -> (integer == 32) ? FontSet.SPACE_GLYPH : this.stitch(this.getRaw(integer)));
    }
    
    private BakedGlyph stitch(final RawGlyph dgb) {
        for (final FontTexture dou4 : this.textures) {
            final BakedGlyph dow5 = dou4.add(dgb);
            if (dow5 != null) {
                return dow5;
            }
        }
        final FontTexture dou5 = new FontTexture(new ResourceLocation(this.name.getNamespace(), this.name.getPath() + "/" + this.textures.size()), dgb.isColored());
        this.textures.add(dou5);
        this.textureManager.register(dou5.getName(), dou5);
        final BakedGlyph dow6 = dou5.add(dgb);
        return (dow6 == null) ? this.missingGlyph : dow6;
    }
    
    public BakedGlyph getRandomGlyph(final GlyphInfo dfz) {
        final IntList intList3 = (IntList)this.glyphsByWidth.get(Mth.ceil(dfz.getAdvance(false)));
        if (intList3 != null && !intList3.isEmpty()) {
            return this.getGlyph(intList3.getInt(FontSet.RANDOM.nextInt(intList3.size())));
        }
        return this.missingGlyph;
    }
    
    public BakedGlyph whiteGlyph() {
        return this.whiteGlyph;
    }
    
    static {
        SPACE_GLYPH = new EmptyGlyph();
        SPACE_INFO = (() -> 4.0f);
        RANDOM = new Random();
    }
}
