<commit_before>/*
 * =============================================================================
 * 
 *   Copyright (c) 2011-2014, The THYMELEAF team (http://www.thymeleaf.org)
 * 
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 * 
 * =============================================================================
 */
package org.thymeleaf.standard.processor;

import java.io.StringWriter;
import java.util.Collections;
import java.util.Map;
import java.util.Set;

import org.thymeleaf.IEngineConfiguration;
import org.thymeleaf.context.IEngineContext;
import org.thymeleaf.context.ITemplateContext;
import org.thymeleaf.dialect.IProcessorDialect;
import org.thymeleaf.engine.AttributeName;
import org.thymeleaf.engine.TemplateModel;
import org.thymeleaf.exceptions.TemplateProcessingException;
import org.thymeleaf.model.ICloseElementTag;
import org.thymeleaf.model.IElementAttributes;
import org.thymeleaf.model.IModel;
import org.thymeleaf.model.IOpenElementTag;
import org.thymeleaf.model.IProcessableElementTag;
import org.thymeleaf.model.ITemplateEvent;
import org.thymeleaf.model.ITemplateStart;
import org.thymeleaf.processor.element.AbstractAttributeTagProcessor;
import org.thymeleaf.processor.element.IElementTagStructureHandler;
import org.thymeleaf.standard.expression.FragmentSelectionUtils;
import org.thymeleaf.standard.expression.FragmentSignature;
import org.thymeleaf.standard.expression.FragmentSignatureUtils;
import org.thymeleaf.standard.expression.ParsedFragmentSelection;
import org.thymeleaf.standard.expression.ProcessedFragmentSelection;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.util.EscapedAttributeUtils;
import org.thymeleaf.util.StringUtils;

/**
 *
 * @author <NAME>
 *
 * @since 3.0.0
 *
 */
public abstract class AbstractStandardFragmentInsertionTagProcessor extends AbstractAttributeTagProcessor {


    private static final String FRAGMENT_ATTR_NAME = "fragment";
    private static final String TEMPLATE_NAME_CURRENT_TEMPLATE = "this";


    private final boolean replaceHost;
    // This flag should probably be removed once th:include is removed in 3.2 (deprecated in 3.0)
    private final boolean insertOnlyContents;



    protected AbstractStandardFragmentInsertionTagProcessor(
            final IProcessorDialect dialect, final TemplateMode templateMode, final String dialectPrefix, final String attrName, final int precedence,
            final boolean replaceHost) {
        this(dialect, templateMode, dialectPrefix, attrName, precedence, replaceHost, false);
    }

    /*
     * This constructor has package visibility in order to avoid user-created subclasses to use it. This should
     * only be used by the th:include processor, which was deprecated as of 3.0, and will be removed in 3.2.
     */
    AbstractStandardFragmentInsertionTagProcessor(
            final IProcessorDialect dialect, final TemplateMode templateMode, final String dialectPrefix, final String attrName, final int precedence,
            final boolean replaceHost, final boolean insertOnlyContents) {
        super(dialect, templateMode, dialectPrefix, null, false, attrName, true, precedence, true);
        this.replaceHost = replaceHost;
        this.insertOnlyContents = insertOnlyContents;
    }



