///|
/// RFC 5646 irregular grandfathered tags.
fn irregular_grandfathered() -> Array[String] {
  [
    "en-GB-oed", "i-ami", "i-bnn", "i-default", "i-enochian", "i-hak", "i-klingon",
    "i-lux", "i-mingo", "i-navajo", "i-pwn", "i-tao", "i-tay", "i-tsu", "sgn-BE-FR",
    "sgn-BE-NL", "sgn-CH-DE",
  ]
}

///|
/// RFC 5646 regular grandfathered tags.
fn regular_grandfathered() -> Array[String] {
  [
    "art-lojban", "cel-gaulish", "no-bok", "no-nyn", "zh-guoyu", "zh-hakka", "zh-min",
    "zh-min-nan", "zh-xiang",
  ]
}

///|
fn is_grandfathered(tag : String) -> Bool {
  let low = lower_ascii(tag)
  let irr = irregular_grandfathered()
  let mut i = 0
  while i < irr.length() {
    if lower_ascii(irr[i]) == low {
      return true
    }
    i += 1
  }
  let reg = regular_grandfathered()
  i = 0
  while i < reg.length() {
    if lower_ascii(reg[i]) == low {
      return true
    }
    i += 1
  }
  false
}

///|
fn grandfathered_canonical_form(tag : String) -> String {
  let low = lower_ascii(tag)
  let irr = irregular_grandfathered()
  let mut i = 0
  while i < irr.length() {
    if lower_ascii(irr[i]) == low {
      return irr[i]
    }
    i += 1
  }
  let reg = regular_grandfathered()
  i = 0
  while i < reg.length() {
    if lower_ascii(reg[i]) == low {
      return reg[i]
    }
    i += 1
  }
  tag
}

///|
/// Documented IANA preferred-value subset used by canonicalize().
fn preferred_value(tag : String) -> String {
  let low = lower_ascii(tag)
  match low {
    "i-ami" => "ami"
    "i-bnn" => "bnn"
    "i-hak" => "hak"
    "i-klingon" => "tlh"
    "i-lux" => "lb"
    "i-navajo" => "nv"
    "i-pwn" => "pwn"
    "i-tao" => "tao"
    "i-tay" => "tay"
    "i-tsu" => "tsu"
    "art-lojban" => "jbo"
    "no-bok" => "nb"
    "no-nyn" => "nn"
    "sgn-be-fr" => "sfb"
    "sgn-be-nl" => "vgt"
    "sgn-ch-de" => "sgg"
    "zh-guoyu" => "cmn"
    "zh-hakka" => "hak"
    "zh-min-nan" => "nan"
    "zh-xiang" => "hsn"
    "en-gb-oed" => "en-GB-oxendict"
    _ => tag
  }
}

///|
/// Small suppress-script table for RFC 5646 section 4.1 redundant-script removal.
fn suppress_script_for(language : String) -> String {
  match lower_ascii(language) {
    "en" => "Latn"
    "de" => "Latn"
    "fr" => "Latn"
    "es" => "Latn"
    "it" => "Latn"
    "nl" => "Latn"
    "pt" => "Latn"
    "sv" => "Latn"
    "pl" => "Latn"
    "tr" => "Latn"
    "vi" => "Latn"
    "id" => "Latn"
    "ms" => "Latn"
    "sw" => "Latn"
    "ha" => "Latn"
    "fi" => "Latn"
    "hu" => "Latn"
    "cs" => "Latn"
    "ro" => "Latn"
    "da" => "Latn"
    "no" => "Latn"
    "nb" => "Latn"
    "nn" => "Latn"
    "ru" => "Cyrl"
    "uk" => "Cyrl"
    "bg" => "Cyrl"
    "sr" => "Cyrl"
    "mk" => "Cyrl"
    "be" => "Cyrl"
    "ar" => "Arab"
    "fa" => "Arab"
    "ur" => "Arab"
    "he" => "Hebr"
    "yi" => "Hebr"
    "hi" => "Deva"
    "mr" => "Deva"
    "ne" => "Deva"
    "th" => "Thai"
    "ko" => "Kore"
    "ja" => "Jpan"
    "zh" => "Hani"
    "el" => "Grek"
    "am" => "Ethi"
    "ka" => "Geor"
    "hy" => "Armn"
    "km" => "Khmr"
    "lo" => "Laoo"
    "my" => "Mymr"
    _ => ""
  }
}

///|
fn preferred_region(region : String) -> String {
  match lower_ascii(region) {
    "uk" => "GB"
    "tp" => "TL"
    "bu" => "MM"
    "zr" => "CD"
    _ => region
  }
}

///|
fn preferred_language(language : String) -> String {
  match lower_ascii(language) {
    "iw" => "he"
    "in" => "id"
    "ji" => "yi"
    "jw" => "jv"
    "mo" => "ro"
    _ => language
  }
}