<?php
namespace Newland\PageFrameProvider\Routing;

use Neos\ContentRepository\Domain\Model\NodeInterface;
use Neos\Flow\Aop\AdvicesTrait;
use Neos\Neos\Routing\Exception\NoHomepageException;
use \Neos\Neos\Routing\FrontendNodeRoutePartHandler as OriginalFrontendNodeRoutePartHandler;
use Neos\Flow\Annotations as Flow;
use Newland\PageFrameProvider\NodeResolution\RootNodeResolver;
use Newland\PageFrameProvider\Service\PageFrameContextService;

/**
 * Route part handler that will *always* match the root node of xthe current site no matter
 * which URL was given.
 *
 * If the given URL contains dimension information those will be respected and stripped from
 * the routePath.
 */
class FrontendNodeRoutePartHandler extends OriginalFrontendNodeRoutePartHandler
{
    use AdvicesTrait;

    /**
     * @var PageFrameContextService
     * @Flow\Inject()
     */
    protected $pageFrameContext;

    /**
     * @var RootNodeResolver
     * @Flow\Inject()
     */
    protected $nodeResolver;

    /**
     * @var string
     */
    protected $matchedPath;

    /**
     * Every part of request path could be part of the node or more routing
     * definitions. Therefor every part is tried - a request path such as
     * `/foo/bar/baz` will try at max 4 different request paths - exiting if
     * one matches:
     * - `/foo/bar/baz`
     * - `/foo/bar`
     * - `/foo`
     * - (empty string)
     *
     * @param string $requestPath
     * @return bool
     * @throws \Neos\Neos\Routing\Exception\NoHomepageException
     */
    protected function matchValue($requestPath)
    {
        $splitString = $this->splitString ?: '/';
        $parts = (array) explode($splitString, $requestPath);
        while (\count($parts) > 0) {
            $this->matchedPath = implode($splitString, $parts);
            if (parent::matchValue($this->matchedPath) && $this->nodeResolver->isNodePathAllowed($this->value)) {
                return true;
            }
            array_pop($parts);
        }
        $this->matchedPath = '';

        try {
            return parent::matchValue('');
        } catch (NoHomepageException $exception) {
            return false;
        }
    }

    /**
     * Not already splitting the request path up in order to support the multi-try approach above.
     *
     * @param string $requestPath
     * @return string
     */
    protected function findValueToMatch($requestPath)
    {
        return $requestPath;
    }

    protected function removeMatchingPortionFromRequestPath(&$routePath, $valueToMatch)
    {
        $regex = sprintf('/^%s/', preg_quote($this->matchedPath, '/'));
        $routePath = \Safe\preg_replace($regex, '', $routePath, 1);

        if (\is_array($routePath)) {
            $routePath = implode('', $routePath);
        }

        $result = (string) ltrim($routePath, '/');

        $routePath = '/' . $result;
    }

    /**
     * @param NodeInterface|string $node
     * @return bool
     */
    protected function resolveValue($node)
    {
        $result = parent::resolveValue($node);
        if ($result && !\is_string($node)) {
            $this->pageFrameContext->setDimensions(
                $node->getContext()->getTargetDimensionValues()
            );
        }
        return $result;
    }
}
