///|
/// Fixed-capacity numeric window with O(1) mean updates and explicit quality state.
pub struct Window {
  capacity : Int
  mut storage : Array[Double]
  mut start : Int
  mut length : Int
  mut sum : Double
  mut sum_squares : Double
}

///|
pub fn Window::new(capacity : Int) -> Result[Window, DetectError] {
  if capacity < 1 {
    return Err(InvalidRunLengthLimit)
  }
  Ok({ capacity, storage: [], start: 0, length: 0, sum: 0.0, sum_squares: 0.0, })
}

///|
pub fn Window::length(self : Window) -> Int {
  self.length
}

///|
pub fn Window::is_full(self : Window) -> Bool {
  self.length == self.capacity
}

///|
pub fn Window::values(self : Window) -> Array[Double] {
  let result = []
  for offset in 0.. Result[Unit, DetectError] {
  if !finite(value) {
    return Err(NonFiniteObservation)
  }
  if self.length == self.capacity {
    let evicted = self.storage[self.start]
    self.storage[self.start] = value
    self.start = (self.start + 1) % self.capacity
    self.sum = self.sum - evicted
    self.sum_squares = self.sum_squares - evicted * evicted
  } else {
    self.storage.push(value)
    self.length = self.length + 1
  }
  self.sum = self.sum + value
  self.sum_squares = self.sum_squares + value * value
  Ok(())
}

///|
pub fn Window::mean(self : Window) -> Double? {
  if self.length == 0 {
    None
  } else {
    Some(self.sum / self.length.to_double())
  }
}

///|
/// Population variance; useful for short online windows where a sample correction is not wanted.
pub fn Window::variance(self : Window) -> Double? {
  if self.length == 0 {
    return None
  }
  let size = self.length.to_double()
  let variance = self.sum_squares / size - self.sum / size * (self.sum / size)
  Some(if variance > 0.0 { variance } else { 0.0 })
}

///|
pub fn Window::minimum(self : Window) -> Double? {
  if self.length == 0 {
    return None
  }
  let mut result = self.storage[self.start]
  for offset in 1.. Double? {
  if self.length == 0 {
    return None
  }
  let mut result = self.storage[self.start]
  for offset in 1.. result {
      result = value
    }
  }
  Some(result)
}

///|
pub fn Window::clear(self : Window) -> Unit {
  self.storage = []
  self.start = 0
  self.length = 0
  self.sum = 0.0
  self.sum_squares = 0.0
}

///|
/// Online quality facts for a numeric sequence.
pub struct Quality {
  values : Int
  non_finite : Int
  minimum : Double?
  maximum : Double?
  monotonic_increasing : Bool
}

///|
pub fn inspect_values(values : Array[Double]) -> Quality {
  let mut non_finite = 0
  let mut minimum : Double? = None
  let mut maximum : Double? = None
  let mut previous : Double? = None
  let mut monotonic = true
  for value in values {
    if !finite(value) {
      non_finite = non_finite + 1
    } else {
      match minimum {
        None => minimum = Some(value)
        Some(current) => if value < current { minimum = Some(value) }
      }
      match maximum {
        None => maximum = Some(value)
        Some(current) => if value > current { maximum = Some(value) }
      }
      match previous {
        None => ()
        Some(current) => if value < current { monotonic = false }
      }
      previous = Some(value)
    }
  }
  {
    values: values.length(),
    non_finite,
    minimum,
    maximum,
    monotonic_increasing: monotonic,
  }
}