///|
/// Deterministic image-quality metrics for comparing two RGBA images.
///
/// `mse` and `psnr` compare all four stored channels (R, G, B and A) with
/// equal weight. `luma_mse` and `ssim` use the integer Rec.601 luma
/// `floor((299R + 587G + 114B) / 1000)` and ignore alpha. All metrics require
/// equal image dimensions and abort on malformed backing buffers. Empty,
/// equal-sized images are supported: MSE is zero and SSIM is one.

///|
/// Checks the shape and backing-buffer invariants shared by all metrics.
fn metric_pixel_count(a : Image, b : Image) -> Int {
  if a.width != b.width || a.height != b.height {
    abort("image metrics require equal dimensions")
  }
  let expected = checked_buffer_len(a.width, a.height)
  if a.data.length() != expected || b.data.length() != expected {
    abort("image metrics require valid RGBA backing buffers")
  }
  expected / 4
}

///|
/// Mean squared error over all RGBA channels. The result is in channel-value
/// squared units, in the range `[0, 65025]` for valid 8-bit images.
pub fn Image::mse(self : Image, other : Image) -> Double {
  let n = metric_pixel_count(self, other)
  if n == 0 {
    return 0.0
  }
  let mut sum = 0L
  for p in 0.. Double {
  let error = self.mse(other)
  if error == 0.0 {
    return @double.infinity
  }
  10.0 * @math.log10(65025.0 / error)
}

///|
/// Mean squared error over Rec.601 luma only. Alpha is intentionally ignored.
pub fn Image::luma_mse(self : Image, other : Image) -> Double {
  let n = metric_pixel_count(self, other)
  if n == 0 {
    return 0.0
  }
  let mut sum = 0L
  for p in 0.. Double {
  let n = metric_pixel_count(self, other)
  if n == 0 {
    return 1.0
  }
  let mut sum_a = 0L
  let mut sum_b = 0L
  let mut sum_aa = 0L
  let mut sum_bb = 0L
  let mut sum_ab = 0L
  for p in 0.. 1.0 {
    1.0
  } else {
    value
  }
}