<?php
/**
 * Copyright 2020 Adobe
 * All Rights Reserved.
 *
 * NOTICE: Adobe permits you to use, modify, and distribute this file in
 * accordance with the terms of the Adobe license agreement accompanying
 * it.
 */
declare(strict_types=1);

namespace Magento\Mray\Index\Traverser;

use Magento\Mray\Package\AbstractTree\Node\Node;
use Magento\Mray\Package\AbstractTree\Node\NodeTraversable;
use Magento\Mray\Package\AbstractTree\Traverser;
use function array_map;
use function is_array;

class VisitingTraverser implements Traverser
{
    /** @var NodeVisitor[] */
    private $visitors;

    /**
     * @param NodeVisitor[] $visitors
     */
    public function __construct(array $visitors)
    {
        $this->visitors = array_map(function (NodeVisitor $v) {
            return $v;
        }, $visitors);
    }

    /**
     * @inheritDoc
     */
    public function traverse(iterable $nodes): array
    {
        $traversed = [];
        foreach ($nodes as $node) {
            if (is_array($node)) {
                $this->traverse($node);
            } elseif ($node instanceof Node) {
                $this->traverseNode($node);
            }
            $traversed[] = $node;
        }
        return $traversed;
    }

    /**
     * @param Node $node
     */
    private function traverseNode(Node $node): void
    {
        foreach ($this->visitors as $visitor) {
            $visitor->enterNode($node);
        }

        if ($node instanceof NodeTraversable) {
            foreach ($node->getSubNodeNames() as $subNodeName) {
                $subNode = $node->$subNodeName;
                if (is_array($subNode)) {
                    $this->traverse($subNode);
                } elseif ($subNode instanceof Node) {
                    $this->traverseNode($subNode);
                }
            }
        }

        foreach ($this->visitors as $visitor) {
            $visitor->leaveNode($node);
        }
    }
}
