<?php
namespace nur\mapper\base;

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

/**
 * Class MapperAggregate: un aggrégateur de mappers
 */
class MapperAggregate extends Mapper implements ArrayAccess {
  use TBaseArray, TGenericArray;

  function set($key, $mapper): self { return $this->_set($key, mapper_utils::ensure_mapper_class($mapper)); }
  function add($mapper): self { return $this->_set(null, mapper_utils::ensure_mapper_class($mapper)); }

  function setup(): void {
    parent::setup();
    $this->producer = new PushProducer();
    $this->iterator = mapper_utils::assemble_mappers($this->data, $this->producer);
  }

  /** @var PushProducer */
  private $producer;

  /** @var Mapper */
  private $iterator;

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

  /**
   * c'est la méthode {@link setup()} qui contruit $this->iterator. l'accès
   * aux données OOB de la chaine de mapper n'est donc possible que dans la
   * méthodes {@link mapper()}
   */
  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);
    } elseif ($this->iterator instanceof IOobdManager) {
      return $this->iterator->getOvalue($name, $default);
    }
    return null;
  }

  function mapper($item) {
    $this->producer->push($item);
    return $this->mapTo($this->iterator);
  }

  function teardown(): void {
    parent::teardown();
    $this->producer->close();
    $this->producer = null;
    $this->iterator->close();
    $this->iterator = null;
  }
}
