///|
/// A temporal bin of catalog events.
pub struct CatalogTimeBin {
  start_time : Double
  end_time : Double
  event_count : Int
  mean_magnitude : Double
  maximum_magnitude : Double
  mean_confidence : Double
}

///|
/// Build fixed-duration catalog time bins.
pub fn catalog_time_bins(
  catalog : EventCatalog,
  start_time : Double,
  end_time : Double,
  bin_seconds : Double,
) -> Array[CatalogTimeBin] {
  let result = Array::new()
  if bin_seconds <= 0.0 || end_time <= start_time {
    return result
  }
  let count = ((end_time - start_time) / bin_seconds).ceil().to_int().max(0)
  for index = 0; index < count; index = index + 1 {
    let left = start_time + index.to_double() * bin_seconds
    let right = (left + bin_seconds).min(end_time)
    let entries = catalog.entries.filter(entry => {
      entry.origin_time >= left && entry.origin_time < right
    })
    result.push({
      start_time: left,
      end_time: right,
      event_count: entries.length(),
      mean_magnitude: mean_samples(entries.map(entry => entry.magnitude)),
      maximum_magnitude: maximum_sample(entries.map(entry => entry.magnitude)),
      mean_confidence: mean_samples(entries.map(entry => entry.confidence)),
    })
  }
  result
}

///|
/// Return the temporal bin with the largest event count.
pub fn busiest_catalog_bin(bins : Array[CatalogTimeBin]) -> CatalogTimeBin? {
  if bins.is_empty() {
    return None
  }
  let mut best = 0
  for index = 1; index < bins.length(); index = index + 1 {
    if bins[index].event_count > bins[best].event_count {
      best = index
    }
  }
  Some(bins[best])
}

///|
/// Export temporal catalog bins.
pub fn catalog_time_bins_to_csv(bins : Array[CatalogTimeBin]) -> String {
  let mut output = "start_time,end_time,event_count,mean_magnitude,maximum_magnitude,mean_confidence\n"
  for bin in bins {
    output = output +
      bin.start_time.to_string() +
      "," +
      bin.end_time.to_string() +
      "," +
      bin.event_count.to_string() +
      "," +
      bin.mean_magnitude.to_string() +
      "," +
      bin.maximum_magnitude.to_string() +
      "," +
      bin.mean_confidence.to_string() +
      "\n"
  }
  output
}

///|
/// Format a catalog time bin.
pub fn catalog_time_bin_text(bin : CatalogTimeBin) -> String {
  "start=" +
  bin.start_time.to_string() +
  " end=" +
  bin.end_time.to_string() +
  " events=" +
  bin.event_count.to_string() +
  " mean_mag=" +
  bin.mean_magnitude.to_string() +
  " max_mag=" +
  bin.maximum_magnitude.to_string() +
  " confidence=" +
  bin.mean_confidence.to_string()
}