// Writes gallery.svg (to stdout): every shape with every fill style.
//
//   moon run src/examples/gallery > gallery.svg

///|
const CELL_W : Double = 150.0

///|
const CELL_H : Double = 130.0

///|
const LEFT : Double = 110.0

///|
const TOP : Double = 40.0

///|
fn label(
  x : Double,
  y : Double,
  text : String,
  anchor~ : String = "middle",
) -> String {
  "\{text}"
}

///|
/// Draws one shape into the cell whose top-left corner is (x, y).
fn draw_shape(
  gen : @moon_rough.Generator,
  shape : String,
  x : Double,
  y : Double,
  options : @moon_rough.Options,
) -> @moon_rough.Drawable {
  match shape {
    "rectangle" => gen.rectangle(x + 20.0, y + 20.0, 110.0, 80.0, options~)
    "ellipse" => gen.ellipse(x + 75.0, y + 60.0, 120.0, 80.0, options~)
    "circle" => gen.circle(x + 75.0, y + 60.0, 90.0, options~)
    "polygon" =>
      gen.polygon(
        [
          (x + 75.0, y + 12.0),
          (x + 135.0, y + 50.0),
          (x + 112.0, y + 108.0),
          (x + 38.0, y + 108.0),
          (x + 15.0, y + 50.0),
        ],
        options~,
      )
    "arc" =>
      gen.arc(
        x + 75.0,
        y + 62.0,
        120.0,
        95.0,
        @jsmath.PI * 0.15,
        @jsmath.PI * 1.65,
        closed=true,
        options~,
      )
    "curve" =>
      gen.curve(
        [
          (x + 15.0, y + 100.0),
          (x + 40.0, y + 15.0),
          (x + 80.0, y + 85.0),
          (x + 135.0, y + 20.0),
          (x + 130.0, y + 110.0),
        ],
        options~,
      )
    _ =>
      // path: a heart with a relative arc
      gen.path(
        "M \{x + 75.0} \{y + 105.0} L \{x + 20.0} \{y + 50.0} a 27 27 0 0 1 55 -25 a 27 27 0 0 1 55 25 Z",
        options~,
      ) catch {
        _ => panic()
      }
  }
}

///|
fn main {
  let gen = @moon_rough.generator(
    source=@moon_rough.RandomSource::park_miller(2024),
  )
  let shapes = [
    "rectangle", "ellipse", "circle", "polygon", "arc", "curve", "path",
  ]
  let styles : Array[@moon_rough.FillStyle?] = [
    None,
    Some(Hachure),
    Some(Solid),
    Some(Zigzag),
    Some(CrossHatch),
    Some(Dots),
    Some(Dashed),
    Some(ZigzagLine),
  ]
  let colors = [
    "none", "#e03131", "#f08c00", "#2f9e44", "#1971c2", "#9c36b5", "#0c8599", "#e8590c",
  ]
  let content = StringBuilder()
  content.write_string(
    label(
      LEFT + CELL_W * 3.5,
      24.0,
      "moon_rough — rough.js 4.6.6 ported to MoonBit",
    ),
  )
  for i, shape in shapes {
    content.write_string(
      label(LEFT + CELL_W * i.to_double() + CELL_W / 2.0, TOP + 14.0, shape),
    )
  }
  for row, style in styles {
    let y = TOP + 20.0 + CELL_H * row.to_double()
    let name = match style {
      Some(style) => style.name()
      None => "stroke only"
    }
    content.write_string(
      label(LEFT - 12.0, y + CELL_H / 2.0, name, anchor="end"),
    )
    for col, shape in shapes {
      let x = LEFT + CELL_W * col.to_double()
      let seed = 1 + row * 16 + col
      let options = match style {
        Some(fill_style) =>
          @moon_rough.Options::new(
            seed~,
            fill=colors[row],
            fill_style~,
            hachure_gap=if fill_style == Dots { 9.0 } else { 6.0 },
            fill_weight=if fill_style == Dots { 2.0 } else { 1.2 },
            stroke_width=1.5,
            fixed_decimal_place_digits=2,
          )
        None =>
          @moon_rough.Options::new(
            seed~,
            stroke_width=1.5,
            fixed_decimal_place_digits=2,
          )
      }
      content.write_string(
        @moon_rough.drawable_to_svg(draw_shape(gen, shape, x, y, options)),
      )
    }
  }
  // Open shapes without a fill.
  let y = TOP + 20.0 + CELL_H * styles.length().to_double()
  let options = @moon_rough.Options::new(
    seed=999,
    stroke_width=1.5,
    roughness=1.8,
    fixed_decimal_place_digits=2,
  )
  content.write_string(
    label(LEFT - 12.0, y + CELL_H / 2.0, "open shapes", anchor="end"),
  )
  let open = [
    gen.line(LEFT + 15.0, y + 100.0, LEFT + 135.0, y + 20.0, options~),
    gen.linear_path(
      [
        (LEFT + CELL_W + 15.0, y + 100.0),
        (LEFT + CELL_W + 55.0, y + 20.0),
        (LEFT + CELL_W + 95.0, y + 100.0),
        (LEFT + CELL_W + 135.0, y + 20.0),
      ],
      options~,
    ),
    gen.arc(
      LEFT + CELL_W * 2.0 + 75.0,
      y + 60.0,
      110.0,
      90.0,
      0.0,
      @jsmath.PI * 1.2,
      options~,
    ),
    gen.curves(
      [
        [
          (LEFT + CELL_W * 3.0 + 15.0, y + 40.0),
          (LEFT + CELL_W * 3.0 + 75.0, y + 10.0),
          (LEFT + CELL_W * 3.0 + 135.0, y + 40.0),
        ],
        [
          (LEFT + CELL_W * 3.0 + 15.0, y + 100.0),
          (LEFT + CELL_W * 3.0 + 75.0, y + 70.0),
          (LEFT + CELL_W * 3.0 + 135.0, y + 100.0),
        ],
      ],
      options~,
    ),
    gen.rectangle(
      LEFT + CELL_W * 4.0 + 20.0,
      y + 20.0,
      110.0,
      80.0,
      options=@moon_rough.Options::new(
        seed=1000,
        roughness=0.0,
        stroke_width=1.5,
        fixed_decimal_place_digits=2,
      ),
    ),
    gen.rectangle(
      LEFT + CELL_W * 5.0 + 20.0,
      y + 20.0,
      110.0,
      80.0,
      options=@moon_rough.Options::new(
        seed=1001,
        roughness=3.0,
        bowing=6.0,
        stroke_width=1.5,
        fixed_decimal_place_digits=2,
      ),
    ),
  ]
  let captions = [
    "line", "linearPath", "open arc", "curves", "roughness 0", "roughness 3",
  ]
  for i, d in open {
    content.write_string(@moon_rough.drawable_to_svg(d))
    content.write_string(
      label(
        LEFT + CELL_W * i.to_double() + CELL_W / 2.0,
        y + CELL_H - 8.0,
        captions[i],
      ),
    )
  }
  let width = LEFT + CELL_W * shapes.length().to_double() + 20.0
  let height = y + CELL_H + 10.0
  println(
    @moon_rough.svg_document(
      width,
      height,
      content.to_string(),
      background="#fff",
    ),
  )
}