<commit_before>/**
 *  Copyright (C) 2008 Orbeon, Inc.
 *
 *  This program is free software; you can redistribute it and/or modify it under the terms of the
 *  GNU Lesser General Public License as published by the Free Software Foundation; either version
 *  2.1 of the License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *  See the GNU Lesser General Public License for more details.
 *
 *  The full text of the license is available at http://www.gnu.org/copyleft/lesser.html
 */
package org.orbeon.oxf.xforms;

import org.dom4j.Element;
import org.orbeon.oxf.common.OXFException;
import org.orbeon.oxf.common.ValidationException;
import org.orbeon.oxf.pipeline.api.PipelineContext;
import org.orbeon.oxf.util.XPathCache;
import org.orbeon.oxf.xforms.control.XFormsControl;
import org.orbeon.oxf.xforms.event.XFormsEventHandlerContainer;
import org.orbeon.oxf.xforms.function.XFormsFunction;
import org.orbeon.oxf.xforms.processor.XFormsServer;
import org.orbeon.oxf.xml.dom4j.ExtendedLocationData;
import org.orbeon.oxf.xml.dom4j.LocationData;
import org.orbeon.saxon.om.Item;
import org.orbeon.saxon.om.NodeInfo;
import org.orbeon.saxon.om.ValueRepresentation;

import java.util.*;

/**
 * Handle a stack of XPath evaluation context information. This can be used by controls, models, and actions.
 */
public class XFormsContextStack {

    private XFormsContainingDocument containingDocument;
    private Stack contextStack = new Stack();
    private XFormsFunction.Context functionContext;

    public XFormsContextStack(XFormsContainingDocument containingDocument) {
        this.containingDocument = containingDocument;
        this.functionContext = new XFormsFunction.Context(containingDocument, this);
    }

    public XFormsContextStack(XFormsModel containingModel) {
        this.containingDocument = containingModel.getContainingDocument();
        this.functionContext = new XFormsFunction.Context(containingModel, this);
    }

    public XFormsFunction.Context getFunctionContext() {
        return functionContext;
    }

    /**
     * Reset the binding context to the root of the first model's first instance.
     */
    public void resetBindingContext(PipelineContext pipelineContext) {
        resetBindingContext(pipelineContext, containingDocument.getDefaultModel());
    }

    /**
     * Reset the binding context to the root of the given model's first instance.
     */
    public void resetBindingContext(PipelineContext pipelineContext, XFormsModel xformsModel) {
        // Clear existing stack
        contextStack.clear();

        // Push the default context
        if (xformsModel.getInstanceCount() > 0) {
            final NodeInfo defaultNode = xformsModel.getDefaultInstance().getInstanceRootElementInfo();
            final List defaultNodeset = Arrays.asList(new Object[]{ defaultNode });
            contextStack.push(new BindingContext(null, xformsModel, defaultNodeset, 1, null, true, null, xformsModel.getDefaultInstance().getLocationData(), false, defaultNode));
        } else {
            contextStack.push(new BindingContext(null, xformsModel, Collections.EMPTY_LIST, 0, null, true, null, xformsModel.getLocationData(), false, null));
        }

        // Add model variables for default model
        addVariables(pipelineContext, getCurrentBindingContext(), xformsModel);
    }

    private void addVariables(PipelineContext pipelineContext, BindingContext bindingContext, XFormsModel xformsModel) {
        int variablesCount = 0;
        // TODO: Check dirty flag to prevent needless re-evaluation
        for (Iterator i = xformsModel.getModelDocument().getRootElement().elements("variable").iterator(); i.hasNext(); variablesCount++) {
            final Element currentVariableElement = (Element) i.next();

            // All variables in the model are in scope for the nested binds and actions.
            // NOTE: The value is computed immediately. We should use Expression objects and do lazy evaluation in the future.
            final Variable variable = new Variable(containingDocument, this, currentVariableElement);
            bindingContext.addVariable(variable.getVariableName(), variable.getVariableValue(pipelineContext, false));
        }

        if (variablesCount > 0 && XFormsServer.logger.isDebugEnabled())
            containingDocument.logDebug("model", "evaluated variables",
                    new String[] { "count", Integer.toString(variablesCount) });
    }

