package net.minecraft.client.gui;

import java.util.Arrays;
import net.minecraft.util.Mth;
import java.util.Iterator;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.blaze3d.font.GlyphInfo;
import net.minecraft.client.gui.font.glyphs.BakedGlyph;
import net.minecraft.client.gui.font.glyphs.EmptyGlyph;
import net.minecraft.ChatFormatting;
import com.google.common.collect.Lists;
import com.mojang.math.Vector3f;
import net.minecraft.client.renderer.MultiBufferSource;
import com.mojang.blaze3d.vertex.Tesselator;
import com.mojang.math.Matrix4f;
import com.ibm.icu.text.ArabicShapingException;
import com.ibm.icu.text.Bidi;
import com.ibm.icu.text.ArabicShaping;
import com.mojang.math.Transformation;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.font.GlyphProvider;
import java.util.List;
import net.minecraft.client.gui.font.FontSet;
import net.minecraft.client.renderer.texture.TextureManager;
import java.util.Random;

public class Font implements AutoCloseable {
    public final int lineHeight = 9;
    public final Random random;
    private final TextureManager textureManager;
    private final FontSet fonts;
    private boolean bidirectional;
    
    public Font(final TextureManager eak, final FontSet deg) {
        this.random = new Random();
        this.textureManager = eak;
        this.fonts = deg;
    }
    
    public void reload(final List<GlyphProvider> list) {
        this.fonts.reload(list);
    }
    
    @Override
    public void close() {
        this.fonts.close();
    }
    
    public int drawShadow(final String string, final float float2, final float float3, final int integer) {
        RenderSystem.enableAlphaTest();
        return this.drawInternal(string, float2, float3, integer, Transformation.identity().getMatrix(), true);
    }
    
    public int draw(final String string, final float float2, final float float3, final int integer) {
        RenderSystem.enableAlphaTest();
        return this.drawInternal(string, float2, float3, integer, Transformation.identity().getMatrix(), false);
    }
    
    public String bidirectionalShaping(final String string) {
        try {
            final Bidi bidi3 = new Bidi(new ArabicShaping(8).shape(string), 127);
            bidi3.setReorderingMode(0);
            return bidi3.writeReordered(2);
        }
        catch (ArabicShapingException ex) {
            return string;
        }
    }
    
    private int drawInternal(final String string, final float float2, final float float3, final int integer, final Matrix4f b, final boolean boolean6) {
        if (string == null) {
            return 0;
        }
        final MultiBufferSource.BufferSource a8 = MultiBufferSource.immediate(Tesselator.getInstance().getBuilder());
        final int integer2 = this.drawInBatch(string, float2, float3, integer, boolean6, b, a8, false, 0, 15728880);
        a8.endBatch();
        return integer2;
    }
    
    public int drawInBatch(final String string, final float float2, final float float3, final int integer4, final boolean boolean5, final Matrix4f b, final MultiBufferSource dqt, final boolean boolean8, final int integer9, final int integer10) {
        return this.drawInternal(string, float2, float3, integer4, boolean5, b, dqt, boolean8, integer9, integer10);
    }
    
    private int drawInternal(String string, float float2, final float float3, int integer4, final boolean boolean5, final Matrix4f b, final MultiBufferSource dqt, final boolean boolean8, final int integer9, final int integer10) {
        if (this.bidirectional) {
            string = this.bidirectionalShaping(string);
        }
        if ((integer4 & 0xFC000000) == 0x0) {
            integer4 |= 0xFF000000;
        }
        if (boolean5) {
            this.renderText(string, float2, float3, integer4, true, b, dqt, boolean8, integer9, integer10);
        }
        final Matrix4f b2 = b.copy();
        b2.translate(new Vector3f(0.0f, 0.0f, 0.001f));
        float2 = this.renderText(string, float2, float3, integer4, false, b2, dqt, boolean8, integer9, integer10);
        return (int)float2 + (boolean5 ? 1 : 0);
    }
    
