<?php
namespace nur\ldap\syntaxes;

use nur\A;
use nur\b\ValueException;
use nur\ldap\CompositeAttr;
use nur\ldap\CompositeValue;

class CompositeSyntax extends AbstractSyntax {
  /**
   * @var string la classe dérivée de {@link CompositeAttr} qui porte l'attribut
   */
  const CACLASS = CompositeAttr::class;

  function getAttrClass(): string {
    return static::CACLASS;
  }

  function newAttr(string $name, ?array &$values, ?int $flags): CompositeAttr {
    $attrClass = $this->getAttrClass();
    return new $attrClass($name, $values, $this, $flags);
  }

  /**
   * @var string la classe dérivée de {@link CompositeValue} qui porte les
   * valeurs de cette syntaxe
   */
  const CVCLASS = CompositeValue::class;

  /** retourner la classe d'une valeur composite */
  function getPhpType(): ?string {
    return static::CVCLASS;
  }

  protected function newCompositeValue(): CompositeValue {
    $class = $this->getPhpType();
    /** @var CompositeValue $cvalue */
    $cvalue = new $class;
    return $cvalue->setup($this->conn);
  }

  function ensureArray($values): ?array {
    A::ensure_narray($values);
    if ($values === null) return null;
    # déterminer si $values est *une* valeur ou une liste de valeurs
    $list = false;
    foreach ($values as $value) {
      if (is_array($value) || $value instanceof CompositeValue) {
        $list = true;
        break;
      }
    }
    if (!$list) $values = [$values];
    return $values;
  }

  function ensureComposite($value): ?CompositeValue {
    if ($value === null) return null;
    if (is_array($value)) {
      $value = $this->newCompositeValue()->reset($value);
    }
    ValueException::check_class($value, $this->getPhpType());
    return $value;
  }

  /** @param ?CompositeValue $value */
  function php2ldap($value): ?string {
    $cvalue = $this->ensureComposite($value);
    if ($cvalue === null) return null;
    else return $cvalue->formatLdap();
  }

  function ldap2php(string $value): CompositeValue {
    return $this->newCompositeValue()->parseLdap($value);
  }

  function fromMultivaluedLdap($values): ?array {
    A::ensure_narray($values);
    if ($values !== null) {
      $tmp = [];
      foreach ($values as $value) {
        $value = $this->ldap2php($value);
        $key = $value->getKey();
        $tmp[$key] = $value;
      }
      $values = $tmp;
    }
    return A::filter_n($values)?: null;
  }

  function fromPhp($values): ?array {
    $values = $this->ensureArray($values);
    return parent::fromPhp($values);
  }
}
