fn = $fn; $this->v = $v; } public function callable(DiffInterface $e): ?bool { $callable = $this->fn; return $callable( $e, $this->v->getIntersect($e), $this->v->getIntersected($e) ); } } class Variation implements TimeInterface, \IteratorAggregate { private $time; private $entities = []; private $intersected = []; private $intersects = []; public function __construct(Time $t) { $this->time = $t; } public function addEntity(DiffInterface $entity, ?Variation $intersects): self { $this->entities[] = $entity; if ($intersects != null) { $this->intersects[array_key_last($this->entities)] = $intersects; $intersects->addIntersected($entity, $this); } return $this; } public function getTime(): Time { return $this->time; } public function getFrom(): \DateTimeImmutable { return $this->time->getFrom(); } public function getUntil(): \DateTimeImmutable { return $this->time->getUntil(); } private function getEntityKey(DiffInterface $entity): ?int { $key = (function() use ($entity) : ?int { foreach ($this->entities as $key => $ent) if ($ent instanceof $entity) return $key; return null; })(); return $key; } public function getIntersect(DiffInterface $entity): ?Variation { $key = $this->getEntityKey($entity); if ($key === null || !isset($this->intersects[$key])) return null; return $this->intersects[$key]; } public function getIntersected(DiffInterface $entity): ?Variation { $key = $this->getEntityKey($entity); if ($key === null || !isset($this->intersected[$key])) return null; foreach ($this->intersected[$key] as $var) if ($var->getEntity(get_class($entity)) != null) return $var; } protected function addIntersected(DiffInterface $entity, Variation $var): self { $key = $this->getEntityKey($entity); if ($key === null) return $this; if (!isset($this->intersected[$key])) $this->intersected[$key] = [$var]; else $this->intersected[$key][] = $var; return $this; } public function isEmpty(): bool { return empty($this->entities); } public function filter(callable $filterFn): ?Variation { $entities = array_filter($this->entities, [ new VariationFn($filterFn, $this), 'callable', ]); if (count($entities) == 0) return null; $var = new Variation($this->time); foreach ($entities as $entity) $var->addEntity($entity, null); return $var; } public function operate(callable $opFn): void { array_walk($this->entities, [ new VariationFn($opFn, $this), 'callable' ]); } public function numEntities(): int { return sizeof($this->entities); } public function getEntity(string $class): ?DiffInterface { foreach ($this as $entity) if ($entity instanceof $class) return $entity; return null; } public function getIterator(): \Generator { foreach ($this->entities as $entity) yield $entity; return null; } }