<commit_before>using DotVVM.Framework.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DotVVM.Framework.Binding.Expressions;
using DotVVM.Framework.Compilation.Javascript;
using DotVVM.Framework.Compilation.Javascript.Ast;
using DotVVM.Framework.Binding.Properties;
using DotVVM.Framework.Compilation.ControlTree;
using System.Collections.Concurrent;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
using DotVVM.Framework.Compilation.ControlTree.Resolved;

namespace DotVVM.Framework.Binding
{
    public static partial class BindingHelper
    {
        public static T GetProperty<T>(this IBinding binding, ErrorHandlingMode errorMode = ErrorHandlingMode.ThrowException) => (T)binding.GetProperty(typeof(T), errorMode);

        [Obsolete]
        public static string GetKnockoutBindingExpression(this IValueBinding binding) =>
            JavascriptTranslator.FormatKnockoutScript(binding.KnockoutExpression);
        /// <summary>
        /// Gets the javascript translation of the binding adjusted to the `currentControl`s DataContext
        /// </summary>
        public static string GetKnockoutBindingExpression(this IValueBinding binding, DotvvmBindableObject currentControl, bool unwrapped = false) =>
            (unwrapped ? binding.UnwrappedKnockoutExpression : binding.KnockoutExpression)
            .FormatKnockoutScript(currentControl, binding);

        /// <summary>
        /// Gets the javascript translation of the binding adjusted to the `currentControl`s DataContext, returned value is ParametrizedCode, so it can be further adjusted
        /// </summary>
        public static ParametrizedCode GetParametrizedKnockoutExpression(this IValueBinding binding, DotvvmBindableObject currentControl, bool unwrapped = false) =>
            JavascriptTranslator.AdjustKnockoutScriptContext(unwrapped ? binding.UnwrappedKnockoutExpression : binding.KnockoutExpression, dataContextLevel: FindDataContextTarget(binding, currentControl).stepsUp);

        /// <summary>
        /// Adjusts the knockout expression to `currentControl`s DataContext like it was translated in `currentBinding`s context
        /// </summary>
        public static string FormatKnockoutScript(this ParametrizedCode code, DotvvmBindableObject currentControl, IBinding currentBinding) =>
            JavascriptTranslator.FormatKnockoutScript(code, dataContextLevel: FindDataContextTarget(currentBinding, currentControl).stepsUp);

        /// <summary>
        /// Gets Internal.PathFragmentProperty or DataContext.KnockoutExpression
        /// </summary>
        public static string GetDataContextPathFragment(this DotvvmBindableObject currentControl) =>
            (string)currentControl.GetValue(Internal.PathFragmentProperty, inherit: false) ??
            (currentControl.GetBinding(DotvvmBindableObject.DataContextProperty, inherit: false) is IValueBinding binding ?
                binding.GetProperty<SimplePathExpressionBindingProperty>(ErrorHandlingMode.ThrowException)
                .Code.FormatKnockoutScript(currentControl, binding) :
            null);


        // PERF: maybe safe last GetValue's target/binding to ThreadLocal variable, so the path does not have to be traversed twice
        /// <summary>
        /// Finds expected context control of the `binding` and returns (parent index of the correct DataContext, control in the corrent context)
        /// </summary>
        public static (int stepsUp, DotvvmBindableObject target) FindDataContextTarget(this IBinding binding, DotvvmBindableObject control)
        {
            if (control == null) throw new InvalidOperationException($"Can not evaluate binding without any dataContext.");
            var controlContext = (DataContextStack)control.GetValue(Internal.DataContextTypeProperty);
            var bindingContext = binding.GetProperty<DataContextStack>(ErrorHandlingMode.ReturnNull);
            if (bindingContext == null || controlContext == null || controlContext.Equals(bindingContext)) return (0, control);

            var changes = 0;
            foreach (var a in control.GetAllAncestors(incudingThis: true))
            {
                if (bindingContext.Equals(a.GetValue(Internal.DataContextTypeProperty, inherit: false)))
                    return (changes, a);

                if (a.properties.ContainsKey(DotvvmBindableObject.DataContextProperty)) changes++;
            }

            throw new NotSupportedException($"Could not find DataContextSpace of binding '{binding}'.");
        }

        /// <summary>
        /// Prepares DataContext hierarchy argument and executes update delegate.
        /// </summary>
        public static void ExecUpdateDelegate(this BindingUpdateDelegate func, DotvvmBindableObject contextControl, object value)
        {
            var dataContexts = GetDataContexts(contextControl);
            //var control = contextControl.GetClosestControlBindingTarget();
            func(dataContexts.ToArray(), contextControl, value);
        }

