<?php
namespace nur;

use nur\b\io\FileWriter;
use nur\b\io\IOException;
use nur\b\io\IWriter;

/**
 * Class writer: des outils pour écrire des valeurs vers une destination
 */
class writer {
  const OUTPUT_MAP = [
    "-" => "php://stdout",
    "/dev/stdout" => "php://stdout",
    "/dev/stderr" => "php://stderr",
  ];
  const OUTPUT_MODES = [
    "php://stdout" => "w",
    "php://stderr" => "w",
  ];

  /** indiquer si $output désigne une des sorties standard (stdout ou stderr) */
  static final function is_stdxxx($output): bool {
    if ($output === null) return true;
    if (!is_string($output)) return false;
    if (array_key_exists($output, self::OUTPUT_MAP)) {
      $output = self::OUTPUT_MAP[$output];
    }
    return array_key_exists($output, self::OUTPUT_MODES);
  }

  /** indiquer si $file désigne un nom de fichier local utilisable en écriture */
  static final function is_file($file): bool {
    if (!is_string($file)) return false;
    if (array_key_exists($file, self::OUTPUT_MAP)) {
      $file = self::OUTPUT_MAP[$file];
    }
    if (substr($file, 0, 7) === "file://") return true;
    return !preg_match('/^[a-z]+:\/\//', $file);
  }

  /**
   * ouvrir le cas échéant le fichier spécifié pour écriture
   *
   * @throws IOException
   */
  static final function with($output, ?string $mode=null): IWriter {
    if ($output instanceof IWriter) return $output;
    if ($mode === null) $mode = FileWriter::DEFAULT_MODE;
    if (!is_resource($output)) {
      if (array_key_exists($output, self::OUTPUT_MAP)) {
        $output = self::OUTPUT_MAP[$output];
      }
      if (array_key_exists($output, self::OUTPUT_MODES)) {
        $mode = self::OUTPUT_MODES[$output];
      }
    }
    return new FileWriter($output, $mode);
  }

  /**
   * écrire une suite de valeurs collées les unes aux autres dans la destination
   *
   * @throws IOException
   */
  static final function write($output, ...$values): void {
    if ($output === null) {
      out::write(...$values);
    } else {
      $close = !($output instanceof IWriter);
      self::with($output)->write(...$values)->close($close);
    }
  }

  /**
   * afficher une suite de valeurs collées les unes aux autres suivie d'un saut
   * à la ligne
   *
   * @throws IOException
   */
  static final function wnl($output, ...$values): void {
    if ($output === null) {
      out::wnl(...$values);
    } else {
      $close = !($output instanceof IWriter);
      self::with($output)->wnl(...$values)->close($close);
    }
  }

  /**
   * écrire une suite de valeurs séparées par des espaces dans la destination
   *
   * @throws IOException
   */
  static final function print($output, ...$values): void {
    if ($output === null) {
      out::print(...$values);
    } else {
      $close = !($output instanceof IWriter);
      self::with($output)->print(...$values)->close($close);
    }
  }

  /**
   * afficher une suite de valeurs séparées par des espaces suivi d'un saut à la ligne
   *
   * @throws IOException
   */
  static final function pnl($output, ...$values): void {
    if ($output === null) {
      out::pnl(...$values);
    } else {
      $close = !($output instanceof IWriter);
      self::with($output)->pnl(...$values)->close($close);
    }
  }

  /**
   * écrire une suite de lignes dans la destination
   *
   * @throws IOException
   */
  static final function write_lines($output, iterable $lines): void {
    if ($output === null) {
      foreach ($lines as $line) {
        echo $line;
        echo "\n";
      }
    } else {
      $close = !($output instanceof IWriter);
      self::with($output)->writeLines($lines)->close($close);
    }
  }
}
