/* -------------------------------------------------------------------------
 * 文件名: lcd_text.c
 * 模块职责:
 *   提供文本渲染能力，包含：
 *   1) ASCII 字符绘制（内部函数 Lcd_Pub_Ascii）
 *   2) 中文位图绘制（内部函数 Lcd_Pub_UTF8）
 *   3) 字符串渲染入口（Lcd_ShowStr）
 *   4) 依赖 common/utf8 的 utf8_next 进行 UTF-8 解析
 *
 * 设计说明:
 *   - 显示像素最终通过 Lcd_SetPixel 写入显存。
 *   - 当前字体配置固定为：
 *       ASCII: 7x12
 *       中文:  13x12（来自 utf8_hz12_get）
 *   - 对越界场景采用“显式错误返回”，便于上层与测试捕获。
 * ------------------------------------------------------------------------- */
#include "lcd_text.h"

#include <stddef.h>

#include "ascii.h"
#include "lcd_draw.h"

textConfig text_cfg = {
    .wGBFontWidth = 13,
    .wGBFontHeight = 12,
    .wASCIIFontWidth = 7,
    .wASCIIFontHeight = 12,
    .pbyLibAscii = g_abyASCII126[0],
    .rowSpace = 2
};

/* -------------------------------------------------------------------------
 * 函数名: Lcd_Pub_Ascii（内部）
 * 功能:
 *   按 ASCII 点阵库将单个 ASCII 字符绘制到指定坐标。
 *
 * 参数:
 *   x, y    - 字符左上角坐标
 *   byAscii - ASCII 码值
 *
 * 返回值:
 *   LCD_OK / LCD_ERR_OUT_OF_RANGE
 * ------------------------------------------------------------------------- */
static int8_t Lcd_Pub_Ascii(uint16_t x, uint16_t y, uint8_t byAscii)
{
    const textConfig *cfg = &text_cfg;
    uint8_t i, j;
    uint8_t byLine, *pbyFontLib;

    /* 按字库行高定位字符位图起始地址 */
    pbyFontLib = &cfg->pbyLibAscii[byAscii * cfg->wASCIIFontHeight];
    if ((x + cfg->wASCIIFontWidth) > LCD_SIZE_X) return LCD_ERR_OUT_OF_RANGE;
    if ((y + cfg->wASCIIFontHeight) > LCD_SIZE_Y) return LCD_ERR_OUT_OF_RANGE;


    for (j = 0; j < cfg->wASCIIFontHeight; j++) {
        byLine = pbyFontLib[j];
        for (i = 0; i < cfg->wASCIIFontWidth; i++) {
            uint8_t bit_on = ((byLine << i) & 0x80) != 0;
            uint16_t px, py;
            uint8_t color = bit_on ? LCD_FONT : LCD_BACK;
            px = x + i;
            py = y + j;
            if (Lcd_SetPixel(px, py, color) != LCD_OK) {
                return LCD_ERR_OUT_OF_RANGE;
            }
        }
    }
    return LCD_OK;
}

/* -------------------------------------------------------------------------
 * 函数名: Lcd_Pub_UTF8（内部）
 * 功能:
 *   将一个 Unicode 字符（中文）按 13x12 位图绘制到指定坐标。
 *
 * 参数:
 *   x, y    - 字符左上角坐标
 *   unicode - Unicode 码点
 *
 * 返回值:
 *   LCD_OK / LCD_ERR_OUT_OF_RANGE
 *
 * 注意:
 *   - 若字库中找不到该字符位图，当前实现按“空操作成功”处理（返回 LCD_OK）。
 * ------------------------------------------------------------------------- */
