/*
 * Copyright 2022 Tarsin Norbin
 *
 * This file is part of EhViewer
 *
 * EhViewer is free software: you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * EhViewer is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with EhViewer.
 * If not, see <https://www.gnu.org/licenses/>.
 */

package com.hippo.glview.glrenderer;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Typeface;

import java.util.Arrays;

// TODO support multiline

/**
 * Works like movable type.<br>
 * <br>
 * Only support single line now
 */
public final class MovableTextTexture extends SpriteTexture {
    private final char[] mCharacters;
    private final float[] mWidths;
    private final float mHeight;
    private final float mMaxWidth;

    private MovableTextTexture(Bitmap bitmap, int count, int[] rects, char[] characters,
                               float[] widths, float height, float maxWidth) {
        super(bitmap, false, count, rects);
        mCharacters = characters;
        mWidths = widths;
        mHeight = height;
        mMaxWidth = maxWidth;
    }

    /**
     * Create a TextTexture to draw text
     *
     * @param typeface   the typeface
     * @param size       text size
     * @param characters all Characters
     * @return the TextTexture
     */
    public static MovableTextTexture create(Typeface typeface, int size, int color, char[] characters) {
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setTextSize(size);
        paint.setColor(color);
        paint.setTypeface(typeface);

        Paint.FontMetricsInt fmi = paint.getFontMetricsInt();
        int fixed = fmi.bottom;
        int height = fmi.bottom - fmi.top;

        int length = characters.length;
        float[] widths = new float[length];
        paint.getTextWidths(characters, 0, length, widths);

        // Calculate bitmap size
        float maxWidth = 0.0f;
        for (float f : widths) {
            maxWidth = Math.max(maxWidth, f);
        }
        int hCount = (int) Math.ceil(Math.sqrt(height / maxWidth * length));
        int vCount = (int) Math.ceil(Math.sqrt(maxWidth / height * length));
        if (hCount * (vCount - 1) > length) {
            vCount--;
        }
        if ((hCount - 1) * vCount > length) {
            hCount--;
        }

        Bitmap bitmap = Bitmap.createBitmap((int) Math.ceil(hCount * maxWidth),
                (int) (double) (vCount * height), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        canvas.translate(0, height - fixed);

        // Draw
        int[] rects = new int[length * 4];
        int x = 0;
        int y = 0;
        for (int i = 0; i < length; i++) {
            int offset = i * 4;
            rects[offset] = x;
            rects[offset + 1] = y;
            rects[offset + 2] = (int) widths[i];
            rects[offset + 3] = height;

            canvas.drawText(characters, i, 1, x, y, paint);

            if (i % hCount == hCount - 1) {
                // The end of row
                x = 0;
                y += height;
            } else {
                x += (int) maxWidth;
            }
        }

        return new MovableTextTexture(bitmap, length, rects, characters, widths, height, maxWidth);
    }

    public int[] getTextIndexes(String text) {
        int length = text.length();
        int[] indexes = new int[length];
        for (int i = 0; i < length; i++) {
            char ch = text.charAt(i);
            indexes[i] = Arrays.binarySearch(mCharacters, ch);
        }

        return indexes;
    }

    public float getTextWidth(String text) {
        float width = 0.0f;
        for (int i = 0, n = text.length(); i < n; i++) {
            char ch = text.charAt(i);
            int index = Arrays.binarySearch(mCharacters, ch);
            if (index >= 0) {
                width += mWidths[index];
            } else {
                width += mMaxWidth;
            }
        }

        return width;
    }

    public float getTextWidth(int[] indexes) {
        float width = 0.0f;
        for (int index : indexes) {
            if (index >= 0) {
                width += mWidths[index];
            } else {
                width += mMaxWidth;
            }
        }

        return width;
    }

    public float getMaxWidth() {
        return mMaxWidth;
    }

    public float getTextHeight() {
        return mHeight;
    }

    public void drawText(GLCanvas canvas, String text, int x, int y) {
        for (int i = 0, n = text.length(); i < n; i++) {
            char ch = text.charAt(i);
            int index = Arrays.binarySearch(mCharacters, ch);
            if (index >= 0) {
                drawSprite(canvas, index, x, y);
                x += (int) mWidths[index];
            } else {
                x += (int) mMaxWidth;
            }
        }
    }

    public void drawText(GLCanvas canvas, int[] indexes, int x, int y) {
        for (int index : indexes) {
            if (index >= 0) {
                drawSprite(canvas, index, x, y);
                x += (int) mWidths[index];
            } else {
                x += (int) mMaxWidth;
            }
        }
    }
}