    /**
     * Set the binding context to the current control.
     *
     * @param xformsControl       control to bind
     */
    public void setBinding(XFormsControl xformsControl) {

        BindingContext controlBindingContext = xformsControl.getBindingContext();

        // Don't do the work if the current context is already as requested<commit_msg>Fixed NPE when no model is yet available.<commit_after>/**
 *  Copyright (C) 2008 Orbeon, Inc.
 *
 *  This program is free software; you can redistribute it and/or modify it under the terms of the
 *  GNU Lesser General Public License as published by the Free Software Foundation; either version
 *  2.1 of the License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *  See the GNU Lesser General Public License for more details.
 *
 *  The full text of the license is available at http://www.gnu.org/copyleft/lesser.html
 */
package org.orbeon.oxf.xforms;

import org.dom4j.Element;
import org.orbeon.oxf.common.OXFException;
import org.orbeon.oxf.common.ValidationException;
import org.orbeon.oxf.pipeline.api.PipelineContext;
import org.orbeon.oxf.util.XPathCache;
import org.orbeon.oxf.xforms.control.XFormsControl;
import org.orbeon.oxf.xforms.event.XFormsEventHandlerContainer;
import org.orbeon.oxf.xforms.function.XFormsFunction;
import org.orbeon.oxf.xforms.processor.XFormsServer;
import org.orbeon.oxf.xml.dom4j.ExtendedLocationData;
import org.orbeon.oxf.xml.dom4j.LocationData;
import org.orbeon.saxon.om.Item;
import org.orbeon.saxon.om.NodeInfo;
import org.orbeon.saxon.om.ValueRepresentation;

import java.util.*;

/**
 * Handle a stack of XPath evaluation context information. This can be used by controls, models, and actions.
 */
public class XFormsContextStack {

    private XFormsContainingDocument containingDocument;
    private Stack contextStack = new Stack();
    private XFormsFunction.Context functionContext;

    public XFormsContextStack(XFormsContainingDocument containingDocument) {
        this.containingDocument = containingDocument;
        this.functionContext = new XFormsFunction.Context(containingDocument, this);
    }

    public XFormsContextStack(XFormsModel containingModel) {
        this.containingDocument = containingModel.getContainingDocument();
        this.functionContext = new XFormsFunction.Context(containingModel, this);
    }

    public XFormsFunction.Context getFunctionContext() {
        return functionContext;
    }

    /**
     * Reset the binding context to the root of the first model's first instance.
     */
    public void resetBindingContext(PipelineContext pipelineContext) {
        resetBindingContext(pipelineContext, containingDocument.getDefaultModel());
    }

    /**
     * Reset the binding context to the root of the given model's first instance.
     */
    public void resetBindingContext(PipelineContext pipelineContext, XFormsModel xformsModel) {

        // Clear existing stack
        contextStack.clear();

        if (xformsModel != null && xformsModel.getInstanceCount() > 0) {
            // Push the default context
            final NodeInfo defaultNode = xformsModel.getDefaultInstance().getInstanceRootElementInfo();
            final List defaultNodeset = Arrays.asList(new Object[]{ defaultNode });
            contextStack.push(new BindingContext(null, xformsModel, defaultNodeset, 1, null, true, null, xformsModel.getDefaultInstance().getLocationData(), false, defaultNode));
        } else {
            // Push empty context
            contextStack.push(new BindingContext(null, xformsModel, Collections.EMPTY_LIST, 0, null, true, null, xformsModel.getLocationData(), false, null));
        }

        // Add model variables for default model
        if (xformsModel != null)
            addVariables(pipelineContext, getCurrentBindingContext(), xformsModel);
    }

    private void addVariables(PipelineContext pipelineContext, BindingContext bindingContext, XFormsModel xformsModel) {
        int variablesCount = 0;
        // TODO: Check dirty flag to prevent needless re-evaluation
        for (Iterator i = xformsModel.getModelDocument().getRootElement().elements("variable").iterator(); i.hasNext(); variablesCount++) {
            final Element currentVariableElement = (Element) i.next();

            // All variables in the model are in scope for the nested binds and actions.
            // NOTE: The value is computed immediately. We should use Expression objects and do lazy evaluation in the future.
            final Variable variable = new Variable(containingDocument, this, currentVariableElement);
            bindingContext.addVariable(variable.getVariableName(), variable.getVariableValue(pipelineContext, false));
        }

        if (variablesCount > 0 && XFormsServer.logger.isDebugEnabled())
            containingDocument.logDebug("model", "evaluated variables",
                    new String[] { "count", Integer.toString(variablesCount) });
    }

    /**
     * Set the binding context to the current control.
     *
     * @param xformsControl       control to bind
     */
    public void setBinding(XFormsControl xformsControl) {

        BindingContext controlBindingContext = xformsControl.getBindingContext();

        // Don't do the work if the current context is already as requested
{'fraction_non_alphanumeric': 0.08378672470076169, 'fraction_numerical': 0.0027698090810169156, 'mean_word_length': 3.5912806539509536, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 4}, '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': '673129', 'n_tokens_mistral': 2633, 'n_tokens_neox': 2556, 'n_words': 792}