///|
pub fn validate_gtin(value : String) -> Bool {
  (
    value.length() == 8 ||
    value.length() == 12 ||
    value.length() == 13 ||
    value.length() == 14
  ) &&
  is_all_digits(value) &&
  mod10_check_digit(value)
}

///|
pub fn validate_sscc(value : String) -> Bool {
  value.length() == 18 && is_all_digits(value) && mod10_check_digit(value)
}

///|
pub fn validate_gln(value : String) -> Bool {
  value.length() == 13 && is_all_digits(value) && mod10_check_digit(value)
}

///|
pub fn validate_grai(value : String) -> Bool {
  value.length() == 14 && is_all_digits(value) && mod10_check_digit(value)
}

///|
pub fn validate_giai(value : String) -> Bool {
  value.length() >= 1 && value.length() <= 30 && is_all_digits(value)
}

///|
fn mod10_check_digit(value : String) -> Bool {
  if value.length() < 2 {
    false
  } else {
    let body_length = value.length() - 1
    let sum = for i = body_length - 1, acc = 0; i >= 0; i = i - 1 {
      let distance = body_length - 1 - i
      let weight = if distance % 2 == 0 { 3 } else { 1 }
      continue i - 1, acc + digit_at(value, i) * weight
    } nobreak {
      acc
    }
    (10 - sum % 10) % 10 == digit_at(value, value.length() - 1)
  }
}

///|
pub fn check_digit(value : String) -> Int? {
  if value.is_empty() || !is_all_digits(value) {
    None
  } else {
    let sum = for i = value.length() - 1, acc = 0; i >= 0; i = i - 1 {
      let distance = value.length() - 1 - i
      let weight = if distance % 2 == 0 { 3 } else { 1 }
      continue i - 1, acc + digit_at(value, i) * weight
    } nobreak {
      acc
    }
    Some((10 - sum % 10) % 10)
  }
}