///|
fn repeated_sequence(length : Int) -> String {
  let pattern = "ATGCGTTAA"
  let buf = StringBuilder::new(size_hint=length)
  let mut produced = 0
  while produced + pattern.length() <= length {
    buf.write_string(pattern)
    produced = produced + pattern.length()
  }
  if produced < length {
    buf.write_string(pattern[0:length - produced].to_owned())
  }
  buf.to_string()
}

///|
fn repeated_protein(length : Int) -> String {
  let pattern = "MRAA*"
  let buf = StringBuilder::new(size_hint=length)
  let mut produced = 0
  while produced + pattern.length() <= length {
    buf.write_string(pattern)
    produced = produced + pattern.length()
  }
  if produced < length {
    buf.write_string(pattern[0:length - produced].to_owned())
  }
  buf.to_string()
}

///|
fn benchmark_translation(seq : String, iterations : Int) -> (UInt64, Int) {
  let options = @translator.TranslationOptions::default()
  let mut checksum = 0
  let start = @env.now()
  for _ in 0.. (UInt64, Int) {
  let mut options = @orf.OrfSearchOptions::default()
  options = { ..options, min_length_nt: 9 }
  let mut checksum = 0
  let start = @env.now()
  for _ in 0.. (UInt64, Int) {
  let table = @tables.standard_table()
  let rscu = @bias.ecoli_reference_rscu()
  let constraints = @optimize.OptimizationConstraints::default()
  let mut checksum = 0
  let start = @env.now()
  for _ in 0.. Unit {
  let line = StringBuilder::new()
  line.write_string("case=")
  line.write_string(name)
  line.write_string(" input_bases=")
  line.write_string(input_size.to_string())
  line.write_string(" iterations=")
  line.write_string(iterations.to_string())
  line.write_string(" elapsed_ms=")
  line.write_string(elapsed_ms.to_string())
  line.write_string(" checksum=")
  line.write_string(checksum.to_string())
  println(line.to_string())
}

///|
fn main {
  let translation_input = repeated_sequence(120_000)
  let orf_input = repeated_sequence(12_000)
  let protein_input = repeated_protein(600)

  // Warm up code paths once; the reported runs use fixed deterministic inputs.
  ignore(benchmark_translation(translation_input, 1))
  ignore(benchmark_orfs(orf_input, 1))
  ignore(benchmark_optimization(protein_input, 1))

  let translation = benchmark_translation(translation_input, 20)
  let orfs = benchmark_orfs(orf_input, 10)
  let optimization = benchmark_optimization(protein_input, 20)
  print_benchmark(
    "translation_report",
    120_000,
    20,
    translation.0,
    translation.1,
  )
  print_benchmark("six_frame_orf_scan", 12_000, 10, orfs.0, orfs.1)
  print_benchmark(
    "constrained_optimization",
    1_800,
    20,
    optimization.0,
    optimization.1,
  )
}