#!/usr/bin/env python3
"""Pilote l'émulateur iPod Touch 2G (qemu-ios) via son socket QMP.

  ipod-qmp screenshot [sortie.png]     capture l'écran (320x480, PNG ou PPM)
  ipod-qmp tap X Y [DURÉE]            touche l'écran (coordonnées 320x480, appui 0.3 s par défaut)
  ipod-qmp swipe X1 Y1 X2 Y2           glisse (ex. déverrouiller : swipe 40 430 280 430)
  ipod-qmp home | power                appuie sur Home / Power
  ipod-qmp status                      état de la VM
  ipod-qmp hmp COMMANDE                commande du moniteur QEMU (ex. "info registers", "x/8i $pc")
  ipod-qmp quit                        arrête l'émulateur
  ipod-qmp reset                       reset matériel brut (synchroniser la NAND avec ipod-agent sync avant)

Socket : -s SOCK, sinon $IPOD_QMP, sinon ~/ipod-emu/run/qmp.sock
"""
import argparse, json, os, socket, subprocess, sys, tempfile, time

W, H = 320, 480


class QMP:
    def __init__(self, path):
        self.s = socket.socket(socket.AF_UNIX)
        self.s.connect(path)
        self.f = self.s.makefile("rw")
        json.loads(self.f.readline())  # greeting
        self.cmd("qmp_capabilities")

    def cmd(self, name, **args):
        msg = {"execute": name}
        if args:
            msg["arguments"] = args
        self.f.write(json.dumps(msg) + "\n")
        self.f.flush()
        while True:
            line = self.f.readline()
            if not line:
                return None
            r = json.loads(line)
            if "event" in r:
                continue
            if "error" in r:
                sys.exit(f"QMP {name}: {r['error']['desc']}")
            return r.get("return")


def pos(x, y):
    return [{"type": "abs", "data": {"axis": "x", "value": int(x * 0x7fff / (W - 1))}},
            {"type": "abs", "data": {"axis": "y", "value": int(y * 0x7fff / (H - 1))}}]


def btn(down):
    return [{"type": "btn", "data": {"button": "left", "down": down}}]


def key(q, qcode):
    for down in (True, False):
        q.cmd("input-send-event", events=[{"type": "key", "data": {"down": down, "key": {"type": "qcode", "data": qcode}}}])
        time.sleep(0.2)


def main():
    p = argparse.ArgumentParser(usage=__doc__)
    tools_home = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    default_home = tools_home if os.path.isdir(os.path.join(tools_home, "images")) else os.path.expanduser("~/ipod-emu")
    emu_home = os.environ.get("IPOD_EMU_HOME", default_home)
    p.add_argument("-s", "--sock", default=os.environ.get("IPOD_QMP", os.path.join(emu_home, "run", "qmp.sock")))
    p.add_argument("action")
    p.add_argument("args", nargs="*")
    a = p.parse_args()
    q = QMP(a.sock)

    if a.action == "screenshot":
        out = os.path.abspath(a.args[0] if a.args else time.strftime("ipod-%Y%m%d-%H%M%S.png"))
        if out.endswith(".ppm"):
            q.cmd("screendump", filename=out)
        else:
            fd, tmp = tempfile.mkstemp(suffix=".ppm")
            os.close(fd)
            q.cmd("screendump", filename=tmp)
            subprocess.run(["magick", tmp, out], check=True)
            os.unlink(tmp)
        print(out)
    elif a.action == "tap":
        x, y = map(float, a.args[:2])
        hold = float(a.args[2]) if len(a.args) > 2 else 0.3
        q.cmd("input-send-event", events=pos(x, y))
        time.sleep(0.1)
        q.cmd("input-send-event", events=btn(True))
        time.sleep(hold)
        q.cmd("input-send-event", events=btn(False))
    elif a.action == "swipe":
        x1, y1, x2, y2 = map(float, a.args)
        q.cmd("input-send-event", events=pos(x1, y1))
        q.cmd("input-send-event", events=btn(True))
        for i in range(1, 16):
            t = i / 15
            q.cmd("input-send-event", events=pos(x1 + (x2 - x1) * t, y1 + (y2 - y1) * t))
            time.sleep(0.03)
        q.cmd("input-send-event", events=btn(False))
    elif a.action == "home":
        key(q, "h")
    elif a.action == "power":
        key(q, "p")
    elif a.action == "status":
        print(q.cmd("query-status"))
    elif a.action == "hmp":
        print(q.cmd("human-monitor-command", **{"command-line": " ".join(a.args)}))
    elif a.action == "quit":
        q.cmd("quit")
    elif a.action == "reset":
        q.cmd("system_reset")
    else:
        sys.exit(__doc__)


if __name__ == "__main__":
    main()
