///|
/// Gauge repeatability and reproducibility results for a crossed study.
pub struct GaugeRRReport {
  part_count : Int
  operator_count : Int
  repeat_count : Int
  total_measurements : Int
  repeatability : Double
  reproducibility : Double
  part_to_part : Double
  total_variation : Double
  percent_tolerance : Double
  ndc : Double
} derive(Debug, Eq)

///|
fn measurement_group(
  values : Array[Double],
  start : Int,
  count : Int,
) -> Array[Double] {
  let group = []
  for index in 0.. GaugeRRReport {
  if part_count <= 0 || operator_count <= 0 || repeat_count <= 0 {
    abort("gauge R&R dimensions must be positive")
  }
  if tolerance_width <= 0.0 {
    abort("gauge tolerance width must be positive")
  }
  let expected = part_count * operator_count * repeat_count
  if values.length() != expected {
    abort("gauge R&R values do not match the study dimensions")
  }
  let mut pooled_variance = 0.0
  let mut subgroup_count = 0
  let operator_values = []
  for _ in 0.. {
    summarize_samples(values_for_operator).mean
  })
  let reproducibility = summarize_samples(operator_means).standard_deviation
  let part_to_part = summarize_samples(part_means).standard_deviation
  let total_variation = (repeatability * repeatability +
  reproducibility * reproducibility).sqrt()
  let percent_tolerance = total_variation / tolerance_width * 100.0
  let ndc = if total_variation == 0.0 {
    0.0
  } else {
    1.41 * part_to_part / total_variation
  }
  {
    part_count,
    operator_count,
    repeat_count,
    total_measurements: expected,
    repeatability,
    reproducibility,
    part_to_part,
    total_variation,
    percent_tolerance,
    ndc,
  }
}

///|
/// A measured bias relative to a reference value.
pub struct BiasReport {
  count : Int
  reference : Double
  mean : Double
  bias : Double
  standard_deviation : Double
  maximum_absolute_error : Double
} derive(Debug, Eq)

///|
/// Calculate mean bias and maximum absolute error against a reference.
pub fn measurement_bias(
  values : Array[Double],
  reference : Double,
) -> BiasReport {
  let statistics = summarize_samples(values)
  let mut maximum_absolute_error = 0.0
  for value in values {
    let error = (value - reference).abs()
    if error > maximum_absolute_error {
      maximum_absolute_error = error
    }
  }
  {
    count: statistics.count,
    reference,
    mean: statistics.mean,
    bias: statistics.mean - reference,
    standard_deviation: statistics.standard_deviation,
    maximum_absolute_error,
  }
}

///|
/// Return the average absolute error against a reference.
pub fn mean_absolute_error(
  values : Array[Double],
  reference : Double,
) -> Double {
  let mut total = 0.0
  for value in values {
    total += (value - reference).abs()
  }
  total / values.length().to_double()
}

///|
/// Return the percentage of measurements inside an interval.
pub fn measurement_yield(
  values : Array[Double],
  window : AcceptanceWindow,
) -> Double {
  let mut accepted = 0
  for value in values {
    if window.contains(value) {
      accepted += 1
    }
  }
  accepted.to_double() / values.length().to_double()
}