///|
/// The paged results control OID (RFC 2696).
pub const PAGED_RESULTS_OID : String = "1.2.840.113556.1.4.319"

///|
/// RealSearchControlValue ::= SEQUENCE { size INTEGER, cookie OCTET STRING }
/// for a paged results *request* control value (RFC 2696).
pub fn paged_results_request_value(size : Int, cookie : Bytes) -> Bytes {
  encode_sequence([encode_integer(size), encode_octet_string(cookie)])
}

///|
/// The paged results *response* control value: an estimated total size plus
/// the server-issued continuation cookie.
pub fn paged_results_response_value(total_size : Int, cookie : Bytes) -> Bytes {
  encode_sequence([encode_integer(total_size), encode_octet_string(cookie)])
}

///|
pub struct PagedResultsResponse {
  total_size : Int
  cookie : Bytes
} derive(Eq, @debug.Debug)

///|
pub fn PagedResultsResponse::new(total_size : Int, cookie : Bytes) -> Self {
  { total_size, cookie }
}

///|
/// Build the paged results request control with the given page size and
/// cookie (empty cookie starts the enumeration).
pub fn paged_results_control(size : Int, cookie : Bytes) -> Control {
  Control::new(
    PAGED_RESULTS_OID,
    false,
    paged_results_request_value(size, cookie),
  )
}

///|
fn parse_paged_value(value : Bytes) -> PagedResultsResponse? {
  let decoded = match decode_ber(value, None) {
    Ok(v) => v
    Err(_) => return None
  }
  if !decoded.is_constructed() {
    return None
  }
  let kids = decoded.children_or_empty()
  if kids.length() != 2 {
    return None
  }
  let total_size = match parse_integer(kids[0].content, 8) {
    Ok(v) => v
    Err(_) => return None
  }
  Some(PagedResultsResponse::new(total_size, kids[1].content))
}

///|
/// Extract the paged results response control from a response's controls,
/// returning `None` when absent or malformed.
pub fn parse_paged_results_response(
  controls : Array[Control]?,
) -> PagedResultsResponse? {
  match controls {
    Some(list) =>
      for ctrl in list {
        if ctrl.control_type == PAGED_RESULTS_OID {
          return parse_paged_value(ctrl.control_value)
        }
      }
    None => ()
  }
  None
}