<?php
namespace nur\sery\output\std;

use Exception;
use nur\sery\output\IMessenger;

/**
 * Class ProxyMessenger: un proxy vers ou un plusieurs instances de IMessenger
 *
 * NB: si cette classe est instanciée sans argument, elle agit comme un
 * "NullMessenger", c'est à dire une instance qui envoie tous les messages vers
 * /dev/null
 */
class ProxyMessenger implements IMessenger {
  function __construct(?IMessenger ...$msgs) {
    $this->msgs = [];
    foreach ($msgs as $msg) {
      if ($msg !== null) $this->msgs[] = $msg;
    }
  }

  /** @var IMessenger[] */
  protected $msgs;

  function resetParams(?array $params=null): void { foreach ($this->msgs as $msg) { $msg->resetParams($params); } }
  function clone(?array $params=null): self {
    $clone = clone $this;
    foreach ($clone->msgs as &$msg) {
      $msg = $msg->clone($params);
    }; unset($msg);
    return $clone;
  }
  function section($content, ?callable $func=null, ?int $level=null): void {
    $useFunc = false;
    foreach ($this->msgs as $msg) {
      $msg->section($content, null, $level);
      if ($msg instanceof _IMessenger) $useFunc = true;
    }
    if ($useFunc && $func !== null) {
      try {
        $func($this);
      } finally {
        /** @var _IMessenger $msg */
        foreach ($this->msgs as $msg) {
          $msg->_endSection();
        }
      }
    }
  }
  function title($content, ?callable $func=null, ?int $level=null): void {
    $useFunc = false;
    $untils = [];
    foreach ($this->msgs as $msg) {
      if ($msg instanceof _IMessenger) {
        $useFunc = true;
        $untils[] = $msg->_getTitleMark();
      }
      $msg->title($content, null, $level);
    }
    if ($useFunc && $func !== null) {
      try {
        $func($this);
      } finally {
        /** @var _IMessenger $msg */
        $index = 0;
        foreach ($this->msgs as $msg) {
          if ($msg instanceof _IMessenger) {
            $msg->_endTitle($untils[$index++]);
          }
        }
      }
    }
  }
  function desc($content, ?int $level=null): void { foreach ($this->msgs as $msg) { $msg->desc($content, $level); } }
  function action($content, ?callable $func=null, ?int $level=null): void {
    $useFunc = false;
    $untils = [];
    foreach ($this->msgs as $msg) {
      $msg->action($content, null, $level);
      if ($msg instanceof _IMessenger) {
        $useFunc = true;
        $untils[] = $msg->_getActionMark();
      }
    }
    if ($useFunc && $func !== null) {
      try {
        $result = $func($this);
        /** @var _IMessenger $msg */
        $index = 0;
        foreach ($this->msgs as $msg) {
          if ($msg->_getActionMark() > $untils[$index++]) {
            $msg->aresult($result);
          }
        }
      } catch (Exception $e) {
        /** @var _IMessenger $msg */
        foreach ($this->msgs as $msg) {
          $msg->afailure($e);
        }
        throw $e;
      } finally {
        /** @var _IMessenger $msg */
        $index = 0;
        foreach ($this->msgs as $msg) {
          $msg->_endAction($untils[$index++]);
        }
      }
    }
  }
  function step($content, ?int $level=null): void { foreach ($this->msgs as $msg) { $msg->step($content, $level); } }
  function asuccess($content=null, ?int $overrideLevel=null): void { foreach ($this->msgs as $msg) { $msg->asuccess($content, $overrideLevel); } }
  function afailure($content=null, ?int $overrideLevel=null): void { foreach ($this->msgs as $msg) { $msg->afailure($content, $overrideLevel); } }
  function adone($content=null, ?int $overrideLevel=null): void { foreach ($this->msgs as $msg) { $msg->adone($content, $overrideLevel); } }
  function aresult($result=null, ?int $overrideLevel=null): void { foreach ($this->msgs as $msg) { $msg->aresult($result, $overrideLevel); } }
  function print($content, ?int $level=null): void { foreach ($this->msgs as $msg) { $msg->print($content, $level); } }
  function info($content, ?int $level=null): void { foreach ($this->msgs as $msg) { $msg->info($content, $level); } }
  function note($content, ?int $level=null): void { foreach ($this->msgs as $msg) { $msg->note($content, $level); } }
  function warning($content, ?int $level=null): void { foreach ($this->msgs as $msg) { $msg->warning($content, $level); } }
  function error($content, ?int $level=null): void { foreach ($this->msgs as $msg) { $msg->error($content, $level); } }
  function end(bool $all=false): void { foreach ($this->msgs as $msg) { $msg->end($all); } }
}