///|
/// Deterministic xorshift32 generator for reproducible protocol tests.
pub struct PropertyGenerator {
  mut state : UInt
} derive(Debug)

///|
pub fn PropertyGenerator::new(seed : UInt) -> PropertyGenerator {
  { state: if seed == 0U { 0x6d2b79f5U } else { seed } }
}

///|
pub fn PropertyGenerator::next_u32(self : PropertyGenerator) -> UInt {
  let mut value = self.state
  value = value ^ (value << 13)
  value = value ^ (value >> 17)
  value = value ^ (value << 5)
  self.state = value
  value
}

///|
pub fn PropertyGenerator::next_byte(self : PropertyGenerator) -> Byte {
  self.next_u32().to_byte()
}

///|
pub fn PropertyGenerator::next_port(self : PropertyGenerator) -> Int {
  (self.next_u32() % 65536U).reinterpret_as_int()
}

///|
pub fn PropertyGenerator::next_bytes(
  self : PropertyGenerator,
  length : Int,
) -> Bytes {
  let output = @buffer.Buffer(size_hint=length)
  for index = 0; index < length; index = index + 1 {
    output.write_byte(self.next_byte())
  }
  output.to_bytes()
}

///|
pub fn PropertyGenerator::next_ipv4(self : PropertyGenerator) -> Ipv4Address {
  Ipv4Address::new(self.next_bytes(4).to_fixedarray()).unwrap()
}

///|
pub fn PropertyGenerator::next_ipv6(self : PropertyGenerator) -> Ipv6Address {
  Ipv6Address::new(self.next_bytes(16).to_fixedarray()).unwrap()
}

///|
pub fn PropertyGenerator::next_unknown_tlv(self : PropertyGenerator) -> RawTlv {
  {
    type_code: (0x80 | (self.next_u32() % 0x50U).reinterpret_as_int()).to_byte(),
    value: self.next_bytes((self.next_u32() % 32U).reinterpret_as_int()),
  }
}

///|
pub fn PropertyGenerator::next_payload(self : PropertyGenerator) -> Bytes {
  self.next_bytes((self.next_u32() % 128U).reinterpret_as_int())
}

///|
pub fn PropertyGenerator::next_v2_header(
  self : PropertyGenerator,
) -> ProxyHeader {
  let selector = (self.next_u32() % 6U).reinterpret_as_int()
  if selector == 0 {
    ProxyHeader::new(V2, Local, Unspec, Unspec, NoAddress, []).unwrap()
  } else if selector == 1 {
    ProxyHeader::new(V2, Proxy, Unspec, Unspec, NoAddress, []).unwrap()
  } else if selector == 2 || selector == 3 {
    ProxyHeader::new(
      V2,
      Proxy,
      Inet,
      if selector == 2 {
        Stream
      } else {
        Datagram
      },
      Ipv4({
        source_address: self.next_ipv4(),
        destination_address: self.next_ipv4(),
        source_port: self.next_port(),
        destination_port: self.next_port(),
      }),
      [],
    ).unwrap()
  } else {
    ProxyHeader::new(
      V2,
      Proxy,
      Inet6,
      if selector == 4 {
        Stream
      } else {
        Datagram
      },
      Ipv6({
        source_address: self.next_ipv6(),
        destination_address: self.next_ipv6(),
        source_port: self.next_port(),
        destination_port: self.next_port(),
      }),
      [],
    ).unwrap()
  }
}