///|
/// LDAP result codes. Codes 0-80 come from RFC 4511 A.10; codes 81+ are the
/// conventional client-side extensions (matching `ldap.h`).
pub(all) enum ResultCode {
  Success
  OperationsError
  ProtocolError
  TimeLimitExceeded
  SizeLimitExceeded
  CompareFalse
  CompareTrue
  AuthMethodNotSupported
  StrongerAuthRequired
  Referral
  AdminLimitExceeded
  UnavailableCriticalExtension
  ConfidentialityRequired
  SaslBindInProgress
  NoSuchAttribute
  UndefinedAttributeType
  InappropriateMatching
  ConstraintViolation
  AttributeOrValueExists
  InvalidAttributeSyntax
  NoSuchObject
  AliasProblem
  InvalidDNSyntax
  AliasDereferencingProblem
  InappropriateAuthentication
  InvalidCredentials
  InsufficientAccessRights
  Busy
  Unavailable
  UnwillingToPerform
  LoopDetect
  NamingViolation
  ObjectClassViolation
  NotAllowedOnNonLeaf
  NotAllowedOnRDN
  EntryAlreadyExists
  ObjectClassModsProhibited
  AffectsMultipleDSAs
  Other
  ServerDown
  LocalError
  EncodingError
  DecodingError
  Timeout
  AuthUnknown
  FilterError
  UserCanceled
  ParameterError
  NoMemory
  ConnectError
  NotSupported
  ControlNotFound
  NoResultsReturned
  MoreResultsToReturn
  ClientLoop
  ReferralLimitExceeded
  Unknown(Int)
} derive(Eq, @debug.Debug)

///|
pub fn ResultCode::from_int(code : Int) -> ResultCode {
  match code {
    0 => Success
    1 => OperationsError
    2 => ProtocolError
    3 => TimeLimitExceeded
    4 => SizeLimitExceeded
    5 => CompareFalse
    6 => CompareTrue
    7 => AuthMethodNotSupported
    8 => StrongerAuthRequired
    10 => Referral
    11 => AdminLimitExceeded
    12 => UnavailableCriticalExtension
    13 => ConfidentialityRequired
    14 => SaslBindInProgress
    16 => NoSuchAttribute
    17 => UndefinedAttributeType
    18 => InappropriateMatching
    19 => ConstraintViolation
    20 => AttributeOrValueExists
    21 => InvalidAttributeSyntax
    32 => NoSuchObject
    33 => AliasProblem
    34 => InvalidDNSyntax
    36 => AliasDereferencingProblem
    48 => InappropriateAuthentication
    49 => InvalidCredentials
    50 => InsufficientAccessRights
    51 => Busy
    52 => Unavailable
    53 => UnwillingToPerform
    54 => LoopDetect
    64 => NamingViolation
    65 => ObjectClassViolation
    66 => NotAllowedOnNonLeaf
    67 => NotAllowedOnRDN
    68 => EntryAlreadyExists
    69 => ObjectClassModsProhibited
    71 => AffectsMultipleDSAs
    80 => Other
    81 => ServerDown
    82 => LocalError
    83 => EncodingError
    84 => DecodingError
    85 => Timeout
    86 => AuthUnknown
    87 => FilterError
    88 => UserCanceled
    89 => ParameterError
    90 => NoMemory
    91 => ConnectError
    92 => NotSupported
    93 => ControlNotFound
    94 => NoResultsReturned
    95 => MoreResultsToReturn
    96 => ClientLoop
    97 => ReferralLimitExceeded
    _ => Unknown(code)
  }
}

///|
pub fn ResultCode::to_int(self : ResultCode) -> Int {
  match self {
    Success => 0
    OperationsError => 1
    ProtocolError => 2
    TimeLimitExceeded => 3
    SizeLimitExceeded => 4
    CompareFalse => 5
    CompareTrue => 6
    AuthMethodNotSupported => 7
    StrongerAuthRequired => 8
    Referral => 10
    AdminLimitExceeded => 11
    UnavailableCriticalExtension => 12
    ConfidentialityRequired => 13
    SaslBindInProgress => 14
    NoSuchAttribute => 16
    UndefinedAttributeType => 17
    InappropriateMatching => 18
    ConstraintViolation => 19
    AttributeOrValueExists => 20
    InvalidAttributeSyntax => 21
    NoSuchObject => 32
    AliasProblem => 33
    InvalidDNSyntax => 34
    AliasDereferencingProblem => 36
    InappropriateAuthentication => 48
    InvalidCredentials => 49
    InsufficientAccessRights => 50
    Busy => 51
    Unavailable => 52
    UnwillingToPerform => 53
    LoopDetect => 54
    NamingViolation => 64
    ObjectClassViolation => 65
    NotAllowedOnNonLeaf => 66
    NotAllowedOnRDN => 67
    EntryAlreadyExists => 68
    ObjectClassModsProhibited => 69
    AffectsMultipleDSAs => 71
    Other => 80
    ServerDown => 81
    LocalError => 82
    EncodingError => 83
    DecodingError => 84
    Timeout => 85
    AuthUnknown => 86
    FilterError => 87
    UserCanceled => 88
    ParameterError => 89
    NoMemory => 90
    ConnectError => 91
    NotSupported => 92
    ControlNotFound => 93
    NoResultsReturned => 94
    MoreResultsToReturn => 95
    ClientLoop => 96
    ReferralLimitExceeded => 97
    Unknown(code) => code
  }
}

