<?php
namespace nur\mapper\base;

use ArrayAccess;
use nur\b\coll\TBaseArray;
use nur\b\coll\TGenericArray;
use nur\mapper\base\oobd\IOobdManager;

/**
 * Class ProducerAggregate: un aggrégateur de producer, qui fournit les données
 * des producers qu'il aggrège
 */
class ProducerAggregate extends Producer implements ArrayAccess {
  use TBaseArray, TGenericArray;

  function setup(): void {
    parent::setup();
    foreach ($this->data as &$producer) {
      $producer = producer_utils::ensure_producer($producer);
    }; unset($producer);
  }

  function hasOvalue(string $name): bool {
    if ($this->_hasOobdValue($name)) {
      return true;
    } elseif ($this->sharedOobdManager !== null
      && $this->sharedOobdManager->hasOvalue($name)) {
      return true;
    }
    foreach ($this->data as $producer) {
      if ($producer instanceof IOobdManager && $producer->hasOvalue($name)) {
        return true;
      }
    }
    return false;
  }

  /**
   * l'accès aux données OOB de la chaine de producer n'est possible qu'après
   * l'appel de la méthode {@link setup()}
   */
  function getOvalue(string $name, $default=null) {
    if ($this->_hasOobdValue($name)) {
      return $this->_getOobdValue($name, $default);
    } elseif ($this->sharedOobdManager !== null
      && $this->sharedOobdManager->hasOvalue($name)) {
      return $this->sharedOobdManager->getOvalue($name, $default);
    }
    foreach ($this->data as $producer) {
      if ($producer instanceof IOobdManager && $producer->hasOvalue($name)) {
        return $producer->getOvalue($name, $default);
      }
    }
    return null;
  }

  function producer() {
    foreach ($this->data as $producer) {
      if ($producer instanceof Producer) {
        try {
          yield from $producer;
        } finally {
          $producer->close();
        }
        $this->return = $producer->getReturn();
      } else {
        yield from $producer;
      }
    }
  }

  protected function teardown(): void {
    parent::teardown();
    foreach ($this->data as $producer) {
      $producer->close();
    }
  }
}