<?php
namespace nur\sery\wip\schema\_assoc;

use nulib\ValueException;
use nur\sery\wip\schema\_scalar\ScalarResult;
use nur\sery\wip\schema\_scalar\ScalarWrapper;
use nur\sery\wip\schema\input\Input;
use nur\sery\wip\schema\Result;
use nur\sery\wip\schema\types\IType;
use nur\sery\wip\schema\Wrapper;

class AssocWrapper extends Wrapper {
  function __construct(AssocSchema $schema, &$array=null, $arrayKey=null, ?array $params=null) {
    $verifix = $params["verifix"] ?? true;
    $throw = $params["throw"] ?? null;
    if ($array !== null && $throw === null) {
      # Si $value est null, ne pas lancer d'exception, parce qu'on considère que
      # c'est une initialisation sans conséquences
      $throw = true;
    }
    $this->schema = $schema;
    $this->verifix = $verifix;
    $this->throw = $throw ?? false;
    $this->result = new AssocResult();
    $this->reset($array, $arrayKey);
    $this->throw = $throw ?? true;
  }

  function isAssoc(?AssocWrapper &$wrapper=null): bool { $wrapper = $this; return true; }

  protected bool $verifix;

  protected bool $throw;

  /** schéma de ce tableau */
  protected AssocSchema $schema;

  /** source et destination de la valeur */
  protected Input $input;

  /** @var string|int|null clé du tableau dans le tableau destination */
  protected $arrayKey;

  protected IType $arrayType;

  protected ScalarResult $arrayResult;

  /** @var IType[] */
  protected array $keyTypes;

  /** @var Result[] */
  protected array $keyResults;

  protected AssocResult $result;

  protected ?array $keys;

  protected ?array $wrappers;

  protected function newInput(&$value): Input {
    return new Input($value);
  }

  function reset(&$array, $arrayKey=null, ?bool $verifix=null): Wrapper {
    if ($array instanceof Input) $input = $array;
    else $input = $this->newInput($array);
    $this->input = $input;
    $this->arrayKey = $arrayKey;
    $this->analyze();
    if ($verifix ?? $this->verifix) $this->verifix();
    return $this;
  }

  function getKeys(): array {
    return $this->keys;
  }

  function select($key=null): ScalarWrapper {
    $wrapper = $this->wrappers[$key] ?? null;
    if ($key !== null) return $wrapper;
    throw ValueException::invalid_key($key);
  }

  /** @param Result[] $results */
  function verifix(?bool $throw=null, ?array &$results=null): bool {
  }


  function getResult(): AssocResult {
    return $this->result;
  }

  function isPresent(): bool {
    return $this->result->present;
  }

  function getType(): IType {
    return $this->arrayType;
  }

  function isAvailable(): bool {
    return $this->result->available;
  }

  function isValid(): bool {
    return $this->result->valid;
  }

  function isNormalized(): bool {
    return $this->result->normalized;
  }

  function get($default=null) {
    if ($this->result->available) return $this->input->get($this->arrayKey);
    else return $default;
  }

  function set($value, ?bool $verifix=null): AssocWrapper {
    $this->input->set($value, $this->arrayKey);
    $this->analyze();
    if ($verifix ?? $this->verifix) $this->verifix();
    return $this;
  }

  function unset(?bool $verifix=null): AssocWrapper {
    $this->input->unset($this->arrayKey);
    $this->analyze();
    if ($verifix ?? $this->verifix) $this->verifix();
    return $this;
  }

  function format($format = null): string {
    // TODO: Implement format() method.
  }

  function ensureKeys(): bool {
  }
  function orderKeys(): bool {
  }
}
