<?php
namespace Vendor\RmedRealurlConfig\Hooks;


use DmitryDulepov\Realurl\Encoder\UrlEncoder;
use TYPO3\CMS\Core\Error\Exception;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\HttpUtility;
use TYPO3\CMS\Core\Utility\MathUtility;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
use TYPO3\CMS\Frontend\Page\PageRepository;


/**
 * @Notice This is an individual redirect for clubwien.at.
 * You can find the method buildUrl where you can change the output individual
 *
 */
class UrlRedirect
{
    /**
     * @var $pageId
     */
    protected $pageId;

    /**
     * cObject to generate links
     *
     * @var \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
     * @inject
     */
    protected $cObj;

    /**
     * @var $pageUid
     */
    protected $pageUid;

    /**
     * @var $rootLine
     */
    protected $rootLine;

    /**
     * @var $params
     */
    protected $params;

    /**
     * @var array $sessionParams
     */
    private $sessionParams = [
        'type'  => 'ses',
        'key'   => 'lastVisit'
    ];


    public function __construct()
    {
        $this->cObj = GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectRenderer');
        $this->cObj->start(array());
    }


    /**
     * @param array $params
     */
    public function redirect(array $params)
    {
        /** @var UrlEncoder $encoder */
        try {
            $headerCode = HttpUtility::HTTP_STATUS_301;
            $this->params = $params;
            $pObj = $params['params']['pObj'];
            $uri = $pObj->siteScript;

            if(strpos($uri, 'html') !== false) {

                // @todo add a hook for change the expressionx
                preg_match("/[-\w]+\.([0-9]+)\.0\.html$/", $uri, $match);

                if (isset($match[1])) {
                    $uid = intval($match[1]);
                    $this->setPageUid($uid);

                    // sets rootLine if empty it throws page not found error
                    if(!$this->rootLine = $this->getRootLine())
                    {
                        $errorMessage = '404 Page Not Found!';
                        return $this->throw404($errorMessage);
                    }

                    $this->initTSFE();

                    // 1: page, 2: category, 3: category page, 4: page
                    if($this->hasParentPage()) {
                        $uri = $this->buildUri();
                        HttpUtility::redirect($uri, $headerCode);
                    }
                }
            }
        } catch (Exception $e) {
            $errorMessage =  $e->getMessage();
            $this->TypoScriptFrontendController()->pageNotFoundAndExit($errorMessage);
        }
    }


    /**
     * @param int $nodeLevel
     * @return mixed|string
     */
    protected function buildUri($nodeLevel = 3)
    {
        if($this->countRootLine() >= $nodeLevel) {
            $this->params['URL'] = $this->getPageLink();
            return $this->params['URL'];
        }
    }


    /**
     * Gets the Root
     *
     * @return array
     */
    protected function getRootLine()
    {
        $uid = $this->getPageUid();
        if($this->getPageByUID()) {
            return $this->PageRepository()->getRootLine($uid);
        }

        return null;
    }


    /**
     * @return array
     */
    protected function getPageByUID()
    {
        $uid = $this->getPageUid();
        return $this->PageRepository()->getPage($uid);
    }


    /**
     * @return bool
     */
    protected function hasParentPage()
    {
        $hasParent = false;
        if(!empty($this->getCurrentPage('pid'))) {
            $hasParent = true;
        }
        return $hasParent;
    }


    /**
     * This is just a workaround to build a Speaking URL
     *
     * @param null $key
     * @return mixed
     */
    protected function getCurrentPage($key = null)
    {
        $pObj = null;
        $currentKey = ($this->countRootLine()-1);
        if(isset($this->rootLine[$currentKey])) {
            $pObj = $this->rootLine[$currentKey];
            if($key) {
                $pObj = $pObj[$key];
            }
        }
        return $pObj;
    }

    /**
     * Generates the link to a single page
     *
     * @return	string	Full URL of the page including host name (escaped)
     */
    protected function getPageLink()
    {
        $pageId = $this->getPageUid();
        # old conf for typoLink method from ContentObjectRenderer
        $conf = array(
            'useCacheHash' => true,
            'parameter' => $pageId,
            'returnLast' => 'url',
            'additionalParams' => '&tx_rmedpage_showcase[controller]=News'.
                '&tx_rmedpage_showcase[action]=detail'
        );

        /** @var ContentObjectRenderer cObj */
        $this->cObj = GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectRenderer');
        $this->cObj->start([]);

        $uri = htmlspecialchars($this->cObj->typoLink('', $conf));
        return GeneralUtility::locationHeaderUrl($uri);
    }


    // unused
    protected function initTSFE($typeNum = 0)
    {
        \TYPO3\CMS\Frontend\Utility\EidUtility::initTCA();
        if (!is_object($GLOBALS['TT'])) {
            $GLOBALS['TT'] = new \TYPO3\CMS\Core\TimeTracker\NullTimeTracker;
            $GLOBALS['TT']->start();
        }

        $uid = $this->getPageUid();
        $GLOBALS['TSFE']->id = $uid;

        /** @var TypoScriptFrontendController $GLOBALS['TSFE'] */
        $GLOBALS['TSFE'] = GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\Controller\\TypoScriptFrontendController',  $GLOBALS['TYPO3_CONF_VARS'], $uid, $typeNum);

        /** @var GeneralUtility sys_page */
        $GLOBALS['TSFE']->sys_page = GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\Page\\PageRepository');
        $GLOBALS['TSFE']->sys_page->init(true);

        $GLOBALS['TSFE']->connectToDB();
        $GLOBALS['TSFE']->initFEuser();
        $GLOBALS['TSFE']->determineId();
        $GLOBALS['TSFE']->initTemplate();

        $GLOBALS['TSFE']->rootLine = $this->rootLine;
        $GLOBALS['TSFE']->getConfigArray();

        if (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('realurl')) {
            $rootline = \TYPO3\CMS\Backend\Utility\BackendUtility::BEgetRootLine($uid);
            $host = \TYPO3\CMS\Backend\Utility\BackendUtility::firstDomainRecord($rootline);
            $_SERVER['HTTP_HOST'] = $host;
        }
    }


    /**
     * Throws a 404 error with the corresponding message.
     *
     * @param string $errorMessage
     * @return void
     */
    protected function throw404($errorMessage)
    {
        // Set language to allow localized error pages
        if (MathUtility::canBeInterpretedAsInteger($this->detectedLanguageId)) {
            $_GET['L'] = $this->detectedLanguageId;
        }
        $this->TypoScriptFrontendController()->pageNotFoundAndExit($errorMessage);
    }


    /**
     * @return int
     */
    protected function countRootLine()
    {
        $count = count($this->rootLine);
        return $count;
    }


    /**
     * @return ContentObjectRenderer object
     */
    protected function getCObj()
    {
        return GeneralUtility::makeInstance(ContentObjectRenderer::class);
    }


    /**
     * @return PageRepository object
     */
    protected function PageRepository()
    {
        return GeneralUtility::makeInstance(PageRepository::class);
    }


    /**
     * @return TypoScriptFrontendController object
     */
    protected function TypoScriptFrontendController()
    {
        return $GLOBALS['TSFE'];
    }


    /**
     * @return mixed
     */
    public function getPageUid()
    {
        return $this->pageUid;
    }


    /**
     * @param mixed $pageUid
     * @throws Exception
     */
    public function setPageUid($pageUid)
    {
        if(MathUtility::canBeInterpretedAsInteger($pageUid)) {
            $this->pageUid = intval($pageUid);
            return;
        }

        throw new Exception('The input can not be interpreted as integer');
    }
}