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

use nulib\ValueException;
use nur\sery\wip\schema\input\Input;
use nur\sery\wip\schema\Result;
use nur\sery\wip\schema\Schema;

/**
 * Interface IType: un type de données
 */
interface IType {
  /**
   * obtenir, pour information, le nom officiel de ce type, utilisable dans une
   * définition de schéma
   */
  function getName(): string;

  /** obtenir la liste des aliases valides pour ce type */
  function getAliases(): array;

  /**
   * @return string la classe des objets gérés par ce format: le type attendu
   * par {@link format()} et le type retourné par {@link verifix()}
   *
   * Les valeurs "mixed", "bool", "float", "int", "string" et "array" peuvent
   * aussi être retournées, bien qu'elles ne soient pas à proprement parler des
   * classes.
   *
   * La valeur "mixed" signifie qu'il peut s'agir de n'importe quelle classe
   * et/ou que la valeur ne peut pas être déterminée à l'avance.
   */
  function getClass(): string;

  /**
   * comme {@link getClass()} mais peut être utilisé directement comme type dans
   * une déclaration PHP. notamment, si le type est nullable et que
   * $allowNullable==true, il y a "?" devant le nom.
   *
   * Par exemple:
   * - pour un type chaine nullable, {@link getClass()} retournerait "string"
   * alors que cette méthode retournerait "?string".
   * - pour un type mixed, {@link getClass()} retournerait "mixed" alors que
   * cette méthode retournerait null
   */
  function getPhpType(bool $allowNullable=true): ?string;

  /**
   * indiquer si c'est le type d'une valeur qui ne peut prendre que 2 états: une
   * "vraie" et une "fausse"
   */
  function is2States(): bool;

  /**
   * Si {@link is2States()} est vrai, retourner les deux valeurs [faux, vrai]
   */
  function get2States(): array;

  /**
   * indiquer si c'est le type d'une valeur qui ne peut prendre que 3 états: une
   * "vraie", une "fausse", et une "indéterminée"
   */
  function is3States(): bool;

  /**
   * Si {@link is3States()} est vrai, retourner les 3 valeurs [faux, vrai, undef]
   */
  function get3States(): array;

  /** la donnée $input($valueKey) est-elle disponible? */
  function isAvailable(Input $input, $valueKey): bool;

  /** la valeur $value est-elle nulle? */
  function isNull($value): bool;

  /**
   * la valeur $value est-elle valide et normalisée le cas échéant?
   *
   * NB: si $value est un string. elle doit avoir déjà été traitée au préalable
   * par extract() et parse()
   */
  function isValid($value, ?bool &$normalized=null): bool;

  /**
   * extraire de la chaine la valeur à analyser
   *
   * @throws ValueException en cas d'erreur d'analyse
   */
  function extract(string $value): string;

  /**
   * analyser la chaine et retourner la valeur "convertie"
   *
   * @throws ValueException en cas d'erreur d'analyse
   */
  function parse(string $value);

  /**
   * analyser, corriger éventuellement et normaliser la valeur
   *
   * NB: si $value est un string. elle doit avoir déjà été traitée au préalable
   * par extract() et parse()
   *
   * si la valeur était déjà normalisée, ou si une erreur s'est produite,
   * retourner false.
   */
  function verifix(&$value, Result $result, Schema $schema): bool;

  /**
   * formatter la valeur pour affichage. si $value n'est pas null, elle est
   * garantie d'être du bon type
   */
  function format($value, $format=null): string;

  #############################################################################

  /** @return string le nom d'un getter pour une valeur de ce type */
  function getGetterName(string $name): string;

  /** @return string le nom d'un setter pour une valeur de ce type */
  function getSetterName(string $name): string;

  /** @return string le nom d'un deleter pour une valeur de ce type */
  function getDeleterName(string $name): string;

  /**
   * @return string le nom d'une constante de classe pour une valeur de ce type
   */
  function getClassConstName(string $name): string;

  /**
   * @return string le nom d'une propriété d'une classe pour une valeur de ce
   * type
   */
  function getObjectPropertyName(string $name): string;

  /** @return string le nom d'une clé d'un tableau pour une valeur de ce type */
  function getArrayKeyName(string $name): string;
}
