///|
fn linkify_split_domain_for_tld(host : StringView) -> (String, String)? {
  let stripped = linkify_strip_edge_dots(host.trim())
  if stripped.is_empty() {
    return None
  }
  if stripped.compare_ignore_ascii_case("localhost") == 0 {
    return Some(("localhost", ""))
  }
  match linkify_last_char_index(stripped, '.') {
    Some(dot) => {
      let base = stripped[0:dot]
      let tld = stripped[dot + 1:stripped.length()]
      Some((base.to_owned(), tld.to_lower().to_owned()))
    }
    None => None
  }
}

///|
fn linkify_strip_edge_dots(value : StringView) -> StringView {
  let mut start = 0
  let mut end = value.length()
  while start < end && value.get_char(start) is Some('.') {
    start += 1
  }
  while end > start && value.get_char(end - 1) is Some('.') {
    end -= 1
  }
  value[start:end]
}

///|
fn linkify_valid_tld(tld : String, extra_tlds : Set[String]) -> Bool {
  let tld = tld.trim().to_lower().to_owned()
  if tld == "" {
    return false
  }
  if tld.has_prefix("xn--") {
    return true
  }
  linkify_default_tld(tld) ||
  linkify_common_cc_tld(tld) ||
  extra_tlds.contains(tld)
}

///|
fn linkify_default_tld(tld : StringView) -> Bool {
  match tld {
    "aero"
    | "asia"
    | "biz"
    | "com"
    | "coop"
    | "edu"
    | "gov"
    | "info"
    | "museum"
    | "name"
    | "net"
    | "org"
    | "pro"
    | "shop"
    | "web"
    | "xxx"
    | "рф" => true
    _ => false
  }
}

///|
fn linkify_common_cc_tld(tld : StringView) -> Bool {
  match tld {
    "ac"
    | "ad"
    | "ae"
    | "af"
    | "ag"
    | "ai"
    | "al"
    | "am"
    | "an"
    | "ao"
    | "aq"
    | "ar"
    | "as"
    | "at"
    | "au"
    | "aw"
    | "ax"
    | "az"
    | "ba"
    | "bb"
    | "bd"
    | "be"
    | "bf"
    | "bg"
    | "bh"
    | "bi"
    | "bj"
    | "bm"
    | "bn"
    | "bo"
    | "br"
    | "bs"
    | "bt"
    | "bv"
    | "bw"
    | "by"
    | "bz"
    | "ca"
    | "cc"
    | "cd"
    | "cf"
    | "cg"
    | "ch"
    | "ci"
    | "ck"
    | "cl"
    | "cm"
    | "cn"
    | "co"
    | "cr"
    | "cu"
    | "cv"
    | "cw"
    | "cx"
    | "cy"
    | "cz"
    | "de"
    | "dj"
    | "dk"
    | "dm"
    | "do"
    | "dz"
    | "ec"
    | "ee"
    | "eg"
    | "er"
    | "es"
    | "et"
    | "eu"
    | "fi"
    | "fj"
    | "fk"
    | "fm"
    | "fo"
    | "fr"
    | "ga"
    | "gb"
    | "gd"
    | "ge"
    | "gf"
    | "gg"
    | "gh"
    | "gi"
    | "gl"
    | "gm"
    | "gn"
    | "gp"
    | "gq"
    | "gr"
    | "gs"
    | "gt"
    | "gu"
    | "gw"
    | "gy"
    | "hk"
    | "hm"
    | "hn"
    | "hr"
    | "ht"
    | "hu"
    | "id"
    | "ie"
    | "il"
    | "im"
    | "in"
    | "io"
    | "iq"
    | "ir"
    | "is"
    | "it"
    | "je"
    | "jm"
    | "jo"
    | "jp"
    | "ke"
    | "kg"
    | "kh"
    | "ki"
    | "km"
    | "kn"
    | "kp"
    | "kr"
    | "kw"
    | "ky"
    | "kz"
    | "la"
    | "lb"
    | "lc"
    | "li"
    | "lk"
    | "lr"
    | "ls"
    | "lt"
    | "lu"
    | "lv"
    | "ly"
    | "ma"
    | "mc"
    | "md"
    | "me"
    | "mg"
    | "mh"
    | "mk"
    | "ml"
    | "mm"
    | "mn"
    | "mo"
    | "mp"
    | "mq"
    | "mr"
    | "ms"
    | "mt"
    | "mu"
    | "mv"
    | "mw"
    | "mx"
    | "my"
    | "mz"
    | "na"
    | "nc"
    | "ne"
    | "nf"
    | "ng"
    | "ni"
    | "nl"
    | "no"
    | "np"
    | "nr"
    | "nu"
    | "nz"
    | "om"
    | "pa"
    | "pe"
    | "pf"
    | "pg"
    | "ph"
    | "pk"
    | "pl"
    | "pm"
    | "pn"
    | "pr"
    | "ps"
    | "pt"
    | "pw"
    | "py"
    | "qa"
    | "re"
    | "ro"
    | "rs"
    | "ru"
    | "rw"
    | "sa"
    | "sb"
    | "sc"
    | "sd"
    | "se"
    | "sg"
    | "sh"
    | "si"
    | "sj"
    | "sk"
    | "sl"
    | "sm"
    | "sn"
    | "so"
    | "sr"
    | "st"
    | "su"
    | "sv"
    | "sx"
    | "sy"
    | "sz"
    | "tc"
    | "td"
    | "tf"
    | "tg"
    | "th"
    | "tj"
    | "tk"
    | "tl"
    | "tm"
    | "tn"
    | "to"
    | "tr"
    | "tt"
    | "tv"
    | "tw"
    | "tz"
    | "ua"
    | "ug"
    | "uk"
    | "us"
    | "uy"
    | "uz"
    | "va"
    | "vc"
    | "ve"
    | "vg"
    | "vi"
    | "vn"
    | "vu"
    | "wf"
    | "ws"
    | "ye"
    | "yt"
    | "za"
    | "zm"
    | "zw" => true
    _ => false
  }
}