///|
/// Parsed Accept-Ranges field. `NoneAccepted` is the reserved `none` value.
pub(all) enum AcceptRanges {
  NoneAccepted
  Units(Array[String])
} derive(Eq, Debug)

///|
pub fn parse_accept_ranges(input : String) -> Result[AcceptRanges, RangeError] {
  parse_accept_ranges_with_limits(input, Limits::default())
}

///|
pub fn parse_accept_ranges_with_limits(
  input : String,
  limits : Limits,
) -> Result[AcceptRanges, RangeError] {
  if utf8_length(input) > limits.max_input_bytes() {
    return Err(
      range_error(
        Limit,
        LimitExceeded,
        0,
        "Accept-Ranges exceeds max_input_bytes",
      ),
    )
  }
  let trimmed = trim_ows(input)
  if trimmed.length() == 0 {
    return Err(
      range_error(AcceptRanges, EmptyInput, 0, "Accept-Ranges is empty"),
    )
  }
  if ascii_equal(trimmed, "none") {
    return Ok(NoneAccepted)
  }
  let units : Array[String] = []
  let mut start = 0
  for i = 0; i <= trimmed.length(); i = i + 1 {
    if i == trimmed.length() || trimmed[i] == ','.to_int().to_uint16() {
      let value = trim_ows(trimmed[start:i].to_owned())
      if value.length() == 0 {
        return Err(
          range_error(
            AcceptRanges,
            InvalidUnit,
            start,
            "empty Accept-Ranges unit",
          ),
        )
      }
      if utf8_length(value) > limits.max_unit_bytes() {
        return Err(
          range_error(
            Limit,
            LimitExceeded,
            start,
            "Accept-Ranges unit exceeds limit",
          ),
        )
      }
      for c in value {
        if !is_tchar(c) {
          return Err(
            range_error(
              AcceptRanges,
              InvalidUnit,
              start,
              "invalid Accept-Ranges unit",
            ),
          )
        }
      }
      if ascii_equal(value, "none") {
        return Err(
          range_error(
            AcceptRanges,
            InvalidUnit,
            start,
            "none cannot be combined with range units",
          ),
        )
      }
      units.push(ascii_lower(value))
      start = i + 1
    }
  }
  Ok(Units(units))
}

///|
pub fn AcceptRanges::supports(self : AcceptRanges, unit : String) -> Bool {
  match self {
    NoneAccepted => false
    Units(units) => {
      for value in units {
        if ascii_equal(value, unit) {
          return true
        }
      }
      false
    }
  }
}

///|
pub fn AcceptRanges::supports_bytes(self : AcceptRanges) -> Bool {
  self.supports("bytes")
}

///|
pub fn AcceptRanges::units(self : AcceptRanges) -> Array[String] {
  match self {
    NoneAccepted => []
    Units(units) => units.copy()
  }
}

///|
pub fn serialize_accept_ranges(value : AcceptRanges) -> String {
  match value {
    NoneAccepted => "none"
    Units(units) => join_strings(units, ", ")
  }
}