"""DIMENSION 2 batch 2.

HYPOTHESES
 H1 The request-descriptor table around 0x1802cb230 maps action name ->
    uppercase name -> url template / method / factory. Decoding one row decodes
    all of them, and gives DiscardCard / DiscardACard / DiscardCardByRes /
    MoveCard / SwapCard their routes and their request+response classes.
 H2 FutDiscardCardServerResponse stores totalCredits at obj+0x28 and the last
    discarded id at obj+0x30. Whoever reads +0x28 decides whether the coin
    credit is server-authored or client-computed.
 H3 FUN_18011a830() is the FUT client-model singleton; vtable slot 0xa30 removes
    an item by id (called once per discarded id) and slot 0x160 hands out the
    pack-reveal item collection that createPack post-processes.
 H4 TO_TRADEPILE (FUN_1801be6a0) and 'Tradepile' (FUN_18010c3b0) are the
    send-to-transfer-list paths.

CONTROLS: class_deser with the FULL literal names, which is what the -4 rule
needs. FutSquadSaveServerResponse -> 0x180171a60, FutSquadListServerResponse ->
0x180172140, FutCreateMatchServerResponse -> 0x180120380.
"""
import traceback, os

OUT = "/tmp/claude-1000/-home-alex-Documents-OpenFUT/8e521ca1-ca3e-4138-bb96-df1744dd1d30/scratchpad/packres"


def dump(name, text):
    with open(os.path.join(OUT, name), "w") as f:
        f.write(text)
    print("[wrote %s  %d chars]" % (name, len(text)))


def show(label, va):
    s = dec(va)
    print("-" * 74)
    print("%s  %#x  fname=%s  len(src)=%d" % (label, va, fname(va), len(s)))
    print(s)
    return s


try:
    print("=" * 78)
    print("SECTION 0 -- CONTROLS with the full RS4 literal name")
    for c in ("FutSquadSaveServerResponse", "FutSquadListServerResponse",
              "FutCreateMatchServerResponse"):
        print(" ", c, [(hex(a), hex(v), hex(e)) for a, v, e in class_deser(c)])

    print("=" * 78)
    print("SECTION 0b -- targets, with vtable + factory")
    for c in ("FutDiscardCardServerResponse", "FutDiscardCardByResServerResponse",
              "FutMoveCardByResServerResponse", "FutCreatePackServerResponse",
              "FutViewCardsServerResponse"):
        print(" ", c, [(hex(a), hex(v), hex(e)) for a, v, e in class_deser(c)])

    print("=" * 78)
    print("SECTION 1 -- the action-descriptor table around 0x1802cb230")
    base = 0x1802CB000
    for i in range(0, 0x600, 8):
        va = base + i
        try:
            q = qword(va)
        except Exception:
            continue
        note = ""
        if 0x1801E5000 <= q <= 0x180290000:
            try:
                t = rd_str(q, 48)
                if t and all(0x20 <= ord(ch) < 0x7F for ch in t):
                    note = "STR %r" % t
            except Exception:
                pass
        if not note and 0x180001000 <= q < 0x1801E5000:
            f = fm.getFunctionAt(addr(q))
            note = "FUNC %s" % (f.getName() if f else "(mid)")
        print("  %#x : %#018x  %s" % (va, q, note))

    print("=" * 78)
    print("SECTION 2 -- readers of the FutDiscardCard response fields")
    print("xrefs to deser 0x180127300:")
    for r in xrefs_to(0x180127300):
        print("   ", [hex(r[0]), r[1], r[2], hex(r[3])])

    print("=" * 78)
    print("SECTION 3 -- TO_TRADEPILE / Tradepile owners")
    show("FUN_1801be6a0 (TO_TRADEPILE)", 0x1801BE6A0)
    show("FUN_18010c3b0 (Tradepile)", 0x18010C3B0)

    print("=" * 78)
    print("SECTION 4 -- the FUT model singleton")
    show("FUN_18011a830 (singleton getter)", 0x18011A830)

    print("=" * 78)
    print("SECTION 5 -- string search for the Scaleform action names, exact literal")
    for lit in (b"CardsDiscardCard\x00", b"CardsDiscardCardList\x00",
                b"CardsDiscardCardByRes\x00", b"GetCardDuplicate\x00",
                b"CardsSwapCards\x00", b"AddCardBackToTradePile\x00",
                b"RemoveFromTradePile\x00", b"RemoveAllSoldFromTradePile\x00",
                b"TradePileFull\x00", b"GetTradePileResults\x00",
                b"CardsMoveCard\x00", b"CardsSendToClub\x00"):
        hits = find_all(lit)
        print("  %-30s hits=%s" % (lit.decode().strip("\x00"), [hex(h) for h in hits]))
        for h in hits:
            for r in xrefs_to(h):
                print("       ref %#x %s %s %#x" % (r[0], r[1], r[2], r[3]))
            for r in xrefs_to(h - 4):
                print("       ref-4 %#x %s %s %#x" % (r[0], r[1], r[2], r[3]))

except Exception:
    traceback.print_exc()
