/*******************************************************************************
 * This file is part of Pebble.
 * <p>
 * Copyright (c) 2014 by Mitchell Bösecke
 * <p>
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 ******************************************************************************/
package com.mitchellbosecke.pebble.template;

import com.google.common.cache.Cache;
import com.mitchellbosecke.pebble.cache.BaseTagCacheKey;
import com.mitchellbosecke.pebble.extension.ExtensionRegistry;

import java.util.List;
import java.util.Locale;
import java.util.concurrent.ExecutorService;

/**
 * An evaluation context will store all stateful data that is necessary for the
 * evaluation of a template. Passing the entire state around will assist with
 * thread safety.
 *
 * @author Mitchell
 */
public class EvaluationContext {

    private final boolean strictVariables;

    /**
     * A template will look to it's parent and children for overridden macros
     * and other features; this inheritance chain will help the template keep
     * track of where in the inheritance chain it currently is.
     */
    private final Hierarchy hierarchy;

    /**
     * A scope is a set of visible variables. A trivial template will only have
     * one scope. New scopes are added with for loops and macros for example.
     * <p>
     * Most scopes will have a link to their parent scope which allow an
     * evaluation to look up the scope chain for variables. A macro is an
     * exception to this as it only has access to it's local variables.
     */
    private final ScopeChain scopeChain;

    /**
     * The locale of this template.
     */
    private final Locale locale;

    /**
     * All the available filters/tests/functions for this template.
     */
    private final ExtensionRegistry extensionRegistry;

    /**
     * The tag cache
     */
    private final Cache<BaseTagCacheKey, Object> tagCache;

    /**
     * The user-provided ExecutorService (can be null).
     */
    private final ExecutorService executorService;

    /**
     * The imported templates are used to look up macros.
     */
    private final List<PebbleTemplateImpl> importedTemplates;

    /**
     * Constructor used to provide all final variables.
     *
     * @param self              The template implementation
     * @param strictVariables   Whether strict variables is to be used
     * @param locale            The locale of the template
     * @param extensionRegistry The extension registry
     * @param executorService   The optional executor service
     * @param scopeChain        The scope chain
     * @param hierarchy         The inheritance chain
     * @param tagCache          The cache used by the "cache" tag
     */
    public EvaluationContext(PebbleTemplateImpl self, boolean strictVariables, Locale locale,
            ExtensionRegistry extensionRegistry, Cache<BaseTagCacheKey, Object> tagCache,
            ExecutorService executorService, List<PebbleTemplateImpl> importedTemplates, ScopeChain scopeChain,
            Hierarchy hierarchy) {

        if (hierarchy == null) {
            hierarchy = new Hierarchy(self);
        }

        this.strictVariables = strictVariables;
        this.locale = locale;
        this.extensionRegistry = extensionRegistry;
        this.tagCache = tagCache;
        this.executorService = executorService;
        this.importedTemplates = importedTemplates;
        this.scopeChain = scopeChain;
        this.hierarchy = hierarchy;
    }

    /**
     * Makes an exact copy of the evaluation context EXCEPT for the inheritance
     * chain. This is necessary for the "include" tag.
     *
     * @param self The template implementation
     * @return A copy of the evaluation context
     */
    public EvaluationContext shallowCopyWithoutInheritanceChain(PebbleTemplateImpl self) {
        EvaluationContext result = new EvaluationContext(self, strictVariables, locale, extensionRegistry, tagCache,
                executorService, importedTemplates, scopeChain, null);
        return result;
    }

    /**
     * Makes an exact copy of the evaluation context except the "scopeChain"
     * object will be a deep copy without reference to the original. This is
     * used for the "parallel" tag.
     *
     * @param self The template implementation
     * @return A copy of the evaluation context
     */
    public EvaluationContext shallowCopyWithNewScopeChain(PebbleTemplateImpl self) {
        EvaluationContext result = new EvaluationContext(self, strictVariables, locale, extensionRegistry, tagCache,
                executorService, importedTemplates, scopeChain.deepCopy(), hierarchy);
        return result;
    }

    /**
     * Returns whether or not this template is being evaluated in "strict templates" mode
     *
     * @return Whether or not this template is being evaluated in "strict tempaltes" mode.
     */
    public boolean isStrictVariables() {
        return strictVariables;
    }

    /**
     * Returns the locale
     *
     * @return The current locale
     */
    public Locale getLocale() {
        return locale;
    }

    /**
     * Returns the extension registry used to access all of the tests/filters/functions
     *
     * @return The extension registry
     */
    public ExtensionRegistry getExtensionRegistry() {
        return extensionRegistry;
    }

    /**
     * Returns the executor service if exists or null
     *
     * @return The executor service if exists, or null
     */
    public ExecutorService getExecutorService() {
        return executorService;
    }

    /**
     * Returns a list of imported templates.
     *
     * @return A list of imported templates.
     */
    public List<PebbleTemplateImpl> getImportedTemplates() {
        return this.importedTemplates;
    }

    /**
     * Returns the cache used for the "cache" tag
     *
     * @return The cache used for the "cache" tag
     */
    public Cache<BaseTagCacheKey, Object> getTagCache() {
        return tagCache;
    }

    /**
     * Returns the scope chain data structure that allows variables to be added/removed from the current scope
     * and retrieved from the nearest visible scopes.
     *
     * @return The scope chain.
     */
    public ScopeChain getScopeChain() {
        return scopeChain;
    }

    /**
     * Returns the data structure representing the entire hierarchy of
     * the template currently being evaluated.
     *
     * @return The inheritance chain
     */
    public Hierarchy getHierarchy() {
        return hierarchy;
    }

}

@@ -573,16 +573,44 @@
 egistry;
+%0Aimport java.util.ArrayList;
 %0A%0Aimport
@@ -3521,24 +3521,94 @@
 tedTemplates
+ != null ? new ArrayList%3CPebbleTemplateImpl%3E(importedTemplates) : null
 ;%0A        th

Fix ConcurrentModificationException when importing macros in nested parallels blocks (#182) by snapshotting the importedTemplates passed into EvaluationContext.