<?php
// Copyright (c) Pickware GmbH. All rights reserved.
// This file is part of software that is released under a proprietary license.
// You must not copy, modify, distribute, make publicly available, or execute
// its contents or parts thereof without express permission by the copyright
// holder, unless otherwise permitted by law.

namespace Shopware\Plugins\ViisonCommon\Classes;

use Shopware\Components\DependencyInjection\Container;
use \Enlight_Components_Snippet_Resource as SnippetResource;

class SmartyPlugins
{
    /**
     * The tag name of the custom 'js_snippet' smarty block.
     */
    const JS_SNIPPET_BLOCK_NAME = 'js_snippet';

    /**
     * Registers a new filter with the 'template' service instance, which handles the custom
     * 'js_snippet' blocks.
     *
     * @param \Enlight_Event_EventArgs $args
     */
    public static function register()
    {
        $templateManager = Shopware()->Container()->get('template');
        $templateManager->registerFilter(\Smarty::FILTER_PRE, [__CLASS__, 'filterJsSnippetBlocks']);
    }

    /**
     * Parses the given $source to find any 'js_snippet' blocks and replaces them with their snippet value,
     * which is escaped so it can be used safely in JavaScript single quote strings. That is, all single quotes
     * in the snippet are guaranteed to be escaped when inserted by this filter. The 'js_snippet' block can be
     * used just like a normal 's' block, but current supports only two arguments 'name' and 'namespace' as well
     * as the block content as the default value. If no 'namespace' argument is set, the namespace of the given
     * $source is used. Example usage:
     *
     *  {js_snippet name=the/name namespace=some/random_namespace}An optional default snippet value{/js_snippet}
     *
     * @param string $source
     * @param \Smarty_Internal_Template $template
     * @return string
     */
    public static function filterJsSnippetBlocks($source, \Smarty_Internal_Template $template)
    {
        // Load some dependencies
        $container = Shopware()->Container();
        $snippetManager = $container->get('snippets');
        if ($container->has('snippet_resource')) {
            // Shopware >= 5.2.4
            $snippetResource = $container->get('snippet_resource');
        } else {
            // Create a new SnippetResource instance
            $showSnippetPlaceholder = $container->hasParameter('shopware.snippet.showSnippetPlaceholder')
                && $container->getParameter('shopware.snippet.showSnippetPlaceholder');
            $snippetResource = new SnippetResource($snippetManager, $showSnippetPlaceholder);
        }

        $ldl = $template->smarty->left_delimiter;
        $ldle = preg_quote($ldl);
        $rdl = $template->smarty->right_delimiter;
        $rdle = preg_quote($rdl);
        $snippetTag = self::JS_SNIPPET_BLOCK_NAME;
        $defaultNamespace = $snippetResource->getSnippetNamespace($template->source);

        // Find all 'js_snippet' blocks
        $pattern = sprintf(
            '/%1$s%2$s(\\s.+?)?%3$s(.*?)%1$s\\/%2$s%3$s/msi',
            $ldle,
            $snippetTag,
            $rdle
        );
        while (preg_match($pattern, $source, $matches, PREG_OFFSET_CAPTURE)) {
            if (count($matches) != 3) {
                continue;
            }
            $blockArgs = $matches[1][0];
            $blockContent = $matches[2][0];

            // Parse the snippet arguments to retrieve the snippet
            $hasNamespaceArg = preg_match('/(.?)(namespace=)(.*?)(?=(\\s|$))/', $blockArgs, $namespaceMatches);
            $namespace = ($hasNamespaceArg && !empty($namespaceMatches[3])) ? trim($namespaceMatches[3]) : $defaultNamespace;
            $hasNameArg = preg_match('/(.?)(name=)(.*?)(?=(\\s|$))/', $blockArgs, $nameMatches);
            $name = ($hasNameArg && !empty($nameMatches[3])) ? trim($nameMatches[3]) : $blockContent;
            $snippet = $snippetManager->getNamespace($namespace)->get($name, $blockContent);
            // Unescape already escaped single quotes
            $snippet = str_replace('\\\'', '\'', $snippet);
            // Escape all single quotes
            $snippet = str_replace('\'', '\\\'', $snippet);

            // Replace the whole match with the snippet value
            $matchingBlock = $matches[0];
            $source = substr_replace($source, $snippet, $matchingBlock[1], mb_strlen($matchingBlock[0]));
        }

        return $source;
    }
}
