"""Minimal SP3F v1 stream reader. Sky Patrol V3 docs: /docs/formats.html"""
import json
import struct

from sp3c_reader import read_sp3c  # the SP3C reader on the same page


def _exact(stream, n):
    data = b""
    while len(data) < n:
        chunk = stream.read(n - len(data))
        if not chunk:
            raise EOFError("SP3F stream ended early: no trailer, treat the batch as failed")
        data += chunk
    return data


def read_sp3f(stream):
    """Yield ('item', header, cols), ('error', dict) and finally ('trailer', dict)."""
    head = _exact(stream, 8)
    if head[:4] != b"SP3F" or head[4] != 1:
        raise ValueError("not an SP3F v1 stream")
    while True:
        frame = _exact(stream, 8)
        kind, (length,) = frame[0], struct.unpack_from("<I", frame, 4)
        payload = _exact(stream, length + (-length) % 8)[:length]
        if kind == 1:
            header, cols = read_sp3c(payload)
            yield "item", header, cols
        elif kind == 2:
            yield "error", json.loads(payload)
        elif kind == 3:
            yield "trailer", json.loads(payload)
            return
        else:
            raise ValueError("unknown SP3F frame kind %d" % kind)