    @Override
    protected void doProcess(
            final ITemplateContext context,
            final IProcessableElementTag tag,
            final AttributeName attributeName, final String attributeValue,
            final String attributeTemplateName, final int attributeLine, final int attributeCol,
            final IElementTagStructureHandler structureHandler) {


        final IEngineConfiguration configuration = context.getConfiguration();

        /*
         * PARSE THE FRAGMENT SELECTION SPEC and resolve each of its components
         */
        final ParsedFragmentSelection parsedFragmentSelection =
                FragmentSelectionUtils.parseFragmentSelection(context, attributeValue);
        if (parsedFragmentSelection == null) {
            throw new TemplateProcessingException("Could not parse as fragment selection: \"" + attributeValue + "\"");
        }


        /*
         * PROCESS THE PARSED FRAGMENT SELECTION
         */
        final ProcessedFragmentSelection processedFragmentSelection =
                FragmentSelectionUtils.processFragmentSelection(context, parsedFragmentSelection);

        String templateName = processedFragmentSelection.getTemplateName();
        Map<String,Object> fragmentParameters = processedFragmentSelection.getFragmentParameters();
        final Set<String> fragments =
                (processedFragmentSelection.hasFragmentSelector()? Collections.singleton(processedFragmentSelection.getFragmentSelector()) : null);


        /*
         * MIGHT NEED TO ADJUST THE TEMPLATE NAME if 'this' or an empty name is being used
         */
        if (StringUtils.isEmptyOrWhitespace(templateName) || TEMPLATE_NAME_CURRENT_TEMPLATE.equals(templateName)) {
            // We will use the same templateName that the host tag comes from
            templateName = attributeTemplateName;
        }


        /*
         * OBTAIN THE FRAGMENT MODEL from the TemplateManager. This means the fragment will be parsed and maybe
         * cached, and we will be returned an immutable model object (specifically a ParsedFragmentModel)
         */
        final TemplateModel fragmentModel =
                    configuration.getTemplateManager().parseStandalone(
                            context, templateName, fragments,
                            null, // we will not force the template mode
                            true);  // use the cache if possible, fragments are from template files


        /*
         * ONCE WE HAVE THE FRAGMENT MODEL (its events, in fact), CHECK THE FRAGMENT SIGNATURE which might
         * affect the way we apply the parameters to the fragment.
         *
         * Note this works whatever the template mode of the inserted fragment, given we are looking for an
         * element containing a "th:fragment/data-th-fragment" in a generic, non-template-dependent way.
         */
        final int parsedFragmentLen = fragmentModel.size();
        ITemplateEvent fragmentHolderEvent = (parsedFragmentLen >= 1? fragmentModel.get(0) : null);
        if (fragmentHolderEvent != null && fragmentHolderEvent instanceof ITemplateStart) {
            fragmentHolderEvent = (parsedFragmentLen >= 3? fragmentModel.get(1) : null);<commit_msg>scan template stack when template name = 'this' or empty.<commit_after>/*
 * =============================================================================
 * 
 *   Copyright (c) 2011-2014, The THYMELEAF team (http://www.thymeleaf.org)
 * 
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 * 
 * =============================================================================
 */
package org.thymeleaf.standard.processor;

import java.io.StringWriter;
import java.util.Collections;
import java.util.Map;
import java.util.Set;

import org.thymeleaf.IEngineConfiguration;
import org.thymeleaf.context.IEngineContext;
import org.thymeleaf.context.ITemplateContext;
import org.thymeleaf.dialect.IProcessorDialect;
import org.thymeleaf.engine.AttributeName;
import org.thymeleaf.engine.TemplateModel;
import org.thymeleaf.exceptions.TemplateProcessingException;
import org.thymeleaf.model.ICloseElementTag;
import org.thymeleaf.model.IElementAttributes;
import org.thymeleaf.model.IModel;
import org.thymeleaf.model.IOpenElementTag;
import org.thymeleaf.model.IProcessableElementTag;
import org.thymeleaf.model.ITemplateEvent;
import org.thymeleaf.model.ITemplateStart;
import org.thymeleaf.processor.element.AbstractAttributeTagProcessor;
import org.thymeleaf.processor.element.IElementTagStructureHandler;
import org.thymeleaf.standard.expression.FragmentSelectionUtils;
import org.thymeleaf.standard.expression.FragmentSignature;
import org.thymeleaf.standard.expression.FragmentSignatureUtils;
import org.thymeleaf.standard.expression.ParsedFragmentSelection;
import org.thymeleaf.standard.expression.ProcessedFragmentSelection;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.util.EscapedAttributeUtils;
import org.thymeleaf.util.StringUtils;

/**
 *
 * @author <NAME>
 *
 * @since 3.0.0
 *
 */
public abstract class AbstractStandardFragmentInsertionTagProcessor extends AbstractAttributeTagProcessor {


    private static final String FRAGMENT_ATTR_NAME = "fragment";
    private static final String TEMPLATE_NAME_CURRENT_TEMPLATE = "this";


    private final boolean replaceHost;
    // This flag should probably be removed once th:include is removed in 3.2 (deprecated in 3.0)
    private final boolean insertOnlyContents;



    protected AbstractStandardFragmentInsertionTagProcessor(
            final IProcessorDialect dialect, final TemplateMode templateMode, final String dialectPrefix, final String attrName, final int precedence,
            final boolean replaceHost) {
        this(dialect, templateMode, dialectPrefix, attrName, precedence, replaceHost, false);
    }

    /*
     * This constructor has package visibility in order to avoid user-created subclasses to use it. This should
     * only be used by the th:include processor, which was deprecated as of 3.0, and will be removed in 3.2.
     */
    AbstractStandardFragmentInsertionTagProcessor(
            final IProcessorDialect dialect, final TemplateMode templateMode, final String dialectPrefix, final String attrName, final int precedence,
            final boolean replaceHost, final boolean insertOnlyContents) {
        super(dialect, templateMode, dialectPrefix, null, false, attrName, true, precedence, true);
        this.replaceHost = replaceHost;
        this.insertOnlyContents = insertOnlyContents;
    }



    @Override
    protected void doProcess(
            final ITemplateContext context,
            final IProcessableElementTag tag,
            final AttributeName attributeName, final String attributeValue,
            final String attributeTemplateName, final int attributeLine, final int attributeCol,
            final IElementTagStructureHandler structureHandler) {


        final IEngineConfiguration configuration = context.getConfiguration();

        /*
         * PARSE THE FRAGMENT SELECTION SPEC and resolve each of its components
         */
        final ParsedFragmentSelection parsedFragmentSelection =
                FragmentSelectionUtils.parseFragmentSelection(context, attributeValue);
        if (parsedFragmentSelection == null) {
            throw new TemplateProcessingException("Could not parse as fragment selection: \"" + attributeValue + "\"");
        }


        /*
         * PROCESS THE PARSED FRAGMENT SELECTION
         */
        final ProcessedFragmentSelection processedFragmentSelection =
                FragmentSelectionUtils.processFragmentSelection(context, parsedFragmentSelection);

        String templateName = processedFragmentSelection.getTemplateName();
        Map<String,Object> fragmentParameters = processedFragmentSelection.getFragmentParameters();
        final Set<String> fragments =
                (processedFragmentSelection.hasFragmentSelector()? Collections.singleton(processedFragmentSelection.getFragmentSelector()) : null);

        /*
         * OBTAIN THE FRAGMENT MODEL from the TemplateManager. This means the fragment will be parsed and maybe
         * cached, and we will be returned an immutable model object (specifically a ParsedFragmentModel)
         */
        List<String> templateNameStack = new ArrayList<String>();
        templateNameStack.add(templateName);  //Default template to consider.

        // scan the template stack if template name is 'this' or an empty name is being used
        if (StringUtils.isEmptyOrWhitespace(templateName) || TEMPLATE_NAME_CURRENT_TEMPLATE.equals(templateName)) {
            templateNameStack.clear();
            for (int i = context.getTemplateStack().size() - 1; i >= 0; i--)
            {
                templateNameStack.add(context.getTemplateStack().get(i).getTemplate());
            }
        }

        TemplateModel tempModel;
        int i = 0;
        do {
            tempModel = configuration.getTemplateManager().parseStandalone(
                    context, templateNameStack.get(i), fragments,
                    null, // we will not force the template mode
                    true);  // use the cache if possible, fragments are from template files
            i++;
        } while (i <= templateNameStack.size() - 1 && tempModel.size() <= 2);  //post test -- need to parse at least 1x

        final TemplateModel fragmentModel = tempModel;
        tempModel = null;

        /*
         * ONCE WE HAVE THE FRAGMENT MODEL (its events, in fact), CHECK THE FRAGMENT SIGNATURE which might
         * affect the way we apply the parameters to the fragment.
         *
         * Note this works whatever the template mode of the inserted fragment, given we are looking for an
         * element containing a "th:fragment/data-th-fragment" in a generic, non-template-dependent way.
         */
        final int parsedFragmentLen = fragmentModel.size();
        ITemplateEvent fragmentHolderEvent = (parsedFragmentLen >= 1? fragmentModel.get(0) : null);
        if (fragmentHolderEvent != null && fragmentHolderEvent instanceof ITemplateStart) {
            fragmentHolderEvent = (parsedFragmentLen >= 3? fragmentModel.get(1) : null);
{'fraction_non_alphanumeric': 0.09104036306126659, 'fraction_numerical': 0.004125696211235646, 'mean_word_length': 3.477832512315271, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 16, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4446784', 'n_tokens_mistral': 3646, 'n_tokens_neox': 3518, 'n_words': 1095}