// HTTP Range 区间下载(RFC 7233)的公共类型:请求侧的 `ByteRange`
// 与响应侧的 `Content-Range` 解析。断点续传(client 包)建立在两者之上。

///|
/// HTTP 字节区间(RFC 7233):字节从 0 计,`end` 为**含端**。
/// 只能经 `ByteRange::from` / `ByteRange::suffix` 构造,保证取值合法:
/// 后缀形式(取资源末尾 N 字节)以负数 `start = -N` 存储。
pub struct ByteRange {
  /// 起始字节;后缀形式时为负数 `-N`(`N` 为要取的末尾字节数)
  start : Int32
  /// 结束字节(含);`None` 表示一直到资源末尾(`bytes=N-`)
  end : Int32?
}

///|
/// 区间下载:`start` 缺省 0;`end` 省略表示到资源末尾(`bytes=start-`),
/// 提供则是闭区间(`bytes=start-end`,两端都含)。
pub fn ByteRange::from(start? : Int32, end? : Int32) -> ByteRange {
  { start: start.unwrap_or(0), end, }
}

///|
/// 后缀区间:取资源**末尾** `length` 个字节(`bytes=-length`),
/// `length` 应为正数。
pub fn ByteRange::suffix(length : Int32) -> ByteRange {
  { start: -length, end: None, }
}

///|
/// 渲染成 `Range` 请求头的值:`bytes=start-end` / `bytes=start-` /
/// `bytes=-length`(后缀形式)。
pub fn ByteRange::header_value(self : ByteRange) -> String {
  let start = self.start
  if start < 0 {
    "bytes=\{start}"
  } else {
    match self.end {
      Some(end) => "bytes=\{start}-\{end}"
      None => "bytes=\{start}-"
    }
  }
}

///|
/// 206(部分内容)响应 `Content-Range` 头的解析结果:
/// `bytes first-last/total`,描述服务器实际返回的区间。
pub(all) struct ContentRange {
  /// 区间起始字节(含)
  first : Int32
  /// 区间结束字节(含)
  last : Int32
  /// 资源总字节数;服务器未知时(`bytes a-b/*`)为 `None`
  total : Int32?
}

///|
/// 解析 206 响应的 `Content-Range` 头。RFC 写法为 `bytes 0-1/2`(空格),
/// 部分实现写 `bytes=0-1/2`(等号),均容忍;形态不符 / 数字非法
/// 返回 `None`(`bytes */total` 形态属于 416 响应,用
/// `parse_unsatisfied_range_total` 解析)。
pub fn parse_content_range(text : String) -> ContentRange? {
  let body = strip_range_unit(text.trim().to_owned())
  match body.find("/") {
    Some(slash) => {
      let range_part = body[:slash].to_owned()
      let total_text = body[slash + 1:].to_owned()
      match range_part.find("-") {
        Some(dash) =>
          match
            (
              parse_ascii_int(range_part[:dash].to_owned().trim().to_owned()),
              parse_ascii_int(
                range_part[dash + 1:].to_owned().trim().to_owned(),
              ),
            ) {
            (Some(first), Some(last)) =>
              match parse_range_total(total_text) {
                Some(total) => Some({ first, last, total, })
                None => None
              }
            _ => None
          }
        None => None
      }
    }
    None => None
  }
}

///|
/// 解析 416 响应的 `Content-Range: bytes */total`(服务器告知资源总长)。
/// 形态不符时返回 `None`。
pub fn parse_unsatisfied_range_total(text : String) -> Int32? {
  let body = strip_range_unit(text.trim().to_owned())
  match body.find("/") {
    Some(slash) => {
      let left = body[:slash].to_owned().trim()
      let total = parse_ascii_int(body[slash + 1:].to_owned().trim().to_owned())
      if left == "*" {
        total
      } else {
        None
      }
    }
    None => None
  }
}

///|
/// 去掉 `Content-Range` 的单位前缀:`bytes=…` 与 `bytes …` 两种写法
/// 均剥成 `…`;无前缀原样返回。
fn strip_range_unit(text : String) -> String {
  if text.has_prefix("bytes") {
    let rest = text[5:].to_owned()
    if rest.has_prefix("=") || rest.has_prefix(" ") {
      rest[1:].to_owned()
    } else {
      rest
    }
  } else {
    text
  }
}

///|
/// 解析 `Content-Range` 的总长段:`*` 视为「服务器未知」(成功,
/// 结果为 `None`),纯数字为已知总长,其余非法(返回 `None`)。
fn parse_range_total(text : String) -> Int32?? {
  let trimmed = text.trim().to_owned()
  if trimmed == "*" {
    Some(None)
  } else {
    match parse_ascii_int(trimmed) {
      Some(total) => Some(Some(total))
      None => None
    }
  }
}