// The North American Numbering Plan, the one plan in the table whose structural
// rules are published as rules rather than as tables.
//
// The NANP is ten digits, NPA-NXX-XXXX. Both the area code (NPA) and the exchange
// (NXX) start with 2-9, and an area code of the form N11 is a service code, never
// a geographic one. Those three rules reject most of what cannot be a +1 number
// without consulting any pattern at all.
//
// Which *territory* a +1 number belongs to is a different question, and the plans
// now answer it: the +1 space covers 25 regions (US, CA and 23 Caribbean and
// Pacific territories), each with its own published area-code allocation. So
// `nanp_region_of` walks the territories' patterns instead of a hand-maintained
// list, and a new overlay code arrives with a data refresh rather than a code
// change.

///|
/// The number of digits in a NANP national number.
let nanp_length : Int = 10

///|
/// The digits of the number, or None when it is not exactly ten digits.
fn nanp_digits(national_number : String) -> Array[Char]? {
  let cs = chars_of(national_number)
  if cs.length() != nanp_length {
    return None
  }
  for c in cs {
    if !is_digit(c) {
      return None
    }
  }
  Some(cs)
}

///|
/// True for an NPA or NXX leading digit: 2 through 9.
fn nanp_leading_digit(c : Char) -> Bool {
  c >= '2' && c <= '9'
}

///|
/// True when the area code is an N11 service code (211, 311, ... 911), which is
/// never a geographic area code.
fn nanp_is_service_code(cs : Array[Char]) -> Bool {
  cs[1] == '1' && cs[2] == '1'
}

///|
/// The plan's structural rule: ten digits, an area code and an exchange that both
/// start 2-9, and no N11 area code.
///
/// A `555` exchange is structurally valid; only 555-0100..0199 is reserved for
/// fiction, which is an assignment fact and not part of the shape.
pub fn nanp_possible(national_number : String) -> Bool {
  match nanp_digits(national_number) {
    None => false
    Some(cs) =>
      nanp_leading_digit(cs[0]) &&
      !nanp_is_service_code(cs) &&
      nanp_leading_digit(cs[3])
  }
}

///|
/// The area code of a ten-digit (not necessarily possible) NANP number.
pub fn nanp_area_code(national_number : String) -> String? {
  match nanp_digits(national_number) {
    None => None
    Some(cs) => Some(slice(cs, 0, 3))
  }
}

///|
/// Every region the table places inside the NANP, in table order.
pub fn nanp_region_codes() -> Array[String] {
  let out : Array[String] = []
  for r in regions {
    if r.calling_code == 1 {
      out.push(r.code)
    }
  }
  out
}

///|
/// The territory a +1 national number belongs to.
///
/// The structural rule runs first, so a number without NANP shape has no
/// territory at all. The territories' published patterns then decide: the region
/// marked primary (the United States) wins a tie, which is what sends a toll-free
/// or shared range to US while an ordinary Canadian number resolves to CA. None
/// when the number is structurally valid but no territory's allocation claims it
/// — possible, but not assigned.
pub fn nanp_region_of(national_number : String) -> String? {
  if !nanp_possible(national_number) {
    return None
  }
  let mut fallback : String? = None
  for r in regions {
    if r.calling_code != 1 {
      continue
    }
    // The territory's leading digits answer the cheap half of the question: a
    // number outside them cannot belong to it, so its full rules need not run.
    if !region_leading_matches(r, national_number) {
      continue
    }
    if region_admits(r, national_number) {
      if r.primary {
        return Some(r.code)
      }
      if fallback is None {
        fallback = Some(r.code)
      }
    }
  }
  fallback
}