///|
/// A rectangular scalar field used to drive color, scale and displacement.
pub(all) struct ScalarField {
  width : Int
  height : Int
  values : Array[Double]
} derive(Eq, Debug, ToJson)

///|
pub fn ScalarField::new(
  width : Int,
  height : Int,
  fill? : Double = 0.0,
) -> ScalarField {
  let values = []
  if width > 0 && height > 0 {
    for _ in 0..<(width * height) {
      values.push(fill)
    }
  }
  { width, height, values }
}

///|
pub fn[N : NoiseSampler] ScalarField::from_sampler(
  width : Int,
  height : Int,
  scale : Double,
  sampler : N,
) -> ScalarField {
  let field = ScalarField::new(width, height)
  for y in 0.. Int {
  y * self.width + x
}

///|
pub fn ScalarField::in_bounds(self : ScalarField, x : Int, y : Int) -> Bool {
  x >= 0 && y >= 0 && x < self.width && y < self.height
}

///|
pub fn ScalarField::get(self : ScalarField, x : Int, y : Int) -> Double? {
  if self.in_bounds(x, y) {
    Some(self.values[self.index(x, y)])
  } else {
    None
  }
}

///|
pub fn ScalarField::set(
  self : ScalarField,
  x : Int,
  y : Int,
  value : Double,
) -> Bool {
  if self.in_bounds(x, y) {
    self.values[self.index(x, y)] = value
    true
  } else {
    false
  }
}

///|
pub fn ScalarField::map(
  self : ScalarField,
  transform : (Double) -> Double,
) -> ScalarField {
  let result = ScalarField::new(self.width, self.height)
  for i, value in self.values {
    result.values[i] = transform(value)
  }
  result
}

///|
pub fn ScalarField::normalize(self : ScalarField) -> ScalarField {
  let stats = sample_stats(self.values)
  if stats.maximum == stats.minimum {
    self.map(fn(_value) { 0.0 })
  } else {
    self.map(fn(value) {
      (value - stats.minimum) / (stats.maximum - stats.minimum)
    })
  }
}

///|
pub fn ScalarField::blur(self : ScalarField, radius : Int) -> ScalarField {
  let result = ScalarField::new(self.width, self.height)
  if radius <= 0 {
    self
  } else {
    for y in 0.. {
                total += value
                count += 1
              }
              None => ()
            }
          }
        }
        let _ = result.set(
          x,
          y,
          if count == 0 {
            0.0
          } else {
            total / count.to_double()
          },
        )
      }
    }
    result
  }
}

///|
pub fn ScalarField::to_points(
  self : ScalarField,
  threshold : Double,
) -> Array[Vec2] {
  let points = []
  for y in 0..= threshold {
        points.push(Vec2::new(x.to_double(), y.to_double()))
      }
    }
  }
  points
}

///|
pub fn ScalarField::to_svg(
  self : ScalarField,
  cell_size : Double,
  low : Color,
  high : Color,
) -> SvgDocument {
  let document = SvgDocument::new(
    self.width.to_double() * cell_size,
    self.height.to_double() * cell_size,
  )
  let normalized = self.normalize()
  for y in 0..