package com.atr.tedit.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;

/**
 * @author Adam T. Ryder
 * <a href="https://www.inventati.org/1337gallery">https://www.inventati.org/1337gallery</a>
 */

public class TEditText extends androidx.appcompat.widget.AppCompatEditText {
    private Rect rect;
    private Paint lnPaint;
    private Paint lnBackgroundPaint;
    private boolean showLineNumbers = false;
    private boolean drawLnBackground = true;

    private int paddingLeft = 0;
    private int paddingRight = 0;

    private boolean drawing = false;

    public TEditText(Context ctx) {
        super(ctx);

        rect = new Rect();
        lnPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        lnPaint.setStyle(Paint.Style.FILL);
        lnPaint.setTypeface(Typeface.MONOSPACE);

        lnBackgroundPaint = new Paint();
        lnBackgroundPaint.setStyle(Paint.Style.FILL);

        paddingLeft = getPaddingLeft();
        paddingRight = getPaddingRight();
    }

    public TEditText(Context ctx, AttributeSet attrs) {
        super(ctx, attrs);

        rect = new Rect();
        lnPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        lnPaint.setStyle(Paint.Style.FILL);
        lnPaint.setTypeface(Typeface.MONOSPACE);

        lnBackgroundPaint = new Paint();
        lnBackgroundPaint.setStyle(Paint.Style.FILL);

        paddingLeft = getPaddingLeft();
        paddingRight = getPaddingRight();
    }

    public TEditText(Context ctx, AttributeSet attrs, int defStyle) {
        super(ctx, attrs, defStyle);

        rect = new Rect();
        lnPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        lnPaint.setStyle(Paint.Style.FILL);
        lnPaint.setTypeface(Typeface.MONOSPACE);

        lnBackgroundPaint = new Paint();
        lnBackgroundPaint.setStyle(Paint.Style.FILL);

        paddingLeft = getPaddingLeft();
        paddingRight = getPaddingRight();
    }

    @Override
    public void setPadding(int left, int top, int right, int bottom) {
        super.setPadding(left, top, right, bottom);
        if (!drawing) {
            paddingLeft = left;
            paddingRight = right;
        }
    }

    public boolean isShowLineNumbers() { return showLineNumbers; }

    public void setShowLineNumbers(boolean show) {
        showLineNumbers = show;
        if (!showLineNumbers)
            setPadding(paddingLeft, getPaddingTop(), paddingRight, getPaddingBottom());
    }

    public void setLineNumberColor(int color) {
        lnPaint.setColor(color);
    }

    public void applyLineNumberSize() {
        lnPaint.setTextSize(getTextSize());
    }

    public void setLineNumberBackgroundColor(int color) {
        setLineNumberBackgroundColor(color, true);
    }

    public void setLineNumberBackgroundColor(int color, boolean draw) {
        lnBackgroundPaint.setColor(color);
        drawLnBackground = draw;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (showLineNumbers) {
            this.getLocalVisibleRect(rect);
            drawing = true;
            int baseline;
            int lineCount = getLineCount();
            int line = 2;

            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 || getTextDirection() == View.TEXT_DIRECTION_LTR) {
                String formatString;
                int padding;
                int space = (int) Math.round(lnPaint.measureText(" "));
                if (lineCount <= 9999) {
                    formatString = "%04d";
                    padding = (int) Math.round(lnPaint.measureText("0000 ")) + paddingLeft;
                } else if (lineCount <= 999999) {
                    formatString = "%06d";
                    padding = (int) Math.round(lnPaint.measureText("000000 ")) + paddingLeft;
                } else if (lineCount <= 99999999) {
                    formatString = "%08d";
                    padding = (int) Math.round(lnPaint.measureText("00000000 ")) + paddingLeft;
                } else {
                    formatString = "%010d";
                    padding = (int) Math.round(lnPaint.measureText("0000000000 ")) + paddingLeft;
                }
                setPadding(padding, getPaddingTop(), paddingRight, getPaddingBottom());

                if (drawLnBackground)
                    canvas.drawRect(rect.left, rect.top, rect.left + padding - (space / 2), rect.bottom, lnBackgroundPaint);

                baseline = getLineBounds(0, null);
                if (baseline + lnPaint.descent() >= rect.top)
                    canvas.drawText(String.format(formatString, 1), rect.left + paddingLeft, baseline, lnPaint);

                for (int i = 1; i < lineCount; i++) {
                    baseline = getLineBounds(i, null);
                    if (baseline + lnPaint.descent() < rect.top) {
                        if (getLayout() != null && getText().charAt(getLayout().getLineStart(i) - 1) == '\n')
                            line++;
                        continue;
                    } else if (baseline + lnPaint.ascent() > rect.bottom)
                        break;

                    if (getLayout() != null && getText().charAt(getLayout().getLineStart(i) - 1) == '\n')
                        canvas.drawText(String.format(formatString, line++), rect.left + paddingLeft, baseline, lnPaint);
                }
            } else {
                String formatString;
                int padding;
                int space = (int) Math.round(lnPaint.measureText(" "));
                if (lineCount <= 9999) {
                    formatString = "%04d";
                    padding = (int) Math.round(lnPaint.measureText("0000 ") + paddingRight);
                } else if (lineCount <= 999999) {
                    formatString = "%06d";
                    padding = (int) Math.round(lnPaint.measureText("000000 ") + paddingRight);
                } else if (lineCount <= 99999999) {
                    formatString = "%08d";
                    padding = (int) Math.round(lnPaint.measureText("00000000 ") + paddingRight);
                } else {
                    formatString = "%010d";
                    padding = (int) Math.round(lnPaint.measureText("0000000000 ") + paddingRight);
                }
                setPadding(paddingLeft, getPaddingTop(), padding, getPaddingBottom());

                if (drawLnBackground)
                    canvas.drawRect(rect.right - padding + (space / 2), rect.top, rect.right, rect.bottom, lnBackgroundPaint);

                padding -= space;

                baseline = getLineBounds(0, null);
                if (baseline + lnPaint.descent() >= rect.top)
                    canvas.drawText(String.format(formatString, 1), rect.right - padding, baseline, lnPaint);

                for (int i = 1; i < lineCount; i++) {
                    baseline = getLineBounds(i, null);
                    if (baseline + lnPaint.descent() < rect.top) {
                        if (getLayout() != null && getText().charAt(getLayout().getLineStart(i) - 1) == '\n')
                            line++;
                        continue;
                    } else if (baseline + lnPaint.ascent() > rect.bottom)
                        break;

                    if (getLayout() != null && getText().charAt(getLayout().getLineStart(i) - 1) == '\n')
                        canvas.drawText(String.format(formatString, line++), rect.right - padding, baseline, lnPaint);
                }
            }

            drawing = false;
        }

        super.onDraw(canvas);
    }
}