        /// <summary><commit_msg>fix null reference expcetion in FindDataContextTarget<commit_after>using DotVVM.Framework.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DotVVM.Framework.Binding.Expressions;
using DotVVM.Framework.Compilation.Javascript;
using DotVVM.Framework.Compilation.Javascript.Ast;
using DotVVM.Framework.Binding.Properties;
using DotVVM.Framework.Compilation.ControlTree;
using System.Collections.Concurrent;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
using DotVVM.Framework.Compilation.ControlTree.Resolved;

namespace DotVVM.Framework.Binding
{
    public static partial class BindingHelper
    {
        public static T GetProperty<T>(this IBinding binding, ErrorHandlingMode errorMode = ErrorHandlingMode.ThrowException) => (T)binding.GetProperty(typeof(T), errorMode);

        [Obsolete]
        public static string GetKnockoutBindingExpression(this IValueBinding binding) =>
            JavascriptTranslator.FormatKnockoutScript(binding.KnockoutExpression);
        /// <summary>
        /// Gets the javascript translation of the binding adjusted to the `currentControl`s DataContext
        /// </summary>
        public static string GetKnockoutBindingExpression(this IValueBinding binding, DotvvmBindableObject currentControl, bool unwrapped = false) =>
            (unwrapped ? binding.UnwrappedKnockoutExpression : binding.KnockoutExpression)
            .FormatKnockoutScript(currentControl, binding);

        /// <summary>
        /// Gets the javascript translation of the binding adjusted to the `currentControl`s DataContext, returned value is ParametrizedCode, so it can be further adjusted
        /// </summary>
        public static ParametrizedCode GetParametrizedKnockoutExpression(this IValueBinding binding, DotvvmBindableObject currentControl, bool unwrapped = false) =>
            JavascriptTranslator.AdjustKnockoutScriptContext(unwrapped ? binding.UnwrappedKnockoutExpression : binding.KnockoutExpression, dataContextLevel: FindDataContextTarget(binding, currentControl).stepsUp);

        /// <summary>
        /// Adjusts the knockout expression to `currentControl`s DataContext like it was translated in `currentBinding`s context
        /// </summary>
        public static string FormatKnockoutScript(this ParametrizedCode code, DotvvmBindableObject currentControl, IBinding currentBinding) =>
            JavascriptTranslator.FormatKnockoutScript(code, dataContextLevel: FindDataContextTarget(currentBinding, currentControl).stepsUp);

        /// <summary>
        /// Gets Internal.PathFragmentProperty or DataContext.KnockoutExpression
        /// </summary>
        public static string GetDataContextPathFragment(this DotvvmBindableObject currentControl) =>
            (string)currentControl.GetValue(Internal.PathFragmentProperty, inherit: false) ??
            (currentControl.GetBinding(DotvvmBindableObject.DataContextProperty, inherit: false) is IValueBinding binding ?
                binding.GetProperty<SimplePathExpressionBindingProperty>(ErrorHandlingMode.ThrowException)
                .Code.FormatKnockoutScript(currentControl, binding) :
            null);


        // PERF: maybe safe last GetValue's target/binding to ThreadLocal variable, so the path does not have to be traversed twice
        /// <summary>
        /// Finds expected context control of the `binding` and returns (parent index of the correct DataContext, control in the corrent context)
        /// </summary>
        public static (int stepsUp, DotvvmBindableObject target) FindDataContextTarget(this IBinding binding, DotvvmBindableObject control)
        {
            if (control == null) throw new InvalidOperationException($"Can not evaluate binding without any dataContext.");
            var controlContext = (DataContextStack)control.GetValue(Internal.DataContextTypeProperty);
            var bindingContext = binding.GetProperty<DataContextStack>(ErrorHandlingMode.ReturnNull);
            if (bindingContext == null || controlContext == null || controlContext.Equals(bindingContext)) return (0, control);

            var changes = 0;
            foreach (var a in control.GetAllAncestors(incudingThis: true))
            {
                if (bindingContext.Equals(a.GetValue(Internal.DataContextTypeProperty, inherit: false)))
                    return (changes, a);

                if (a.properties != null && a.properties.ContainsKey(DotvvmBindableObject.DataContextProperty)) changes++;
            }

            throw new NotSupportedException($"Could not find DataContextSpace of binding '{binding}'.");
        }

        /// <summary>
        /// Prepares DataContext hierarchy argument and executes update delegate.
        /// </summary>
        public static void ExecUpdateDelegate(this BindingUpdateDelegate func, DotvvmBindableObject contextControl, object value)
        {
            var dataContexts = GetDataContexts(contextControl);
            //var control = contextControl.GetClosestControlBindingTarget();
            func(dataContexts.ToArray(), contextControl, value);
        }

        /// <summary>
{'fraction_non_alphanumeric': 0.08056365403304179, 'fraction_numerical': 0.00038872691933916425, 'mean_word_length': 3.5555555555555554, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 47, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '3216873', 'n_tokens_mistral': 2579, 'n_tokens_neox': 2448, 'n_words': 644}