///|
/// RTSP track selection uses the existing SDP parser rather than implementing another SDP language.
pub struct Track {
  index : Int32
  kind : String
  control : String
  formats : Array[String]
  rtpmap : Array[String]
  fmtp : Array[String]
}

///|
pub struct Description {
  aggregate : String
  tracks : Array[Track]
  raw : String
}

///|
pub fn describe(body : Bytes, base : String) -> Description raise RtspError {
  require(body.length() <= 1048576, "SDP limit")
  let raw = bytes_text(body)
  let document = match @sdp.parse(raw) {
    Ok(d) => d
    Err(_) => raise Invalid("SDP parse failed")
  }
  let mut aggregate = base
  for attr in document.attributes() {
    if attr.name() == "control" {
      if attr.value() is Some(v) {
        aggregate = resolve_control(base, v)
      }
    }
  }
  let tracks = []
  for media in document.media_descriptions() {
    require(tracks.length() < 16, "track count")
    let control = match media.attribute_value("control") {
      Some(v) => resolve_control(base, v)
      None => raise Invalid("track missing control")
    }
    let rtpmap = []
    let fmtp = []
    for a in media.attributes() {
      if a.value() is Some(v) {
        if a.name() == "rtpmap" {
          rtpmap.push(v)
        }
        if a.name() == "fmtp" {
          fmtp.push(v)
        }
      }
    }
    tracks.push({
      index: tracks.length(),
      kind: media.media(),
      control,
      formats: media.formats().copy(),
      rtpmap,
      fmtp,
    })
  }
  require(tracks.length() > 0, "no media tracks")
  { aggregate, tracks, raw, }
}

///|
pub fn Description::select(
  self : Description,
  indices : Array[Int32],
) -> Array[Track] raise RtspError {
  require(
    indices.length() > 0 && indices.length() <= self.tracks.length(),
    "track selection",
  )
  let selected = []
  let seen : Set[Int32] = Set([])
  for i in indices {
    require(
      i >= 0 && i < self.tracks.length() && !seen.contains(i),
      "track index",
    )
    seen.add(i)
    selected.push(self.tracks[i])
  }
  selected
}