<?php
namespace nur\sery;

/**
 * Class ValueException: indiquer qu'une valeur est invalide
 */
class ValueException extends UserException {
  private static function value($value): string {
    if (is_object($value)) {
      return "<".get_class($value).">";
    } elseif (is_array($value)) {
      $values = $value;
      $parts = [];
      $index = 0;
      foreach ($values as $key => $value) {
        if ($key === $index) {
          $index++;
          $parts[] = self::value($value);
        } else {
          $parts[] = "$key=>".self::value($value);
        }
      }
      return "[" . implode(", ", $parts) . "]";
    } elseif (is_string($value)) {
      return $value;
    } else {
      return var_export($value, true);
    }
  }

  private static function message($value, ?string $message, ?string $kind, ?string $prefix, ?string $suffix): string {
    if ($kind === null) $kind = "value";
    if ($message === null) $message = "$kind$suffix";
    if ($value !== null) {
      $value = self::value($value);
      if ($prefix) $prefix = "$prefix: $value";
      else $prefix = $value;
    }
    if ($prefix) $prefix = "$prefix: ";
    return $prefix.$message;
  }

  static final function null(?string $kind=null, ?string $prefix=null, ?string $message=null): self {
    return new static(self::message(null, $message, $kind, $prefix, " should not be null"));
  }

  static final function invalid_kind($value=null, ?string $kind=null, ?string $prefix=null, ?string $message=null): self {
    return new static(self::message($value, $message, $kind, $prefix, " is invalid"));
  }

  static final function invalid_key($value, ?string $prefix=null, ?string $message=null): self {
    return self::invalid_kind($value, "key", $prefix, $message);
  }

  static final function invalid_value($value, ?string $prefix=null, ?string $message=null): self {
    return self::invalid_kind($value, "value", $prefix, $message);
  }

  static final function invalid_type($value, string $expected_type): self {
    return new static(self::message($value, null, "type", null, " is invalid, expected $expected_type"));
  }

  static final function invalid_class($class, string $expected_class): self {
    if (is_object($class)) $class = get_class($class);
    return new static(self::message($class, null, "class", null, " is invalid, expected $expected_class"));
  }

  static final function forbidden($value=null, ?string $kind=null, ?string $prefix=null, ?string $message=null): self {
    return new static(self::message($value, $message, $kind, $prefix, " is forbidden"));
  }
}
