// vl2svg: render a Vega-Lite JSON file to SVG (or dump its scenegraph).
//
//   vl2svg spec.vl.json [out.svg]      write SVG (stdout when no output)
//   vl2svg --sketch [--seed N] [--roughness R] [--decimals D] spec.vl.json [out.svg]
//                                      hand-drawn style (moon_rough); same spec and seed, same bytes
//   vl2svg --scene spec.vl.json        print the scenegraph as JSON

///|
fn fail_with(msg : String) -> Unit {
  println("error: " + msg)
  @sys.exit(1)
}

///|
fn parse_number(flag : String, text : String) -> Double {
  @string.parse_double(text) catch {
    _ => {
      fail_with(flag + " needs a number, got " + text)
      0.0
    }
  }
}

///|
/// The value after `flag`, if the flag is there.
fn flag_value(args : Array[String], flag : String) -> String? {
  for i in 0.. Unit raise Error {
  let args = @env.args()
  let rest = args[1:].to_owned()
  let scene_mode = rest.contains("--scene")
  let sketch = rest.contains("--sketch")
  let seed = match flag_value(rest, "--seed") {
    Some(v) => parse_number("--seed", v).to_int()
    None => 1
  }
  let roughness = match flag_value(rest, "--roughness") {
    Some(v) => parse_number("--roughness", v)
    None => 1.0
  }
  let decimals = match flag_value(rest, "--decimals") {
    Some(v) => Some(parse_number("--decimals", v).to_int())
    None => None
  }
  // flags with a value are not file names
  let files : Array[String] = []
  let mut skip = false
  for a in rest {
    if skip {
      skip = false
    } else if a == "--seed" || a == "--roughness" || a == "--decimals" {
      skip = true
    } else if a != "--scene" && a != "--sketch" {
      files.push(a)
    }
  }
  if files.length() == 0 {
    fail_with(
      "usage: vl2svg [--scene | --sketch [--seed N] [--roughness R] [--decimals D]] spec.vl.json [out.svg]",
    )
    return
  }
  let text = @fs.read_file_to_string(files[0])
  let c = @moon_vegalite.compile(text) catch {
    e => {
      fail_with(e.message())
      return
    }
  }
  if scene_mode {
    println(@moon_vegalite.scene_json(c).stringify())
    return
  }
  let rendered = if sketch {
    Ok(
      @moon_vegalite.svg_sketch_of(
        c,
        options=@moon_vegalite.SketchOptions::new(
          seed~,
          roughness~,
          fixed_decimals?=decimals,
        ),
      ),
    ) catch {
      e => Err(e.message())
    }
  } else {
    Ok(@moon_vegalite.svg_of(c)) catch {
      e => Err(e.message())
    }
  }
  let svg = match rendered {
    Ok(svg) => svg
    Err(message) => {
      fail_with(message)
      return
    }
  }
  if files.length() > 1 {
    @fs.write_string_to_file(files[1], svg)
  } else {
    println(svg)
  }
}

///|
fn main {
  run() catch {
    e => fail_with(e.to_string())
  }
}