///|
/// Compact integer histogram used for baseline and current windows.
pub(all) struct Histogram {
  spec : BucketSpec
  counts : Array[Int]
  total : Int
} derive(Eq, Debug)

///|
pub fn Histogram::new(spec : BucketSpec) -> Histogram {
  { spec, counts: Array::make(spec.bucket_count(), 0), total: 0 }
}

///|
pub fn Histogram::add(self : Histogram, value : Int) -> Histogram {
  let index = self.spec.index_of(value)
  // Histograms are value objects. Copy before changing a bucket so a caller
  // can safely retain a baseline while deriving a current observation window.
  let counts = Array::make(self.counts.length(), 0)
  for i = 0; i < self.counts.length(); i = i + 1 {
    counts[i] = self.counts[i]
  }
  counts[index] = counts[index] + 1
  { spec: self.spec, counts, total: self.total + 1 }
}

///|
pub fn Histogram::add_many(self : Histogram, values : Array[Int]) -> Histogram {
  let mut next = self
  for i = 0; i < values.length(); i = i + 1 {
    next = next.add(values[i])
  }
  next
}

///|
pub fn Histogram::count_at(self : Histogram, index : Int) -> Int {
  if index >= 0 && index < self.counts.length() {
    self.counts[index]
  } else {
    0
  }
}

///|
pub fn Histogram::share_bp_at(self : Histogram, index : Int) -> Int {
  if self.total <= 0 {
    0
  } else {
    self.count_at(index) * 10000 / self.total
  }
}