    private float renderText(final String string, final float float2, final float float3, final int integer4, final boolean boolean5, final Matrix4f b, final MultiBufferSource dqt, final boolean boolean8, final int integer9, final int integer10) {
        final float float4 = boolean5 ? 0.25f : 1.0f;
        final float float5 = (integer4 >> 16 & 0xFF) / 255.0f * float4;
        final float float6 = (integer4 >> 8 & 0xFF) / 255.0f * float4;
        final float float7 = (integer4 & 0xFF) / 255.0f * float4;
        float float8 = float2;
        float float9 = float5;
        float float10 = float6;
        float float11 = float7;
        final float float12 = (integer4 >> 24 & 0xFF) / 255.0f;
        boolean boolean9 = false;
        boolean boolean10 = false;
        boolean boolean11 = false;
        boolean boolean12 = false;
        boolean boolean13 = false;
        final List<BakedGlyph.Effect> list26 = Lists.newArrayList();
        for (int integer11 = 0; integer11 < string.length(); ++integer11) {
            final char character28 = string.charAt(integer11);
            if (character28 == '§' && integer11 + 1 < string.length()) {
                final ChatFormatting g29 = ChatFormatting.getByCode(string.charAt(integer11 + 1));
                if (g29 != null) {
                    if (g29.shouldReset()) {
                        boolean9 = false;
                        boolean10 = false;
                        boolean13 = false;
                        boolean12 = false;
                        boolean11 = false;
                        float9 = float5;
                        float10 = float6;
                        float11 = float7;
                    }
                    if (g29.getColor() != null) {
                        final int integer12 = g29.getColor();
                        float9 = (integer12 >> 16 & 0xFF) / 255.0f * float4;
                        float10 = (integer12 >> 8 & 0xFF) / 255.0f * float4;
                        float11 = (integer12 & 0xFF) / 255.0f * float4;
                    }
                    else if (g29 == ChatFormatting.OBFUSCATED) {
                        boolean9 = true;
                    }
                    else if (g29 == ChatFormatting.BOLD) {
                        boolean10 = true;
                    }
                    else if (g29 == ChatFormatting.STRIKETHROUGH) {
                        boolean13 = true;
                    }
                    else if (g29 == ChatFormatting.UNDERLINE) {
                        boolean12 = true;
                    }
                    else if (g29 == ChatFormatting.ITALIC) {
                        boolean11 = true;
                    }
                }
                ++integer11;
            }
            else {
                final GlyphInfo cwy29 = this.fonts.getGlyphInfo(character28);
                final BakedGlyph dej30 = (boolean9 && character28 != ' ') ? this.fonts.getRandomGlyph(cwy29) : this.fonts.getGlyph(character28);
                if (!(dej30 instanceof EmptyGlyph)) {
                    final float float13 = boolean10 ? cwy29.getBoldOffset() : 0.0f;
                    final float float14 = boolean5 ? cwy29.getShadowOffset() : 0.0f;
                    final VertexConsumer cyo33 = dqt.getBuffer(dej30.renderType(boolean8));
                    this.renderChar(dej30, boolean10, boolean11, float13, float8 + float14, float3 + float14, b, cyo33, float9, float10, float11, float12, integer10);
                }
                final float float13 = cwy29.getAdvance(boolean10);
                final float float14 = boolean5 ? 1.0f : 0.0f;
                if (boolean13) {
                    list26.add(new BakedGlyph.Effect(float8 + float14 - 1.0f, float3 + float14 + 4.5f, float8 + float14 + float13, float3 + float14 + 4.5f - 1.0f, -0.01f, float9, float10, float11, float12));
                }
                if (boolean12) {
                    list26.add(new BakedGlyph.Effect(float8 + float14 - 1.0f, float3 + float14 + 9.0f, float8 + float14 + float13, float3 + float14 + 9.0f - 1.0f, -0.01f, float9, float10, float11, float12));
                }
                float8 += float13;
            }
        }
        if (integer9 != 0) {
            final float float15 = (integer9 >> 24 & 0xFF) / 255.0f;
            final float float16 = (integer9 >> 16 & 0xFF) / 255.0f;
            final float float17 = (integer9 >> 8 & 0xFF) / 255.0f;
            final float float18 = (integer9 & 0xFF) / 255.0f;
            list26.add(new BakedGlyph.Effect(float2 - 1.0f, float3 + 9.0f, float8 + 1.0f, float3 - 1.0f, 0.01f, float16, float17, float18, float15));
        }
        if (!list26.isEmpty()) {
            final BakedGlyph dej31 = this.fonts.whiteGlyph();
            final VertexConsumer cyo34 = dqt.getBuffer(dej31.renderType(boolean8));
            for (final BakedGlyph.Effect a30 : list26) {
                dej31.renderEffect(a30, b, cyo34, integer10);
            }
        }
        return float8;
    }
    
