///|
/// One attribute inside a relative distinguished name.
pub struct AttributeTypeAndValue {
  oid : @asn1.ObjectIdentifier
  value : String
}

///|
/// A relative distinguished name: a set of attributes that must all hold.
pub struct RelativeDistinguishedName {
  attributes : Array[AttributeTypeAndValue]
}

///|
/// An X.501 name as it appears in a certificate: a sequence of RDNs.
pub struct Name {
  rdns : Array[RelativeDistinguishedName]
}

///|
/// Whether the name has no components.
pub fn Name::is_empty(self : Name) -> Bool {
  self.rdns.is_empty()
}

///|
/// Renders the name in the RFC 4514 form, for example
/// `CN=example.com,O=Acme,C=CN`.
///
/// RFC 4514 prints the components in the reverse of their DER order, so the
/// most specific attribute comes first.
pub fn Name::to_string(self : Name) -> String {
  let buffer = StringBuilder()
  let count = self.rdns.length()
  for i in 0.. 0 {
      buffer.write_string(",")
    }
    let rdn = self.rdns[count - 1 - i]
    let mut first = true
    for attribute in rdn.attributes {
      if !first {
        buffer.write_string("+")
      }
      first = false
      buffer.write_string(attribute_display_name(attribute.oid))
      buffer.write_string("=")
      buffer.write_string(attribute.value)
    }
  }
  buffer.to_string()
}

///|
/// Returns the value of the first attribute with the given short name, for
/// example `"CN"`.
pub fn Name::find(self : Name, short_name : String) -> String? {
  for rdn in self.rdns {
    for attribute in rdn.attributes {
      if attribute_short_name(attribute.oid) == Some(short_name) {
        return Some(attribute.value)
      }
    }
  }
  None
}