#!/usr/bin/env bash
# diag-staxi-screen.sh - one-off diagnostic for the STAXI title test:
# boot + launch STAXI, dump the full SHR framebuffer + palettes as hex
# at a target frame, then extract JOEYLOG.TXT from the work disk so the
# game's own init/asset-load log is visible. Outputs land in
# build/iigs/bin/ (staxi-shr.hex, staxi-joeylog.txt).
set -euo pipefail

repo=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
: "${LLVM816_ROOT:?diag-staxi-screen.sh: source toolchains/env.sh first}"
CADIUS="${CADIUS:-$LLVM816_ROOT/tools/cadius/cadius}"

sys_disk=$repo/toolchains/emulators/support/gsos-system.po
data_disk=$repo/build/iigs/bin/joey.2mg
rompath="${MAME_ROMPATH:-$HOME/.mame/roms}"
dumpFrame="${STAXI_DUMP_FRAME:-9000}"

work=$(mktemp -d -t joeylib-staxidiag.XXXXXX)
trap 'rm -rf "$work"' EXIT
cp "$sys_disk"  "$work/boot.po"
cp "$data_disk" "$work/joey.2mg"

cat > "$work/diag.lua" <<LUA
local cpu = manager.machine.devices[":maincpu"]
local mem = cpu.spaces["program"]
local nat = manager.machine.natkeyboard
local frame = 0
local idx = 1

local function field(port, name)
    local p = manager.machine.ioport.ports[port]
    if p == nil then return nil end
    return p.fields[name]
end
local key_cmd = field(":macadb:KEY3", "Command / Open Apple")
local function press(f)   if f then f:set_value(1) end end
local function release(f) if f then f:set_value(0) end end

local steps = {
    {3000, function() nat:post("J") end},
    {3120, function() press(key_cmd) end},
    {3126, function() nat:post("o") end},
    {3180, function() release(key_cmd) end},
    {3540, function() nat:post("STAXI") end},
    {3660, function() press(key_cmd) end},
    {3666, function() nat:post("o") end},
    {3720, function() release(key_cmd) end},
}
local pcs = {}

emu.register_frame_done(function()
    frame = frame + 1
    while idx <= #steps and frame >= steps[idx][1] do
        steps[idx][2]()
        idx = idx + 1
    end
    -- Hang localization: sample the PC over 60 frames before the dump,
    -- and probe NEWVIDEO (0xE0C029: bit7 = SHR on -> jlpInit ran).
    if frame == $dumpFrame - 120 then
        io.write(string.format("SHRPROBE newvideo=%02X shadow=%02X\n",
            mem:read_u8(0xE0C029), mem:read_u8(0xE0C035)))
        io.flush()
    end
    if frame >= $dumpFrame - 100 and frame < $dumpFrame - 40 then
        local pc = cpu.state["PC"].value
        local k = string.format("%06X", pc)
        pcs[k] = (pcs[k] or 0) + 1
    end
    if frame == $dumpFrame - 40 then
        for k, v in pairs(pcs) do
            io.write(string.format("SHRPC %s count=%d\n", k, v))
        end
        io.flush()
    end
    if frame == $dumpFrame - 20 then
        -- Locate the jlLog RAM ring without UBER's mailbox: bulk-read every
        -- RAM bank and emit it as hex; the host greps for the build-stamp
        -- text. read_range failures are reported, not swallowed.
        local banks = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,0xE0,0xE1}
        for _, bank in ipairs(banks) do
            local base = bank * 65536
            local ok, buf = pcall(function() return mem:read_range(base, base + 65535, 8) end)
            if ok and buf ~= nil then
                for off = 0, 65535, 256 do
                    local chunk = string.sub(buf, off + 1, off + 256)
                    local hex = {}
                    for i = 1, #chunk do
                        hex[#hex + 1] = string.format("%02X", string.byte(chunk, i))
                    end
                    io.write(string.format("SHRMEM %02X%04X %s\n", bank, off, table.concat(hex)))
                end
            else
                io.write(string.format("SHRMEM-FAIL bank=%02X err=%s\n", bank, tostring(buf)))
            end
        end
        io.flush()
    end
    if frame == $dumpFrame then
        -- SHR pixel dump: 200 rows x 160 bytes as hex lines.
        for row = 0, 199 do
            local parts = {}
            for b = 0, 159 do
                parts[#parts + 1] = string.format("%02X", mem:read_u8(0xE12000 + row * 160 + b))
            end
            io.write("SHRROW " .. table.concat(parts) .. "\n")
        end
        -- SCBs + palettes.
        local scb = {}
        for i = 0, 15 do scb[#scb + 1] = string.format("%02X", mem:read_u8(0xE19D00 + i)) end
        io.write("SHRSCB " .. table.concat(scb, " ") .. "\n")
        local pal = {}
        for i = 0, 31 do pal[#pal + 1] = string.format("%02X", mem:read_u8(0xE19E00 + i)) end
        io.write("SHRPAL " .. table.concat(pal, " ") .. "\n")
        io.flush()
        manager.machine:exit()
    end
end)
LUA

echo "diag-staxi: dumping SHR at frame $dumpFrame..." >&2
cd "$work"
out=$(QT_QPA_PLATFORM=offscreen SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy \
    timeout 900 mame apple2gs \
        -rompath "$rompath" \
        -flop3 "$work/boot.po" -flop4 "$work/joey.2mg" \
        -video none -sound none -nothrottle \
        -autoboot_script "$work/diag.lua" </dev/null 2>&1) || true

echo "$out" | grep -E '^SHR(PROBE|PC)|^SHRMEM-FAIL' | sed 's/^/diag-staxi: /' >&2
echo "$out" | grep -E '^SHRMEM ' > "$repo/build/iigs/bin/staxi-mem.hex" || true
echo "$out" | grep -E '^SHR(ROW|SCB|PAL)' > "$repo/build/iigs/bin/staxi-shr.hex"
wc -l "$repo/build/iigs/bin/staxi-shr.hex" >&2

# The game flushed its log to the volume root; pull it off the WORK copy.
rm -f "$repo/build/iigs/bin/staxi-joeylog.txt" "$work/JOEYLOG.TXT"* 2>/dev/null || true
"$CADIUS" EXTRACTFILE "$work/joey.2mg" "/JOEYLIB/JOEYLOG.TXT" "$work/" >/dev/null 2>&1 || true
found=$(ls "$work"/JOEYLOG.TXT* 2>/dev/null | head -1)
if [ -n "$found" ]; then
    tr -d '\r' < "$found" > "$repo/build/iigs/bin/staxi-joeylog.txt"
    echo "diag-staxi: extracted JOEYLOG.TXT:" >&2
else
    echo "diag-staxi: no JOEYLOG.TXT on work disk (flush never ran?)" >&2
fi
