<?php
namespace nulib\schema\types;

use nulib\cl;
use nulib\schema\_scalar\ScalarSchema;
use nulib\schema\Result;
use nulib\schema\Schema;
use nulib\str;

class tarray extends _tstring {
  const NAME = "array";

  const TRIM = true;
  const NORM_NL = true;

  const SEP_MAP = [
    "space" => "spaces",
    "lines" => "line",
  ];
  const STD_SEPS = [
    "spaces" => [" ", '/\s+/', true],
    "line" => ["\n", "\n", false],
  ];

  const DEFAULT_SEP = self::STD_SEPS["spaces"];
  const DEFAULT_PARSE_SEP = self::DEFAULT_SEP[1];
  const DEFAULT_FORMAT_SEP = self::DEFAULT_SEP[0];

  public static function get_params_from_definition(?array $definition): ?array {
    $params = parent::get_params_from_definition($definition);
    $sep = $definition["sep"] ?? null;
    if ($sep !== null) {
      if (!is_array($sep)) {
        $sep = cl::get(self::SEP_MAP, $sep, $sep);
        $sep = self::STD_SEPS[$sep] ?? [$sep, $sep, false];
      }
      $params["parse_sep"] = $sep[1] ?? $sep[0];
      $params["format_sep"] = $sep[0];
      $params["trim"] ??= $sep[2] ?? static::TRIM;
      $params["norm_nl"] ??= $sep[3] ?? static::NORM_NL;
    } else {
      $parseSep = $definition["parse_sep"] ?? null;
      if ($parseSep !== null) $params["parse_sep"] = $parseSep;
      $formatSep = $definition["format_sep"] ?? null;
      if ($formatSep !== null) $params["format_sep"] = $formatSep;
    }
    return $params;
  }

  function getClass(): string {
    return "array";
  }

  function getNullValue() {
    return $this->nullable? null: [];
  }

  function isValid($value, ?bool &$normalized=null): bool {
    $normalized = is_array($value);
    return $normalized || is_scalar($value);
  }

  function parse(string $value) {
    $sep = $this->params["parse_sep"] ?? static::DEFAULT_PARSE_SEP;
    if ($sep !== false) $value = str::split($sep, $value);
    return $value;
  }

  /**
   * @var ScalarSchema $schema
   */
  function normalize(&$value, Result $result, Schema $schema): bool {
    if ($result->normalized) {
    } elseif (is_array($value)) {
      $result->setNormalized();
    } elseif (is_scalar($value)) {
      $value = cl::with($value);
      return true;
    }
    return false;
  }

  function format($value, $format=null): string {
    if ($value === null) return "";
    $format ??= $this->params["format"] ?? static::DEFAULT_FORMAT_SEP;
    return implode($format, $value);
  }
}