    private void renderChar(final BakedGlyph dej, final boolean boolean2, final boolean boolean3, final float float4, final float float5, final float float6, final Matrix4f b, final VertexConsumer cyo, final float float9, final float float10, final float float11, final float float12, final int integer) {
        dej.render(boolean3, float5, float6, b, cyo, float9, float10, float11, float12, integer);
        if (boolean2) {
            dej.render(boolean3, float5 + float4, float6, b, cyo, float9, float10, float11, float12, integer);
        }
    }
    
    public int width(final String string) {
        if (string == null) {
            return 0;
        }
        float float3 = 0.0f;
        boolean boolean4 = false;
        for (int integer5 = 0; integer5 < string.length(); ++integer5) {
            final char character6 = string.charAt(integer5);
            if (character6 == '§' && integer5 < string.length() - 1) {
                final ChatFormatting g7 = ChatFormatting.getByCode(string.charAt(++integer5));
                if (g7 == ChatFormatting.BOLD) {
                    boolean4 = true;
                }
                else if (g7 != null && g7.shouldReset()) {
                    boolean4 = false;
                }
            }
            else {
                float3 += this.fonts.getGlyphInfo(character6).getAdvance(boolean4);
            }
        }
        return Mth.ceil(float3);
    }
    
    public float charWidth(final char character) {
        if (character == '§') {
            return 0.0f;
        }
        return this.fonts.getGlyphInfo(character).getAdvance(false);
    }
    
    public String substrByWidth(final String string, final int integer) {
        return this.substrByWidth(string, integer, false);
    }
    
    public String substrByWidth(final String string, final int integer, final boolean boolean3) {
        final StringBuilder stringBuilder5 = new StringBuilder();
        float float6 = 0.0f;
        final int integer2 = boolean3 ? (string.length() - 1) : 0;
        final int integer3 = boolean3 ? -1 : 1;
        boolean boolean4 = false;
        boolean boolean5 = false;
        for (int integer4 = integer2; integer4 >= 0 && integer4 < string.length() && float6 < integer; integer4 += integer3) {
            final char character12 = string.charAt(integer4);
            if (boolean4) {
                boolean4 = false;
                final ChatFormatting g13 = ChatFormatting.getByCode(character12);
                if (g13 == ChatFormatting.BOLD) {
                    boolean5 = true;
                }
                else if (g13 != null && g13.shouldReset()) {
                    boolean5 = false;
                }
            }
            else if (character12 == '§') {
                boolean4 = true;
            }
            else {
                float6 += this.charWidth(character12);
                if (boolean5) {
                    ++float6;
                }
            }
            if (float6 > integer) {
                break;
            }
            if (boolean3) {
                stringBuilder5.insert(0, character12);
            }
            else {
                stringBuilder5.append(character12);
            }
        }
        return stringBuilder5.toString();
    }
    
    private String eraseTrailingNewLines(String string) {
        while (string != null && string.endsWith("\n")) {
            string = string.substring(0, string.length() - 1);
        }
        return string;
    }
    
    public void drawWordWrap(String string, final int integer2, final int integer3, final int integer4, final int integer5) {
        string = this.eraseTrailingNewLines(string);
        this.drawWordWrapInternal(string, integer2, integer3, integer4, integer5);
    }
    
    private void drawWordWrapInternal(final String string, final int integer2, int integer3, final int integer4, final int integer5) {
        final List<String> list7 = this.split(string, integer4);
        final Matrix4f b8 = Transformation.identity().getMatrix();
        for (final String string2 : list7) {
            float float11 = (float)integer2;
            if (this.bidirectional) {
                final int integer6 = this.width(this.bidirectionalShaping(string2));
                float11 += integer4 - integer6;
            }
            this.drawInternal(string2, float11, (float)integer3, integer5, b8, false);
            integer3 += 9;
        }
    }
    
