///|
/// Boundary generation for multipart messages (RFC 2046 section 5.1.1).
/// The boundary is derived from a caller-supplied seed so that rendering is
/// deterministic and reproducible in tests.
pub fn generate_boundary(seed : String) -> String {
  let digest = bytes_to_hex(string_to_bytes(seed))
  "=_moonmail_" + digest
}

///|
/// Characters permitted inside a boundary value: `[0-9a-zA-Z'()+_,-./:=?]`
/// (MM_MIME_003, RFC 2046).
pub fn is_valid_boundary(boundary : String) -> Bool {
  if boundary.is_empty() || boundary.length() > 70 {
    return false
  }
  for ch in boundary {
    let c = ch.to_int()
    let ok = (c >= 0x30 && c <= 0x39) ||
      (c >= 0x41 && c <= 0x5A) ||
      (c >= 0x61 && c <= 0x7A) ||
      c == 0x27 ||
      c == 0x28 ||
      c == 0x29 ||
      c == 0x2B ||
      c == 0x2C ||
      c == 0x2D ||
      c == 0x2E ||
      c == 0x2F ||
      c == 0x3A ||
      c == 0x3D ||
      c == 0x3F ||
      c == 0x5F
    if !ok {
      return false
    }
  }
  true
}

///|
/// Check that `boundary` does not occur anywhere inside `body` (MM_MIME_002).
/// A boundary line is `--boundary` at the start of a line; to be safe we
/// search for `--boundary` anywhere in the body.
pub fn boundary_collides(boundary : String, body : String) -> Bool {
  body.contains("--" + boundary)
}

///|
/// Generate a boundary that is valid and does not collide with `body`.
/// The seed can be reused: a counter is appended until no collision occurs.
pub fn unique_boundary(seed : String, body : String) -> String {
  let mut counter = 0
  let mut boundary = generate_boundary(seed)
  while boundary_collides(boundary, body) {
    counter += 1
    boundary = generate_boundary(seed + "#\{counter}")
  }
  boundary
}