///|
/// A small reproducible RNG for examples, replay fixtures, and portable
/// sampling. Applications may supply uniforms from their own RNG instead.
pub struct ParkMiller {
  mut state : Int
} derive(Debug)

///|
pub fn ParkMiller::new(seed : Int) -> Result[ParkMiller, SamplingError] {
  if seed <= 0 || seed >= 2147483647 {
    return Err(InvalidParameter("seed must be in 1..2147483646"))
  }
  Ok({ state: seed, })
}

///|
pub fn ParkMiller::state(self : ParkMiller) -> Int {
  self.state
}

///|
/// Schrage's method computes (16807 * state) mod (2^31 - 1) without an
/// overflowing 32-bit multiplication.
pub fn ParkMiller::next_int(self : ParkMiller) -> Int {
  let high = self.state / 127773
  let low = self.state % 127773
  let candidate = 16807 * low - 2836 * high
  self.state = if candidate > 0 { candidate } else { candidate + 2147483647 }
  self.state
}

///|
/// The result lies strictly inside (0, 1), which satisfies the sampler's
/// required [0, 1) interval.
pub fn ParkMiller::next_uniform(self : ParkMiller) -> Double {
  self.next_int().to_double() / 2147483647.0
}

///|
/// Convenience step using this package's reproducible generator. It consumes
/// one draw even if the supplied logits are invalid; callers requiring exact
/// rollback should validate or manage the RNG separately.
pub fn Sampler::sample_with_rng(
  self : Sampler,
  logits : Array[Double],
  rng : ParkMiller,
) -> Result[Step, SamplingError] {
  self.sample(logits, rng.next_uniform())
}