public function findTemplate($template, $themes = null)
    {
        if ($themes === null) {
            $themes = SSViewer::get_themes();
        }

        // Look for a cached result for this data set
        $cacheKey = md5(json_encode($template) . json_encode($themes));
        if ($this->getCache()->has($cacheKey)) {
            return $this->getCache()->get($cacheKey);
        }

        $type = '';
        if (is_array($template)) {
            // Check if templates has type specified
            if (array_key_exists('type', $template)) {
                $type = $template['type'];
                unset($template['type']);
            }
            // Templates are either nested in 'templates' or just the rest of the list
            $templateList = array_key_exists('templates', $template) ? $template['templates'] : $template;
        } else {
            $templateList = array($template);
        }

        foreach ($templateList as $i => $template) {
            // Check if passed list of templates in array format
            if (is_array($template)) {
                $path = $this->findTemplate($template, $themes);
                if ($path) {
                    $this->getCache()->set($cacheKey, $path);
                    return $path;
                }
                continue;
            }

            // If we have an .ss extension, this is a path, not a template name. We should
            // pass in templates without extensions in order for template manifest to find
            // files dynamically.
            if (substr($template, -3) == '.ss' && file_exists($template)) {
                $this->getCache()->set($cacheKey, $template);
                return $template;
            }

            // Check string template identifier
            $template = str_replace('\\', '/', $template);
            $parts = explode('/', $template);

            $tail = array_pop($parts);
            $head = implode('/', $parts);
            $themePaths = $this->getThemePaths($themes);
            foreach ($themePaths as $themePath) {
                // Join path
                $pathParts = [ $this->base, $themePath, 'templates', $head, $type, $tail ];
                $path = Path::join($pathParts) . '.ss';
                if (file_exists($path)) {
                    $this->getCache()->set($cacheKey, $path);
                    return $path;
                }
            }
        }

        // No template found
        $this->getCache()->set($cacheKey, null);
        return null;
    }