///|
pub enum SeriesError {
  EmptySeries
  InvalidValue
} derive(Debug, Eq)

///|
pub struct NumericSeries {
  label : String
  unit : String
  values : Array[String]
} derive(Debug, Eq)

///|
pub struct SeriesStatistics {
  minimum : String
  maximum : String
  mean : String
  count : Int
} derive(Debug, Eq)

///|
pub fn numeric_series(
  label : String,
  unit : String,
  values : Array[String],
) -> NumericSeries {
  { label, unit, values }
}

///|
pub fn NumericSeries::statistics(
  self : NumericSeries,
) -> Result[SeriesStatistics, SeriesError] {
  if self.values.length() == 0 {
    return Err(EmptySeries)
  }
  let first = decimal_scaled(self.values[0])
  if first is None {
    return Err(InvalidValue)
  }
  let mut minimum = first.unwrap()
  let mut maximum = first.unwrap()
  let mut total = first.unwrap()
  for value in self.values[1:] {
    let parsed = decimal_scaled(value)
    if parsed is None {
      return Err(InvalidValue)
    }
    let number = parsed.unwrap()
    minimum = Int::min(minimum, number)
    maximum = Int::max(maximum, number)
    total += number
  }
  Ok({
    minimum: scaled_string(minimum),
    maximum: scaled_string(maximum),
    mean: scaled_string(total / self.values.length()),
    count: self.values.length(),
  })
}

///|
pub fn NumericSeries::is_monotonic(self : NumericSeries) -> Bool {
  if self.values.length() < 2 {
    return true
  }
  let previous = decimal_scaled(self.values[0])
  if previous is None {
    return false
  }
  for value in self.values[1:] {
    let current = decimal_scaled(value)
    if current is None || current.unwrap() < previous.unwrap() {
      break false
    }
  } nobreak {
    true
  }
}