    public int wordWrapHeight(final String string, final int integer) {
        return 9 * this.split(string, integer).size();
    }
    
    public void setBidirectional(final boolean boolean1) {
        this.bidirectional = boolean1;
    }
    
    public List<String> split(final String string, final int integer) {
        return Arrays.<String>asList(this.insertLineBreaks(string, integer).split("\n"));
    }
    
    public String insertLineBreaks(String string, final int integer) {
        String string2;
        int integer2;
        String string3;
        boolean boolean8;
        for (string2 = ""; !string.isEmpty(); string = ChatFormatting.getLastColors(string3) + string.substring(integer2 + (boolean8 ? 1 : 0)), string2 = string2 + string3 + "\n") {
            integer2 = this.indexAtWidth(string, integer);
            if (string.length() <= integer2) {
                return string2 + string;
            }
            string3 = string.substring(0, integer2);
            final char character7 = string.charAt(integer2);
            boolean8 = (character7 == ' ' || character7 == '\n');
        }
        return string2;
    }
    
    public int indexAtWidth(final String string, final int integer) {
        final int integer2 = Math.max(1, integer);
        final int integer3 = string.length();
        float float6 = 0.0f;
        int integer4 = 0;
        int integer5 = -1;
        boolean boolean9 = false;
        boolean boolean10 = true;
        while (integer4 < integer3) {
            final char character11 = string.charAt(integer4);
            Label_0178: {
                switch (character11) {
                    case '§': {
                        if (integer4 < integer3 - 1) {
                            final ChatFormatting g12 = ChatFormatting.getByCode(string.charAt(++integer4));
                            if (g12 == ChatFormatting.BOLD) {
                                boolean9 = true;
                            }
                            else if (g12 != null && g12.shouldReset()) {
                                boolean9 = false;
                            }
                        }
                        break Label_0178;
                    }
                    case '\n': {
                        --integer4;
                        break Label_0178;
                    }
                    case ' ': {
                        integer5 = integer4;
                        break;
                    }
                }
                if (float6 != 0.0f) {
                    boolean10 = false;
                }
                float6 += this.charWidth(character11);
                if (boolean9) {
                    ++float6;
                }
            }
            if (character11 == '\n') {
                integer5 = ++integer4;
                break;
            }
            if (float6 > integer2) {
                if (boolean10) {
                    ++integer4;
                    break;
                }
                break;
            }
            else {
                ++integer4;
            }
        }
        if (integer4 != integer3 && integer5 != -1 && integer5 < integer4) {
            return integer5;
        }
        return integer4;
    }
    
    public int getWordPosition(final String string, final int integer2, final int integer3, final boolean boolean4) {
        int integer4 = integer3;
        final boolean boolean5 = integer2 < 0;
        for (int integer5 = Math.abs(integer2), integer6 = 0; integer6 < integer5; ++integer6) {
            if (boolean5) {
                while (boolean4 && integer4 > 0 && (string.charAt(integer4 - 1) == ' ' || string.charAt(integer4 - 1) == '\n')) {
                    --integer4;
                }
                while (integer4 > 0 && string.charAt(integer4 - 1) != ' ' && string.charAt(integer4 - 1) != '\n') {
                    --integer4;
                }
            }
            else {
                final int integer7 = string.length();
                final int integer8 = string.indexOf(32, integer4);
                final int integer9 = string.indexOf(10, integer4);
                if (integer8 == -1 && integer9 == -1) {
                    integer4 = -1;
                }
                else if (integer8 != -1 && integer9 != -1) {
                    integer4 = Math.min(integer8, integer9);
                }
                else if (integer8 != -1) {
                    integer4 = integer8;
                }
                else {
                    integer4 = integer9;
                }
                if (integer4 == -1) {
                    integer4 = integer7;
                }
                else {
                    while (boolean4 && integer4 < integer7 && (string.charAt(integer4) == ' ' || string.charAt(integer4) == '\n')) {
                        ++integer4;
                    }
                }
            }
        }
        return integer4;
    }
    
    public boolean isBidirectional() {
        return this.bidirectional;
    }
}
