package net.minecraft.client.gui.font.providers;

import net.minecraft.client.Minecraft;
import net.minecraft.util.GsonHelper;
import com.google.gson.JsonObject;
import org.apache.logging.log4j.LogManager;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import javax.annotation.Nullable;
import java.util.function.Function;
import com.mojang.blaze3d.font.RawGlyph;
import net.minecraft.server.packs.resources.Resource;
import java.util.Arrays;
import java.io.IOException;
import com.google.common.collect.Maps;
import com.mojang.blaze3d.platform.NativeImage;
import net.minecraft.resources.ResourceLocation;
import java.util.Map;
import net.minecraft.server.packs.resources.ResourceManager;
import org.apache.logging.log4j.Logger;
import com.mojang.blaze3d.font.GlyphProvider;

public class LegacyUnicodeBitmapsProvider implements GlyphProvider {
    private static final Logger LOGGER;
    private final ResourceManager resourceManager;
    private final byte[] sizes;
    private final String texturePattern;
    private final Map<ResourceLocation, NativeImage> textures;
    
    public LegacyUnicodeBitmapsProvider(final ResourceManager abc, final byte[] arr, final String string) {
        this.textures = Maps.newHashMap();
        this.resourceManager = abc;
        this.sizes = arr;
        this.texturePattern = string;
        for (int integer5 = 0; integer5 < 256; ++integer5) {
            final int integer6 = integer5 * 256;
            final ResourceLocation uh7 = this.getSheetLocation(integer6);
            try (final Resource abb8 = this.resourceManager.getResource(uh7);
                 final NativeImage dgs10 = NativeImage.read(NativeImage.Format.RGBA, abb8.getInputStream())) {
                if (dgs10.getWidth() == 256 && dgs10.getHeight() == 256) {
                    for (int integer7 = 0; integer7 < 256; ++integer7) {
                        final byte byte13 = arr[integer6 + integer7];
                        if (byte13 != 0 && getLeft(byte13) > getRight(byte13)) {
                            arr[integer6 + integer7] = 0;
                        }
                    }
                    continue;
                }
            }
            catch (IOException ex) {}
            Arrays.fill(arr, integer6, integer6 + 256, (byte)0);
        }
    }
    
    @Override
    public void close() {
        this.textures.values().forEach(NativeImage::close);
    }
    
    private ResourceLocation getSheetLocation(final int integer) {
        final ResourceLocation uh3 = new ResourceLocation(String.format(this.texturePattern, String.format("%02x", integer / 256)));
        return new ResourceLocation(uh3.getNamespace(), "textures/" + uh3.getPath());
    }
    
    @Nullable
    @Override
    public RawGlyph getGlyph(final int integer) {
        if (integer < 0 || integer > 65535) {
            return null;
        }
        final byte byte3 = this.sizes[integer];
        if (byte3 != 0) {
            final NativeImage dgs4 = this.textures.computeIfAbsent(this.getSheetLocation(integer), this::loadTexture);
            if (dgs4 != null) {
                final int integer2 = getLeft(byte3);
                return new Glyph(integer % 16 * 16 + integer2, (integer & 0xFF) / 16 * 16, getRight(byte3) - integer2, 16, dgs4);
            }
        }
        return null;
    }
    
    @Override
    public IntSet getSupportedGlyphs() {
        final IntSet intSet2 = (IntSet)new IntOpenHashSet();
        for (int integer3 = 0; integer3 < 65535; ++integer3) {
            if (this.sizes[integer3] != 0) {
                intSet2.add(integer3);
            }
        }
        return intSet2;
    }
    
    @Nullable
    private NativeImage loadTexture(final ResourceLocation uh) {
        try (final Resource abb3 = this.resourceManager.getResource(uh)) {
            return NativeImage.read(NativeImage.Format.RGBA, abb3.getInputStream());
        }
        catch (IOException iOException3) {
            LegacyUnicodeBitmapsProvider.LOGGER.error("Couldn't load texture {}", uh, iOException3);
            return null;
        }
    }
    
    private static int getLeft(final byte byte1) {
        return byte1 >> 4 & 0xF;
    }
    
    private static int getRight(final byte byte1) {
        return (byte1 & 0xF) + 1;
    }
    
    static {
        LOGGER = LogManager.getLogger();
    }
    
    public static class Builder implements GlyphProviderBuilder {
        private final ResourceLocation metadata;
        private final String texturePattern;
        
        public Builder(final ResourceLocation uh, final String string) {
            this.metadata = uh;
            this.texturePattern = string;
        }
        
        public static GlyphProviderBuilder fromJson(final JsonObject jsonObject) {
            return new Builder(new ResourceLocation(GsonHelper.getAsString(jsonObject, "sizes")), GsonHelper.getAsString(jsonObject, "template"));
        }
        
        @Nullable
        @Override
        public GlyphProvider create(final ResourceManager abc) {
            try (final Resource abb3 = Minecraft.getInstance().getResourceManager().getResource(this.metadata)) {
                final byte[] arr5 = new byte[65536];
                abb3.getInputStream().read(arr5);
                return new LegacyUnicodeBitmapsProvider(abc, arr5, this.texturePattern);
            }
            catch (IOException iOException3) {
                LegacyUnicodeBitmapsProvider.LOGGER.error("Cannot load {}, unicode glyphs will not render correctly", this.metadata);
                return null;
            }
        }
    }
    
    static class Glyph implements RawGlyph {
        private final int width;
        private final int height;
        private final int sourceX;
        private final int sourceY;
        private final NativeImage source;
        
        private Glyph(final int integer1, final int integer2, final int integer3, final int integer4, final NativeImage dgs) {
            this.width = integer3;
            this.height = integer4;
            this.sourceX = integer1;
            this.sourceY = integer2;
            this.source = dgs;
        }
        
        @Override
        public float getOversample() {
            return 2.0f;
        }
        
        @Override
        public int getPixelWidth() {
            return this.width;
        }
        
        @Override
        public int getPixelHeight() {
            return this.height;
        }
        
        @Override
        public float getAdvance() {
            return (float)(this.width / 2 + 1);
        }
        
        @Override
        public void upload(final int integer1, final int integer2) {
            this.source.upload(0, integer1, integer2, this.sourceX, this.sourceY, this.width, this.height, false, false);
        }
        
        @Override
        public boolean isColored() {
            return this.source.format().components() > 1;
        }
        
        @Override
        public float getShadowOffset() {
            return 0.5f;
        }
        
        @Override
        public float getBoldOffset() {
            return 0.5f;
        }
    }
}
