///|
/// A decoded BER length octet(s) (X.690 8.1.3).
pub(all) enum BerLength {
  Definite(Int)
  Indefinite
} derive(Eq, @debug.Debug)

///|
/// Encode a definite length. Short form is used for `len < 128`, long form
/// otherwise (X.690 8.1.3.4 / 8.1.3.5). Encoding is always definite.
pub fn encode_length(len : Int) -> Bytes {
  if len < 128 {
    Bytes::from_array([len.to_byte()])
  } else {
    let acc : Array[Byte] = []
    let mut remaining = len
    while remaining > 0 {
      acc.push((remaining & 0xFF).to_byte())
      remaining = remaining >> 8
    }
    let out = reverse_array(acc)
    let head = (out.length() | 0x80).to_byte()
    Bytes::from_array([head]) + Bytes::from_array(out)
  }
}

///|
/// Encode the identifier octets for a tag, including the long form when the
/// tag number is 31 or greater (X.690 8.1.2.4).
pub fn encode_identifier(tag : BerTag) -> Bytes {
  let first = tag.first_octet()
  if tag.number < 31 {
    Bytes::from_array([first.to_byte()])
  } else {
    let acc : Array[Byte] = []
    let mut remaining = tag.number
    while remaining > 0 {
      acc.push((remaining & 0x7F).to_byte())
      remaining = remaining >> 7
    }
    let out = reverse_array(acc)
    for i in 0..<(out.length() - 1) {
      out[i] = (out[i].to_int() | 0x80).to_byte()
    }
    Bytes::from_array([first.to_byte()]) + Bytes::from_array(out)
  }
}

///|
/// Encode a full TLV (tag + length + content).
pub fn encode_tlv(tag : BerTag, content : Bytes) -> Bytes {
  encode_identifier(tag) + encode_length(content.length()) + content
}