<?php declare(strict_types=1);

namespace Newland\NeosCommon\FlowQuery;

use Neos\ContentRepository\Domain\Model\NodeInterface;
use Neos\ContentRepository\Eel\FlowQueryOperations\FindOperation;
use Neos\Eel\FlowQuery\FlowQuery;

/**
 * Drop in replacement for `find` that only finds direct children of the current page but ignores
 * results that have another page child.
 */
class FindInPageOperation extends FindOperation
{
    protected static $shortName = 'findInPage';

    public function evaluate(FlowQuery $flowQuery, array $arguments)
    {
        $allowedParents = (array) $flowQuery->getContext();
        parent::evaluate($flowQuery, $arguments);

        $context = array_filter(
            (array) $flowQuery->getContext(),
            function (NodeInterface $node) use ($allowedParents) {
                return $this->isInDocumentNodes($allowedParents, $node);
            }
        );
        $flowQuery->setContext($context);
    }

    private function isInDocumentNodes(array $documentNodes, NodeInterface $node): bool
    {
        foreach ($documentNodes as $documentNode) {
            if ($this->isInDocumentNode($documentNode, $node)) {
                return true;
            }
        }
        return false;
    }

    private function isInDocumentNode(NodeInterface $documentNode, NodeInterface $node): bool
    {
        do {
            if ($node->getNodeType()->isOfType('Neos.Neos:Document')) {
                return $node->getPath() === $documentNode->getPath();
            }

            /** @var NodeInterface|null $node */
            $node = $node->getParent();
        } while ($node);

        return false;
    }
}