static int8_t Lcd_Pub_UTF8(uint16_t x, uint16_t y, uint32_t unicode)
{
    const textConfig *cfg = &text_cfg;
    const uint8_t *bitmap = utf8_hz12_get(unicode);
    uint16_t word = 0;
    if ((x + cfg->wGBFontWidth) > LCD_SIZE_X) return LCD_ERR_OUT_OF_RANGE;
    if ((y + cfg->wGBFontHeight) > LCD_SIZE_Y) return LCD_ERR_OUT_OF_RANGE;
    if (bitmap == NULL) return LCD_OK;
    for (uint8_t j = 0; j < cfg->wGBFontHeight; j++) {
        word = (uint16_t)((bitmap[j * 2] << 8) | bitmap[j * 2 + 1]);
        for (uint8_t i = 0; i < cfg->wGBFontWidth; i++) {
            if ((word >> (15 - i)) & 1) {
                if (Lcd_SetPixel(x + i, y + j, LCD_FONT) != LCD_OK) {
                    return LCD_ERR_OUT_OF_RANGE;
                }
            } else {
                if (Lcd_SetPixel(x + i, y + j, LCD_BACK) != LCD_OK) {
                    return LCD_ERR_OUT_OF_RANGE;
                }
            }
        }
    }
    return LCD_OK;
}

/* -------------------------------------------------------------------------
 * 函数名: Lcd_ShowStr
 * 功能:
 *   在指定坐标绘制 UTF-8 字符串，支持 ASCII、中文与换行。
 *
 * 参数:
 *   x, y     - 首字符左上角坐标
 *   pcString - UTF-8 字符串（以 '\0' 结尾）
 *
 * 返回值:
 *   0   : 绘制成功
 *  -1   : x 方向越界
 *  -2   : y 方向越界
 *
 * 说明:
 *   - 与历史行为兼容，保留 -1/-2 两种错误码语义。
 *   - 内部会在渲染前做边界预判，并在底层写像素失败时转化为越界错误返回。
 * ------------------------------------------------------------------------- */
int8_t Lcd_ShowStr(uint16_t x, uint16_t y, const uint8_t *pcString)
{
    const textConfig *cfg = &text_cfg;
    uint16_t bakx = x;
    uint32_t unicode;
    uint16_t index = 0;
    uint8_t n = 0;

    if (x > LCD_SIZE_X - cfg->wASCIIFontWidth) return -1;
    if (y >= LCD_SIZE_Y - cfg->wGBFontHeight) return -2;
    while (pcString[index] != 0x0) {
        n = utf8_next(pcString + index, &unicode);
        if (n <= 0) break;
        if (n > 1) {
            /* 中文字符渲染路径（13x12） */
            if (x > LCD_SIZE_X - cfg->wGBFontWidth) {
                for (uint16_t j = y; j < y + cfg->wGBFontHeight; j++) {
                    for (uint16_t i = x; i < LCD_SIZE_X; i++) {
                        Lcd_SetPixel(i, j, LCD_BACK);
                    }
                }
                return -1;
            } else {
                if (Lcd_Pub_UTF8(x, y, unicode) != LCD_OK) {
                    return -2;
                }
                x += cfg->wGBFontWidth;
            }
        } else {
            /* ASCII / 控制字符渲染路径 */
            if (unicode == 0x0a) {
                /* 换行：x 回到行首，y 下移一行（字高 + 行距） */
                x = bakx;
                y += cfg->wGBFontHeight + cfg->rowSpace;
                if (y >= LCD_SIZE_Y - cfg->wGBFontHeight) {
                    return -2;
                }
            } else if (unicode >= 0x10) {
                if (x > LCD_SIZE_X - cfg->wASCIIFontWidth) {
                    for (uint16_t j = y; j < y + cfg->wASCIIFontHeight; j++) {
                        for (uint16_t i = x; i < LCD_SIZE_X; i++) {
                            Lcd_SetPixel(i, j, LCD_BACK);
                        }
                    }
                    return -1;
                } else {
                    if (Lcd_Pub_Ascii(x, y, (uint8_t)unicode) != LCD_OK) {
                        return -1;
                    }
                    x += cfg->wASCIIFontWidth;
                }
            }
        }
        index += n;
    }
    return 0;
}

/* -------------------------------------------------------------------------
 * 函数名: Lcd_ShowTest
 * 功能:
 *   预留测试接口（当前为桩实现）。
 * ------------------------------------------------------------------------- */
int8_t Lcd_ShowTest(uint16_t x, uint16_t y, uint8_t *pcString)
{
    (void)x;
    (void)y;
    (void)pcString;
    return 0;
}
