<?php
namespace nur\ldap;

use nur\b\UserException;

class LdapException extends UserException {
  /** @param $r ?resource */
  static function check(string $message, $r, $value, ?int $allow_errno=null) {
    if ($value !== false) return $value;
    if ($r !== null) {
      $errno = ldap_errno($r);
      if ($allow_errno !== null && $errno === $allow_errno) return $value;
      throw new self($message, $errno, null, ldap_error($r));
    } else {
      throw new self($message);
    }
  }

  static function check_result(string $message, $conn, $r) {
    ldap_parse_result($conn, $r, $errorCode, $matchedDn, $errorMessage, $referrals, $controls);
    if ($errorCode != 0) {
      if (!$errorMessage) $errorMessage = ldap_err2str($errorCode);
      throw new LdapException($message, $errorCode, $matchedDn, $errorMessage, $referrals, $controls);
    }
  }

  function __construct(string $userMessage
    , ?int $errorCode=null, ?string $matchedDn=null, ?string $errorMessage=null
    , ?array $referrals=null, ?array $controls=null) {
    if ($errorCode == 0) {
      parent::__construct($userMessage);
    } else {
      $this->matchedDn = $matchedDn;
      $this->errorMessage = $errorMessage;
      $this->referrals = $referrals;
      $this->controls = $controls;
      $parts = ["error $errorCode"];
      if ($errorMessage) $parts[] = $errorMessage;
      if ($matchedDn) $parts[] = "matched_dn: $matchedDn";
      if ($referrals) $parts[] = "referrals: ".implode(" ", $referrals);
      $techMessage = implode(", ", $parts);
      parent::__construct([
        "user" => $userMessage,
        "tech" => $techMessage,
      ], $errorCode);
    }
  }

  /** @var string */
  protected $matchedDn;

  function getMatchedDn(): ?string {
    return $this->matchedDn;
  }

  /** @var string */
  protected $errorMessage;

  function getErrorMessage(): ?string {
    return $this->errorMessage;
  }

  /** @var ?array */
  protected $referrals;

  function getReferrals(): ?array {
    return $this->referrals;
  }

  /** @var ?array */
  protected $controls;

  function getControls(): ?array {
    return $this->controls;
  }
}