<?php
namespace nur\b\io;

use nur\b\coll\AbstractIterator;
use nur\str;

class StringReader extends AbstractIterator implements IReader {
  use Treader;

  static final function next_line(string $string, int $index, ?int $length=null): ?array {
    if ($length === null) $length = strlen($string);
    $poscr = strpos($string, "\r", $index);
    $poslf = strpos($string, "\n", $index);
    if ($poscr !== false && $poslf !== false) {
      $pos = min($poscr, $poslf);
    } elseif ($poscr !== false) {
      $pos = $poscr;
    } elseif ($poslf !== false) {
      $pos = $poslf;
    } else {
      $pos = false;
    }
    # ligne se terminant par CR[LF]
    if ($pos !== false && $pos === $poscr) {
      $pos++;
      if ($pos < $length && $string[$pos] == "\n") $pos++;
      $line = substr($string, $index, $pos - $index);
      return [str::strip_nl($line), $pos];
    }
    # ligne se terminant par LF
    if ($pos !== false && $pos === $poslf) {
      $pos++;
      $line = substr($string, $index, $pos - $index);
      return [str::strip_nl($line), $pos];
    }
    # ligne sans caractère de fin
    return [substr($string, $index), $length];
  }

  function __construct(?string $string=null, int $index=0) {
    $this->setString($string, $index);
  }

  /** @var string la chaine à lire */
  private $string;

  /** @var int longueur de la chaine */
  private $length;

  /** @var int position de lecture dans la chaine */
  private $index;

  private static function fix_index(int $index, int $length): int {
    if ($index < 0) {
      if ($length > 0) {
        while ($index < 0) $index += $length;
      } else {
        $index = 0;
      }
    }
    if ($index > $length) $index = $length;
    return $index;
  }

  function setString(?string $string, int $index=0) {
    if ($string === null) $string = "";
    $length = strlen($string);
    $index = self::fix_index($index, $length);

    $this->string = $string;
    $this->index = $index;
    $this->length = $length;
  }

  function close(bool $close=true): void {
  }

  function getResource() {
    return null;
  }

  function appendFilter(string $filterName, ?int $readWrite=null, $params=null): void {
  }

  function prependFilter(string $filterName, ?int $readWrite=null, $params=null): void {
  }

  function setEncodingFilter(string $from, string $to = "utf-8"): void {
  }

  function seek(int $index=0, int $whence=SEEK_SET): int {
    if ($whence == SEEK_CUR) {
      $index = $this->index + $index;
    } elseif ($whence == SEEK_END) {
      $index = $this->length - $index;
    }
    return $this->index = self::fix_index($index, $this->length);
  }

  function readLine(): string {
    $index = $this->index;
    $length = $this->length;
    if ($index == $length) throw EOFException::no_more_data();
    [$line, $this->index] = self::next_line($this->string, $index, $length);
    return $line;
  }

  protected function _next(&$key) {
    return $this->readLine();
  }
  function key() { return $this->_key(); }
  function current() { return $this->_current(); }

  function getContents(bool $close=true): string {
    $contents = substr($this->string, $this->index);
    $this->index = $this->length;
    return $contents;
  }
}
