<?php
namespace nur\b\io;

use nur\out;

trait Twriter {
  function isatty(): bool {
    $resource = $this->getResource();
    return $resource !== null && stream_isatty($resource);
  }

  /** @var int */
  private $indentLevel = 0;

  /** @var string */
  private $indentString = out::INDENT_STRING;

  /** réinitialiser l'indentation */
  function resetIndent(?int $indentLevel=0, ?string $indentString=null): void {
    if ($indentLevel !== null) $this->indentLevel = $indentLevel;
    if ($indentString !== null) $this->indentString = $indentString;
  }

  /** augmenter le niveau d'indentation et retourner le niveau précédent */
  function indent(): int {
    $indentLevel = $this->indentLevel;
    $this->indentLevel++;
    return $indentLevel;
  }

  /** diminuer le niveau d'indentation */
  function dedent(): void {
    if ($this->indentLevel > 0) $this->indentLevel--;
  }

  protected function getIndent(): string {
    return str_repeat($this->indentString, $this->indentLevel);
  }

  private function _Twriter__filterValues(array $values): array {
    $nzs = [];
    foreach ($values as $value) {
      if ($value !== null && $value !== false) {
        $nzs[] = $value;
      }
    }
    return $nzs;
  }

  private function _Twriter__indentLines(string $lines, bool $haveNl): string {
    if ($haveNl) $lines = substr($lines, 0, -1);
    $lines = str_replace("\n", "\n".$this->getIndent(), $lines);
    if ($haveNl) $lines .= "\n";
    return $lines;
  }

  /** @var bool faut-il afficher une indentation avant la ligne courante? */
  private $indent = true;

  protected function indentLines(string $lines, bool $updateIndent=true): string {
    if ($this->indentLevel > 0) {
      if ($this->indent) $lines = $this->getIndent().$lines;
      $haveNl = substr($lines, -1) === "\n";
      $lines = $this->_Twriter__indentLines($lines, $haveNl);
      if ($updateIndent) $this->indent = $haveNl;
    }
    return $lines;
  }

  function toString(string $sep, array $values, bool $updateIndent=true): string {
    $lines = implode($sep, $this->_Twriter__filterValues($values));
    $lines = $this->indentLines($lines, $updateIndent);
    return $lines;
  }

  function write(...$values): IWriter {
    $this->_write($this->toString("", $values));
    return $this;
  }

  function wnl(...$values): IWriter {
    $this->_write($this->toString("", $values));
    $this->_write("\n");
    $this->indent = true;
    return $this;
  }

  function print(...$values): IWriter {
    $this->_write($this->toString(" ", $values));
    return $this;
  }

  function pnl(...$values): IWriter {
    $this->_write($this->toString(" ", $values));
    $this->_write("\n");
    $this->indent = true;
    return $this;
  }

  function writeLines(?iterable $lines): IWriter {
    if ($lines !== null) {
      foreach ($lines as $line) {
        $this->_write($this->indentLines($line));
        $this->_write("\n");
      }
    }
    return $this;
  }
}