///|
pub fn flatten_parts(message : MailMessage) -> Array[MailPart] {
  let out : Array[MailPart] = []
  collect_parts(message.root, out)
  out
}

///|
fn collect_parts(part : MailPart, out : Array[MailPart]) -> Unit {
  out.push(part)
  for child in part.children {
    collect_parts(child, out)
  }
}

///|
pub fn text_parts(message : MailMessage) -> Array[MailPart] {
  let out : Array[MailPart] = []
  for part in flatten_parts(message) {
    if is_text(part) {
      out.push(part)
    }
  }
  out
}

///|
pub fn parts_by_media_type(
  message : MailMessage,
  media_type : String,
) -> Array[MailPart] {
  let out : Array[MailPart] = []
  let target = lower_ascii(media_type)
  for part in flatten_parts(message) {
    if part.content_type.media_type == target {
      out.push(part)
    }
  }
  out
}

///|
pub fn first_part_by_content_type(
  message : MailMessage,
  media_type : String,
  subtype : String,
) -> MailPart? {
  let mt = lower_ascii(media_type)
  let st = lower_ascii(subtype)
  for part in flatten_parts(message) {
    if part.content_type.media_type == mt && part.content_type.subtype == st {
      return Some(part)
    }
  }
  None
}

///|
pub fn max_depth(message : MailMessage) -> Int {
  part_depth(message.root)
}

///|
fn part_depth(part : MailPart) -> Int {
  let mut best = 1
  for child in part.children {
    let depth = 1 + part_depth(child)
    if depth > best {
      best = depth
    }
  }
  best
}