#!/usr/bin/env python3
"""Применить патч из редактора прошивки к образу.

    python3 apply_patch.py patch.json [--src stock-fw/rt4d_ru_batt.bin]
                                      [--out stock-fw/rt4d_custom.bin]

Формат патча (его выдаёт кнопка «Скопировать патч»):
    {"texts":[{"va":134370285,"txt":"ОСН. НАСТР"}, ...],
     "logo":{"va":134500045,"b64":"..."}}

Текст пишется в CP1251 и добивается пробелами ровно до исходной ширины поля —
записи в прошивке фиксированной длины, сдвигать их нельзя.
"""
import argparse, base64, json, sys

BASE = 0x08002800
# доступные глифы: ASCII + 33 заглавные кириллические буквы, дописанные при русификации
CYR = "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯЁ"


def widths(src_len):
    """допустимые ширины полей — берём из таблиц редактора"""
    return None


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("patch")
    ap.add_argument("--src", default="stock-fw/rt4d_ru_batt.bin")
    ap.add_argument("--out", default="stock-fw/rt4d_custom.bin")
    ap.add_argument("--meta", default="tools/display-editor/field-widths.json",
                    help="ширины полей (va -> max), пишется при сборке редактора")
    a = ap.parse_args()

    patch = json.load(open(a.patch, encoding="utf-8"))
    img = bytearray(open(a.src, "rb").read())
    try:
        W = {int(k): v for k, v in json.load(open(a.meta, encoding="utf-8")).items()}
    except Exception:
        sys.exit(f"нет файла ширин полей {a.meta} — пересоберите редактор")

    bad = []
    n = 0
    for t in patch.get("texts", []):
        va, txt = t["va"], t["txt"]
        if va not in W:
            bad.append(f"неизвестный адрес 0x{va:08X}")
            continue
        w = W[va]
        for ch in txt:
            if ch not in CYR and not (0x20 <= ord(ch) <= 0x7E):
                bad.append(f"0x{va:08X}: нет глифа для «{ch}»")
        if len(txt) > w:
            bad.append(f"0x{va:08X}: «{txt}» длиннее поля ({len(txt)} > {w})")
            continue
        try:
            enc = txt.encode("cp1251")
        except UnicodeEncodeError as e:
            bad.append(f"0x{va:08X}: не кодируется в CP1251 ({e})")
            continue
        img[va - BASE: va - BASE + w] = enc.ljust(w, b" ")
        n += 1

    lg = patch.get("logo")
    if lg:
        raw = base64.b64decode(lg["b64"])
        if len(raw) != 288:
            bad.append(f"логотип: ожидалось 288 байт, пришло {len(raw)}")
        else:
            va = lg["va"]
            img[va - BASE: va - BASE + 288] = raw
            print("логотип обновлён (288 Б)")

    if bad:
        print("ОШИБКИ:")
        for b in bad:
            print("  " + b)
        if not n:
            sys.exit(1)

    open(a.out, "wb").write(bytes(img))
    print(f"применено текстов: {n}")
    print(f"готово: {a.out}, {len(img)} Б")


if __name__ == "__main__":
    main()
