package net.minecraft.client.gui.font;

import org.apache.logging.log4j.LogManager;
import net.minecraft.client.renderer.texture.AbstractTexture;
import java.util.Iterator;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
import it.unimi.dsi.fastutil.chars.CharArrayList;
import net.minecraft.util.Mth;
import com.google.common.collect.Sets;
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 it.unimi.dsi.fastutil.chars.Char2ObjectOpenHashMap;
import com.google.common.collect.Lists;
import it.unimi.dsi.fastutil.chars.CharList;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.chars.Char2ObjectMap;
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;
import org.apache.logging.log4j.Logger;

public class FontSet implements AutoCloseable {
    private static final Logger LOGGER;
    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 Char2ObjectMap<BakedGlyph> glyphs;
    private final Char2ObjectMap<GlyphInfo> glyphInfos;
    private final Int2ObjectMap<CharList> glyphsByWidth;
    private final List<FontTexture> textures;
    
    public FontSet(final TextureManager eak, final ResourceLocation sm) {
        this.providers = Lists.newArrayList();
        this.glyphs = (Char2ObjectMap<BakedGlyph>)new Char2ObjectOpenHashMap();
        this.glyphInfos = (Char2ObjectMap<GlyphInfo>)new Char2ObjectOpenHashMap();
        this.glyphsByWidth = (Int2ObjectMap<CharList>)new Int2ObjectOpenHashMap();
        this.textures = Lists.newArrayList();
        this.textureManager = eak;
        this.name = sm;
    }
    
    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 Set<GlyphProvider> set3 = Sets.newHashSet();
        for (char character4 = '\0'; character4 < '\uffff'; ++character4) {
            for (final GlyphProvider cwz6 : list) {
                final GlyphInfo cwy7 = (character4 == ' ') ? FontSet.SPACE_INFO : cwz6.getGlyph(character4);
                if (cwy7 != null) {
                    set3.add(cwz6);
                    if (cwy7 != MissingGlyph.INSTANCE) {
                        ((CharList)this.glyphsByWidth.computeIfAbsent(Mth.ceil(cwy7.getAdvance(false)), integer -> new CharArrayList())).add(character4);
                        break;
                    }
                    break;
                }
            }
        }
        list.stream().filter(set3::contains).forEach(this.providers::add);
    }
    
    @Override
    public void close() {
        this.closeProviders();
        this.closeTextures();
    }
    
    private void closeProviders() {
        for (final GlyphProvider cwz3 : this.providers) {
            cwz3.close();
        }
        this.providers.clear();
    }
    
    private void closeTextures() {
        for (final FontTexture deh3 : this.textures) {
            deh3.close();
        }
        this.textures.clear();
    }
    
    public GlyphInfo getGlyphInfo(final char character) {
        return (GlyphInfo)this.glyphInfos.computeIfAbsent(character, integer -> (integer == 32) ? FontSet.SPACE_INFO : this.getRaw((char)integer));
    }
    
    private RawGlyph getRaw(final char character) {
        for (final GlyphProvider cwz4 : this.providers) {
            final RawGlyph cxa5 = cwz4.getGlyph(character);
            if (cxa5 != null) {
                return cxa5;
            }
        }
        return MissingGlyph.INSTANCE;
    }
    
    public BakedGlyph getGlyph(final char character) {
        return (BakedGlyph)this.glyphs.computeIfAbsent(character, integer -> (integer == 32) ? FontSet.SPACE_GLYPH : this.stitch(this.getRaw((char)integer)));
    }
    
    private BakedGlyph stitch(final RawGlyph cxa) {
        for (final FontTexture deh4 : this.textures) {
            final BakedGlyph dej5 = deh4.add(cxa);
            if (dej5 != null) {
                return dej5;
            }
        }
        final FontTexture deh5 = new FontTexture(new ResourceLocation(this.name.getNamespace(), this.name.getPath() + "/" + this.textures.size()), cxa.isColored());
        this.textures.add(deh5);
        this.textureManager.register(deh5.getName(), deh5);
        final BakedGlyph dej6 = deh5.add(cxa);
        return (dej6 == null) ? this.missingGlyph : dej6;
    }
    
    public BakedGlyph getRandomGlyph(final GlyphInfo cwy) {
        final CharList charList3 = (CharList)this.glyphsByWidth.get(Mth.ceil(cwy.getAdvance(false)));
        if (charList3 != null && !charList3.isEmpty()) {
            return this.getGlyph(charList3.get(FontSet.RANDOM.nextInt(charList3.size())));
        }
        return this.missingGlyph;
    }
    
    public BakedGlyph whiteGlyph() {
        return this.whiteGlyph;
    }
    
    static {
        LOGGER = LogManager.getLogger();
        SPACE_GLYPH = new EmptyGlyph();
        SPACE_INFO = (() -> 4.0f);
        RANDOM = new Random();
    }
}
