///|
pub(all) struct TimeSeries {
  name : String
  times : Array[Double]
  values : Array[Double]
} derive(Debug, ToJson)

///|
pub fn TimeSeries::new(name : String) -> TimeSeries {
  { name, times: [], values: [] }
}

///|
pub fn TimeSeries::push(
  series : TimeSeries,
  time : Double,
  value : Double,
) -> Unit {
  series.times.push(time)
  series.values.push(value)
}

///|
pub fn TimeSeries::length(series : TimeSeries) -> Int {
  series.times.length().min(series.values.length())
}

///|
pub fn TimeSeries::last_time(series : TimeSeries) -> Double {
  if series.length() == 0 {
    0.0
  } else {
    series.times[series.length() - 1]
  }
}

///|
pub fn TimeSeries::last_value(series : TimeSeries) -> Double {
  if series.length() == 0 {
    0.0
  } else {
    series.values[series.length() - 1]
  }
}

///|
pub fn TimeSeries::mean(series : TimeSeries) -> Double {
  mean(series.values)
}

///|
pub fn TimeSeries::minimum(series : TimeSeries) -> Double {
  min_value(series.values, 0.0)
}

///|
pub fn TimeSeries::maximum(series : TimeSeries) -> Double {
  max_value(series.values, 0.0)
}

///|
pub fn TimeSeries::integral(series : TimeSeries) -> Double {
  if series.length() < 2 {
    0.0
  } else {
    let mut total = 0.0
    for i in 1.. Array[Double] {
  let output = zeros(series.length())
  if series.length() > 1 {
    for i in 1.. Array[Double] {
  moving_average(series.values, width)
}

///|
pub fn TimeSeries::to_csv(series : TimeSeries) -> String {
  let output = StringBuilder()
  output.write_string("time,\{series.name}\n")
  for i in 0.. SeriesSummary {
  summarize_series(series.name, series.values)
}

///|
pub fn TimeSeries::resample(series : TimeSeries, count : Int) -> TimeSeries {
  let result = TimeSeries::new(series.name)
  let values = interpolate_series(series.values, count)
  let times = interpolate_series(series.times, count)
  for i in 0.. TimeSeries {
  let result = TimeSeries::new(first.name)
  let count = first.length().min(second.length())
  for i in 0.. TimeSeries {
  let result = TimeSeries::new(series.name)
  for i in 0.. TimeSeries {
  let result = TimeSeries::new(series.name)
  for i in 0.. Bool {
  monotonic_time(series.times)
}

///|
pub fn TimeSeries::time_span(series : TimeSeries) -> Double {
  if series.length() < 2 {
    0.0
  } else {
    series.times[series.length() - 1] - series.times[0]
  }
}

///|
pub fn series_from_pairs(
  name : String,
  pairs : Array[(Double, Double)],
) -> TimeSeries {
  let result = TimeSeries::new(name)
  for pair in pairs {
    let (time, value) = pair
    result.push(time, value)
  }
  result
}