<?php

namespace Snaju\Inception\route;

use Snaju\Inception\InceptionCore;
use Snaju\Inception\Route\Loaders\Twig\TemplateManager;
use Snaju\Inception\Util\Util;

class RouteTree
{

    private $root;

    private $cursor;

    private $notFound = false;

    /**
     * RouteTree constructor.
     * @param RouteNode $defaultNode
     */
    public function __construct(RouteNode $defaultNode)
    {
        $this->root = $defaultNode;
        $this->cursor = $this->root;
    }

    public function pushPath(string $fullPath, Route $routeObj = null)
    {
        if ($fullPath == "/" && $this->root->getRoutePart() == null) {
            $this->cursor = $this->root;
            $this->cursor->setRouteObject($routeObj);
        } else {
            $parts = Util::cleanArray(explode("/", $fullPath));

            if (isset($parts[0])) {
                $part = $parts[0];
                $pathLeft = implode("/", array_splice($parts, 1));

                $this->cursor->addChild((new RouteNode($this->cursor, $part)), true);
                $this->cursor = $this->cursor->getChild($part, true);

                $this->pushPath($pathLeft, $routeObj);
            } else {
//            $this->cursor->addChild(new RouteNode(null, $fullPath, null));
                $this->cursor->setRouteObject($routeObj);
                $this->cursor = $this->root;
            }
        }
    }

    public function searchPathWeighted(string $path, $setAtRoot = true): RouteNode
    {
        if ($setAtRoot) {
            $this->cursor = $this->root;
            $this->cursor->calcWeight($path);
            $this->cursor->totalWeight();
        }

        $pp = explode("/", $path);
        $pp = Util::cleanArray($pp);

//        $i = 0;
//        foreach ($pp as $p) {
//            $searchFor = implode("/",array_slice($pp,$i));
//            echo "Searching in: " . $searchFor."<br/>";
//        }

        while (!$this->cursor->allZeroWeights()) {
            $this->cursor = $this->cursor->getHighestChild();
//            $this->cursor->pullUrlParams();
        }

        if ($this->cursor != null) {
            // Pull params out

            $tPath = Util::cleanArray(explode("/", $this->cursor->getFullPath()));
            $rPath = Util::cleanArray(explode("/", $path));

            $i = 0;
            foreach ($tPath as $tp) {
                if (preg_match('/\{(.*?)\}/mi', $tp, $m)) {
                    InceptionCore::getRequest()->mergeAttributes([
                        $m[1] => $rPath[$i]
                    ]);

                    // Add to the URL data
                    TemplateManager::addData("url.{$m[1]}", $rPath[$i]);
                }
                $i++;
            }

        }

//        echo $this->cursor->getFullPath();

//        EXIT;
        return $this->cursor;
    }

    public function searchPath(string $path, $setAtRoot = true)
    {
        if ($setAtRoot) {
            $this->cursor = $this->root;
        }

        $parts = Util::cleanArray(explode("/", $path));

        if (isset($parts[0])) {


            $part = $parts[0];
            $newPath = implode("/", array_slice($parts, 1));

            if ($this->cursor->hasChild($part)) {
                $this->cursor = $this->cursor->getChild($part);
                return $this->searchPath($newPath, false);
            }

            return $this->cursor;
        }

        return $this->cursor;
    }

    public function merge(RouteTree $tree)
    {
        foreach ($tree->getRouteArray() as $path => $obj) {
            if ($obj instanceof RouteNode) {
                $this->pushPath($path, $obj->getRouteObject());
            }
        }
    }

    /**
     * @return RouteNode
     */
    public function getRoot(): RouteNode
    {
        return $this->root;
    }

    /**
     * @param RouteNode $root
     */
    public function setRoot(RouteNode $root): void
    {
        $this->root = $root;
    }

    /**
     * @return RouteNode
     */
    public function getCursor(): RouteNode
    {
        return $this->cursor;
    }

    /**
     * @return bool
     */
    public function isNotFound(): bool
    {
        return $this->notFound;
    }

    /**
     * @param bool $notFound
     */
    public function setNotFound(bool $notFound): void
    {
        $this->notFound = $notFound;
    }

    /**
     * @param RouteNode $cursor
     */
    public function setCursor(RouteNode $cursor): void
    {
        $this->cursor = $cursor;
    }

    public function printOut()
    {
        echo json_encode($this->root->getArray());
    }

    public function getRouteArray(): array
    {
        $routes = [];
        $this->cursor = $this->root;
        $this->cursor->getRoutes($routes);
        return $routes;
    }

}

?>