<?php
namespace nulib\schema\_list;

use nulib\ref\schema\ref_schema;
use nulib\schema\Schema;
use nulib\schema\Wrapper;
use nulib\ValueException;

class ListSchema extends Schema {
  /** @var array meta-schema d'un schéma de nature liste */
  const METASCHEMA = ref_schema::LIST_METASCHEMA;

  /**
   * indiquer si $definition est une définition de schéma de nature liste que
   * {@link normalize()} pourrait normaliser
   */
  static function isa_definition($definition): bool {
    if (!is_array($definition)) return false;
    # nature explicitement spécifiée
    if (self::have_nature($definition, $nature)) {
      return $nature === "list";
    }
    # un unique élément tableau à l'index 0
    $count = count($definition);
    $haveIndex0 = array_key_exists(0, $definition);
    return $count == 1 && $haveIndex0 && is_array($definition[0]);
  }

  static function normalize($definition, $definitionKey=null): array {
    if (!is_array($definition)) $definition = [$definition];
    if (!self::have_nature($definition)) {
      $definition = [
        "?array",
        "" => "list",
        "schema" => $definition[0],
      ];
    }
    self::_normalize_definition($definition, $definitionKey);
    self::_ensure_nature($definition, "list", "array");
    return $definition;
  }

  function __construct($definition=null, $definitionKey=null, bool $normalize=true) {
    if ($definition === null) $definition = static::SCHEMA;
    if ($normalize) {
      $definition = self::normalize($definition, $definitionKey);
      $this->_definition = $definition;
      self::_ensure_type($definition);
      self::_ensure_schema_instances($definition);
    }
    $this->definition = $definition;
  }

  const KEYS = [null];

  function getKeys(): array {
    return self::KEYS;
  }

  public function getSchema($key=false): Schema {
    if ($key !== null) throw ValueException::invalid_key($key);
    return $this;
  }

  protected function newWrapper(): ListWrapper {
    return new ListWrapper($this);
  }

  function getWrapper(&$value=null, $valueKey=null, ?array $params = null, ?Wrapper &$wrapper=null): ListWrapper {
    # si pas de valeur ni de wrapper, pas de vérification et donc pas d'exception
    # cf le code similaire dans ScalarWrapper::__construct()
    $verifix = $value !== null || $wrapper !== null;
    if (!($wrapper instanceof ListWrapper)) $wrapper = $this->newWrapper();
    return $wrapper->reset($value, $valueKey, $verifix);
  }
}
