///|
pub struct Sample {
  offset_seconds : Double
  delay_seconds : Double
} derive(Debug)

///|
/// Verifies basic server reply and computes RFC four-timestamp estimates.
/// Caller supplies the original request timestamp and local receipt timestamp.
pub fn measure(
  sent : Timestamp,
  reply : Packet,
  arrived : Timestamp,
) -> Sample raise NtpError {
  if reply.version < 3 || reply.version > 4 || reply.mode != 4 {
    raise Invalid("not an NTPv3/v4 server response")
  }
  if reply.leap < 0 || reply.leap > 2 || reply.stratum < 1 || reply.stratum > 15 {
    raise Invalid("unsynchronized or kiss-of-death response")
  }
  if reply.origin != sent {
    raise Invalid("origin mismatch")
  }
  if reply.receive == Timestamp::zero() || reply.transmit == Timestamp::zero() {
    raise Invalid("missing server timestamp")
  }
  let elapsed = arrived.difference(sent)
  let processing = reply.transmit.difference(reply.receive)
  if elapsed < 0.0 ||
    elapsed > 86400.0 ||
    processing < 0.0 ||
    processing > elapsed {
    raise Invalid("invalid time ordering or negative delay")
  }
  {
    offset_seconds: (
      reply.receive.difference(sent) + reply.transmit.difference(arrived)
    ) /
    2.0,
    delay_seconds: elapsed - processing,
  }
}