///|
/// A gradient maps a normalized scalar to a color.
pub(all) struct Gradient {
  stops : Array[Color]
  positions : Array[Double]
} derive(Eq, Debug, ToJson)

///|
pub fn Gradient::new(stops : Array[Color]) -> Gradient {
  let positions = []
  if stops.length() == 1 {
    positions.push(0.0)
  } else {
    for i in 0.. Color {
  if self.stops.length() == 0 {
    Color::rgb8(0, 0, 0)
  } else if self.stops.length() == 1 {
    self.stops[0]
  } else {
    let position = value.max(0.0).min(1.0)
    let mut index = 0
    for i in 0..= self.stops.length() {
      self.stops[index]
    } else {
      let span = self.positions[index + 1] - self.positions[index]
      self.stops[index].mix(
        self.stops[index + 1],
        if span == 0.0 {
          0.0
        } else {
          (position - self.positions[index]) / span
        },
      )
    }
  }
}

///|
pub fn Gradient::sample(self : Gradient, count : Int) -> Array[Color] {
  let result = []
  for i in 0.. Gradient {
  let colors = []
  for offset in 1..<=self.stops.length() {
    colors.push(self.stops[self.stops.length() - offset])
  }
  Gradient::new(colors)
}

///|
pub fn linear_gradient(low : Color, high : Color) -> Gradient {
  Gradient::new([low, high])
}

///|
pub fn three_point_gradient(
  low : Color,
  middle : Color,
  high : Color,
) -> Gradient {
  Gradient::new([low, middle, high])
}

///|
pub fn heat_gradient() -> Gradient {
  Gradient::new([
    Color::rgb8(0, 0, 64),
    Color::rgb8(0, 128, 255),
    Color::rgb8(255, 220, 0),
    Color::rgb8(255, 0, 0),
  ])
}

///|
pub fn alpha_gradient(
  color : Color,
  minimum : Double,
  maximum : Double,
) -> Gradient {
  Gradient::new([color.with_alpha(minimum), color.with_alpha(maximum)])
}