protected function findRouteRecursively($routeName)
    {
        // alias check
        if(is_string($routeName)) {
            if(isset($this->aliasIndices[$routeName])) {
                $routeName = $this->aliasIndices[$routeName];
            } else {
                foreach($this->groupAliasIndices as $alias => $name) {
                    if(strpos($routeName, $alias) === 0) {
                        $routeName = substr_replace($routeName, $name, 0, strlen($alias));
                        break;
                    }
                }
            }
        }

        $routeNames = !is_array($routeName) ? explode('.', $routeName) : $routeName;
        $routeName = array_shift($routeNames);
        $isTag = strpos($routeName, '#') === 0;

        // search by route name
        if(!$isTag)
        {
            // loop this group, and find the route.
            foreach($this->storage as $route)
            {
                if($route->getName() === $routeName)
                {
                    // still has depth
                    if(count($routeNames) > 0)
                        if($route->hasSubroutes())
                            return $route->getSubroutes()->findRouteRecursively($routeNames);
                        else
                            return false;

                    return $route;
                }
            }
        }
        // search by route tag under this group.
        else
        {
            $route = $this->findRouteByTag(substr($routeName, 1));

            if($route)
            {
                if(count($routeNames) > 0)
                    if($route->hasSubroutes())
                        return $route->getSubroutes()->findRouteRecursively($routeNames);
                    else
                        return false;

                return $route;
            }
        }

        return false;
    }