///|
/// franc only looks at this many UTF-16 code units of the input.
let max_sample_length : Int32 = 2048

///|
fn in_ranges(ranges : FixedArray[Int32], cp : Int32) -> Bool {
  let mut lo = 0
  let mut hi = ranges.length() / 2 - 1
  while lo <= hi {
    let mid = (lo + hi) / 2
    if cp < ranges[mid * 2] {
      hi = mid - 1
    } else if cp > ranges[mid * 2 + 1] {
      lo = mid + 1
    } else {
      return true
    }
  }
  false
}

///|
/// Code points below this get their scripts from `script_masks` instead of
/// a search in every script's ranges: it covers the alphabetic scripts and
/// leaves Han, kana and Hangul to the search.
let mask_limit : Int32 = 0x3100

///|
/// For each code point below `mask_limit`, a bit per script of
/// `script_ranges` that contains it.
let script_masks : FixedArray[Int32] = FixedArray::makei(mask_limit, cp => {
  let mut mask = 0
  for s in 0.. FixedArray[Int32] {
  let counts = FixedArray::make(script_ranges.length(), 0)
  let limit = if text.length() < max_sample_length {
    text.length()
  } else {
    max_sample_length
  }
  let mut i = 0
  while i < limit {
    let unit = text.unsafe_get(i).to_int()
    let mut cp = -1
    if unit >= 0xD800 && unit <= 0xDBFF && i + 1 < limit {
      let next = text.unsafe_get(i + 1).to_int()
      if next >= 0xDC00 && next <= 0xDFFF {
        cp = 0x10000 + ((unit - 0xD800) << 10) + (next - 0xDC00)
        i += 1
      }
    } else if unit < 0xD800 || unit > 0xDFFF {
      cp = unit
    }
    i += 1
    if cp < 0 {
      continue
    }
    if cp < mask_limit {
      let mask = script_masks[cp]
      if mask != 0 {
        for s in 0.. (Int32, Int32) {
  let counts = script_counts(text)
  let mut best = -1
  let mut best_count = 0
  for s in 0.. best_count {
      best = s
      best_count = counts[s]
    }
  }
  (best, best_count)
}

///|
/// The writing system used by most characters of `text`, following
/// franc-min 6.2.0: only the first 2048 UTF-16 code units are examined,
/// and ties go to the script listed first in `Script::all()`. Returns
/// `None` when no character belongs to a supported script, e.g. for empty
/// input, digits, punctuation or emoji.
///
/// A character can belong to more than one script: Han ideographs count
/// for both `Han` and `Kana`, so Chinese text is `Han` (the tie goes to
/// `Han`) while Japanese text mixing kana and kanji is `Kana`.
pub fn detect_script(text : String) -> Script? {
  match top_script(text) {
    (-1, _) => None
    (index, _) => Some(all_scripts[index])
  }
}