///|
let canonical_tokens : Array[(Int, String)] = [
  (1000, "M"),
  (900, "CM"),
  (500, "D"),
  (400, "CD"),
  (100, "C"),
  (90, "XC"),
  (50, "L"),
  (40, "XL"),
  (10, "X"),
  (9, "IX"),
  (5, "V"),
  (4, "IV"),
  (1, "I"),
]

///|
/// Format an integer from 1 through 3999 as an uppercase Roman numeral.
pub fn format(value : Int) -> Result[String, FormatError] {
  if value < 1 || value > 3999 {
    return Err(FormatOutOfRange(value))
  }
  let mut remaining = value
  let mut output = ""
  for token in canonical_tokens {
    while remaining >= token.0 {
      output = output + token.1
      remaining = remaining - token.0
    }
  }
  Ok(output)
}

///|
/// Format an integer from 1 through 3999 as a lowercase Roman numeral.
pub fn format_lower(value : Int) -> Result[String, FormatError] {
  match format(value) {
    Ok(text) => Ok(text.to_lower())
    Err(error) => Err(error)
  }
}

///|
/// Format a clock-face hour from 1 through 12, using IIII for four.
pub fn format_clock_hour(hour : Int) -> Result[String, FormatError] {
  if hour < 1 || hour > 12 {
    return Err(InvalidClockHour(hour))
  }
  let hours = [
    "I", "II", "III", "IIII", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII",
  ]
  Ok(hours[hour - 1])
}