///|
fn positional(args : Array[String], index : Int, fallback : String) -> String {
  if index < args.length() {
    args[index]
  } else {
    fallback
  }
}

///|
fn parse_config(args : Array[String]) -> (String, Int, UInt) raise Error {
  let prefix = positional(args, 1, "noise-demo")
  let size = @string.parse_int(positional(args, 2, "256"))
  if size < 1 || size > 8192 {
    raise Failure::Failure("image size must be between 1 and 8192")
  }
  let seed = @string.parse_uint(positional(args, 3, "42"))
  (prefix, size, seed)
}

///|
fn run(args : Array[String]) -> Unit raise Error {
  let (prefix, size, seed) = parse_config(args)
  let source = @core.OpenSimplex2S::new(seed)
  let config = @fractal.FbmConfig::new(
    octaves=6,
    persistence=0.5,
    lacunarity=2.0,
    frequency=0.0125,
  ).unwrap()
  let fbm = @fractal.Fbm::new(source, config)
  let simplex_path = prefix + "-simplex.png"
  let fbm_path = prefix + "-fbm.png"
  @render.write_png(simplex_path, size, size, Grayscale, (x, y) => {
    source.sample2(x * 0.0125, y * 0.0125)
  })
  @render.write_png(fbm_path, size, size, Hue, (x, y) => fbm.sample2(x, y))
  println("wrote \{simplex_path}")
  println("wrote \{fbm_path}")
}

///|
fn main {
  run(@env.args()) catch {
    error => abort("noise-demo failed: \{error}")
  }
}