///|
pub fn ResultCode::to_string(self : ResultCode) -> String {
  match self {
    Success => "success"
    OperationsError => "operationsError"
    ProtocolError => "protocolError"
    TimeLimitExceeded => "timeLimitExceeded"
    SizeLimitExceeded => "sizeLimitExceeded"
    CompareFalse => "compareFalse"
    CompareTrue => "compareTrue"
    AuthMethodNotSupported => "authMethodNotSupported"
    StrongerAuthRequired => "strongerAuthRequired"
    Referral => "referral"
    AdminLimitExceeded => "adminLimitExceeded"
    UnavailableCriticalExtension => "unavailableCriticalExtension"
    ConfidentialityRequired => "confidentialityRequired"
    SaslBindInProgress => "saslBindInProgress"
    NoSuchAttribute => "noSuchAttribute"
    UndefinedAttributeType => "undefinedAttributeType"
    InappropriateMatching => "inappropriateMatching"
    ConstraintViolation => "constraintViolation"
    AttributeOrValueExists => "attributeOrValueExists"
    InvalidAttributeSyntax => "invalidAttributeSyntax"
    NoSuchObject => "noSuchObject"
    AliasProblem => "aliasProblem"
    InvalidDNSyntax => "invalidDNSyntax"
    AliasDereferencingProblem => "aliasDereferencingProblem"
    InappropriateAuthentication => "inappropriateAuthentication"
    InvalidCredentials => "invalidCredentials"
    InsufficientAccessRights => "insufficientAccessRights"
    Busy => "busy"
    Unavailable => "unavailable"
    UnwillingToPerform => "unwillingToPerform"
    LoopDetect => "loopDetect"
    NamingViolation => "namingViolation"
    ObjectClassViolation => "objectClassViolation"
    NotAllowedOnNonLeaf => "notAllowedOnNonLeaf"
    NotAllowedOnRDN => "notAllowedOnRDN"
    EntryAlreadyExists => "entryAlreadyExists"
    ObjectClassModsProhibited => "objectClassModsProhibited"
    AffectsMultipleDSAs => "affectsMultipleDSAs"
    Other => "other"
    ServerDown => "serverDown"
    LocalError => "localError"
    EncodingError => "encodingError"
    DecodingError => "decodingError"
    Timeout => "timeout"
    AuthUnknown => "authUnknown"
    FilterError => "filterError"
    UserCanceled => "userCanceled"
    ParameterError => "parameterError"
    NoMemory => "noMemory"
    ConnectError => "connectError"
    NotSupported => "notSupported"
    ControlNotFound => "controlNotFound"
    NoResultsReturned => "noResultsReturned"
    MoreResultsToReturn => "moreResultsToReturn"
    ClientLoop => "clientLoop"
    ReferralLimitExceeded => "referralLimitExceeded"
    Unknown(code) => "unknown(\{code})"
  }
}

///|
pub fn ResultCode::is_success(self : ResultCode) -> Bool {
  match self {
    Success => true
    _ => false
  }
}

///|
pub fn ResultCode::is_referral(self : ResultCode) -> Bool {
  match self {
    Referral => true
    _ => false
  }
}

///|
pub struct LdapResult {
  result_code : ResultCode
  matched_dn : String
  diagnostic_message : String
  referral : Array[String]?
} derive(Eq, @debug.Debug)

///|
pub fn LdapResult::success() -> LdapResult {
  {
    result_code: Success,
    matched_dn: "",
    diagnostic_message: "",
    referral: None,
  }
}

///|
pub fn LdapResult::failure(
  code : ResultCode,
  diagnostic : String,
) -> LdapResult {
  {
    result_code: code,
    matched_dn: "",
    diagnostic_message: diagnostic,
    referral: None,
  }
}

///|
pub fn LdapResult::is_success(self : LdapResult) -> Bool {
  self.result_code.is_success()
}