<?php
class FieldValidator
{
  /*
  * Private members
  */

  private string $name;
  private string $value;
  private string $type;
  private bool $required;
  private int $minLen;
  private int $maxLen;
  private string $error;

  /*
  * Constructor
  */

  public function __construct(string $name, string $value, string $type, bool $required = false, int $minLen = -1, int $maxLen = -1, string $error = "")
  {
    $this->name = $name;
    $this->value = $value;
    $this->type = $type;
    $this->required = $required;
    $this->minLen = $minLen;
    $this->maxLen = $maxLen;
    $this->error = $error;

    return $this;
  }

  /*
  * Fluent Style
  */

  public static function create(string $name, string $value, string $type)
  {
    return new FieldValidator($name, $value, $type);
  }

  public function isRequired()
  {
    $this->required = true;
    return $this;
  }

  public function withMinLen(int $minLen)
  {
    $this->minLen = $minLen;
    return $this;
  }

  public function withMaxLen(int $maxLen)
  {
    $this->maxLen = $maxLen;
    return $this;
  }

  /*
  * Getters and Setters
  */

  public function getError()
  {
    return $this->error;
  }

  public function getName()
  {
    return $this->name;
  }

  /*
  * Methods
  */

  public function isValid()
  {
    if ($this->required && empty($this->value)) {
      $this->error = "$this->name is required";
      return false;
    }

    if ($this->minLen >= 0 && !empty($this->value) && strlen($this->value) < $this->minLen) {
      $this->error = "$this->name requires $this->minLen characters, got " . strlen($this->value);
      return false;
    }

    if ($this->maxLen >= 0 && !empty($this->value) && strlen($this->value) > $this->maxLen) {
      $this->error = "$this->name allows $this->maxLen characters, got " . strlen($this->value);
      return false;
    }

    switch ($this->type) {
      case "email":
        if (!filter_var($this->value, FILTER_VALIDATE_EMAIL)) {
          $this->error = "Not a valid E-Mail";
          return false;
        }
        break;
      case "number":
        if (!filter_var($this->value, FILTER_VALIDATE_FLOAT) || !filter_var($this->value, FILTER_VALIDATE_INT)) {
          $this->error = "Not a valid number";
          return false;
        }
        break;
    }

    return true;
  }
}
