///|
/// A small deterministic integer generator for reproducible RANSAC sampling.
pub(all) struct DeterministicSampler {
  mut state : Int
}

///|
pub fn DeterministicSampler::new(seed~ : Int) -> DeterministicSampler {
  { state: if seed == 0 { 1 } else { seed.abs() } }
}

///|
pub fn DeterministicSampler::next(
  sampler : DeterministicSampler,
  bound : Int,
) -> Int {
  sampler.state = (sampler.state * 1103515245 + 12345) % 2147483647
  if bound <= 0 {
    0
  } else {
    sampler.state.abs() % bound
  }
}

///|
pub fn deterministic_sample_indices(
  population~ : Int,
  sample_size~ : Int,
  seed~ : Int,
) -> Array[Int] {
  let result : Array[Int] = []
  let sampler = DeterministicSampler::new(seed~)
  let target = sample_size.max(0).min(population.max(0))
  while result.length() < target {
    let candidate = sampler.next(population)
    if !result.contains(candidate) {
      result.push(candidate)
    }
  }
  result
}

///|
pub fn unique_index_count(indices : ArrayView[Int]) -> Int {
  let unique : Array[Int] = []
  for index in indices {
    if !unique.contains(index) {
      unique.push(index)
    }
  }
  unique.length()
}

///|
pub fn sorted_indices(indices : ArrayView[Int]) -> Array[Int] {
  let result = indices.to_owned()
  result.sort()
  result
}

///|
pub fn sample_complement(
  population : Int,
  selected : ArrayView[Int],
) -> Array[Int] {
  let result : Array[Int] = []
  for index in 0.. Array[Int] {
  let result : Array[Int] = []
  for index in left {
    if !result.contains(index) {
      result.push(index)
    }
  }
  for index in right {
    if !result.contains(index) {
      result.push(index)
    }
  }
  result
}

///|
pub fn sample_intersection(
  left : ArrayView[Int],
  right : ArrayView[Int],
) -> Array[Int] {
  let result : Array[Int] = []
  for index in left {
    if right.contains(index) && !result.contains(index) {
      result.push(index)
    }
  }
  result
}

///|
pub fn sample_is_valid(
  indices : ArrayView[Int],
  population : Int,
  sample_size : Int,
) -> Bool {
  indices.length() == sample_size &&
  unique_index_count(indices) == sample_size &&
  for_all_indices(indices, fn(index) { index >= 0 && index < population })
}

///|
fn for_all_indices(indices : ArrayView[Int], predicate : (Int) -> Bool) -> Bool {
  for index in indices {
    if !predicate(index) {
      return false
    }
  }
  true
}

///|
pub fn sample_batches(
  population : Int,
  sample_size : Int,
  count : Int,
  seed : Int,
) -> Array[Array[Int]] {
  let result : Array[Array[Int]] = []
  let mut current_seed = seed
  for _ in 0.. Double {
  let covered : Array[Int] = []
  for batch in batches {
    for index in batch {
      if !covered.contains(index) {
        covered.push(index)
      }
    }
  }
  if population <= 0 {
    0.0
  } else {
    covered.length().to_double() / population.to_double()
  }
}

///|
pub fn sample_frequency(
  batches : ArrayView[Array[Int]],
  population : Int,
) -> Array[Int] {
  let result : Array[Int] = []
  for _ in 0..= 0 && index < result.length() {
        result[index] += 1
      }
    }
  }
  result
}