#!/usr/bin/env python3
"""Verify the actual CjkSc24/CjkSc28 glyph tables linked into the firmware ELF."""
from __future__ import annotations

import sys
from pathlib import Path

from elftools.elf.elffile import ELFFile


GLYPH_SIZE = 16
EXPECTED_GLYPHS = 5000
FONT_SYMBOLS = {
    "CjkSc24": "_ZN8wearable5fonts12_GLOBAL__N_1L16cjk_sc_24_glyphsE",
    "CjkSc28": "_ZN8wearable5fonts12_GLOBAL__N_1L16cjk_sc_28_glyphsE",
}
PROBES = "中这的一是在不了有人我为国"


def gb2312_level1_codes() -> set[int]:
    result: set[int] = set()
    for high in range(0xB0, 0xD8):
        for low in range(0xA1, 0xFF):
            try:
                value = bytes((high, low)).decode("gb2312")
            except UnicodeDecodeError:
                continue
            if len(value) == 1 and "\u3400" <= value <= "\u9fff":
                result.add(ord(value))
    return result


def symbol_data(elf: ELFFile, name: str) -> bytes:
    symbols = [
        symbol
        for symbol in elf.get_section_by_name(".symtab").iter_symbols()
        if symbol.name == name
    ]
    assert len(symbols) == 1, f"expected one linked symbol {name}, found {len(symbols)}"
    symbol = symbols[0]
    section = elf.get_section(symbol["st_shndx"])
    offset = symbol["st_value"] - section["sh_addr"]
    return section.data()[offset:offset + symbol["st_size"]]


def glyph_codes(data: bytes) -> list[int]:
    assert len(data) == EXPECTED_GLYPHS * GLYPH_SIZE, (
        f"expected {EXPECTED_GLYPHS} linked glyphs, got {len(data) // GLYPH_SIZE}"
    )
    codes = [
        int.from_bytes(data[offset:offset + 2], "little")
        for offset in range(0, len(data), GLYPH_SIZE)
    ]
    assert codes == sorted(codes), "linked glyph table is not sorted"
    assert len(codes) == len(set(codes)), "linked glyph table contains duplicates"
    return codes


if len(sys.argv) != 2:
    raise SystemExit(f"usage: {Path(sys.argv[0]).name} ELF")

level1 = gb2312_level1_codes()
assert len(level1) == 3755, f"unexpected GB2312 Level 1 size: {len(level1)}"
with Path(sys.argv[1]).open("rb") as handle:
    elf = ELFFile(handle)
    for font_name, symbol_name in FONT_SYMBOLS.items():
        linked = set(glyph_codes(symbol_data(elf, symbol_name)))
        missing = level1 - linked
        assert not missing, f"{font_name} misses {len(missing)} GB2312 Level 1 glyphs"
        for character in PROBES:
            assert ord(character) in linked, f"{font_name} missing {character} U+{ord(character):04X}"
        print(
            f"{font_name} linked coverage PASS "
            f"(glyphs={len(linked)}, GB2312 Level 1={len(level1)}/{len(level1)}, "
            "中 U+4E2D=yes, 这 U+8FD9=yes)"
        )
