<commit_before>﻿#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using DotVVM.Framework.Binding;
using DotVVM.Framework.Binding.Expressions;
using DotVVM.Framework.Configuration;
using DotVVM.Framework.Hosting;

namespace DotVVM.Framework.Controls
{
    public static class DotvvmBindableObjectHelper
    {
        public static DotvvmProperty GetDotvvmProperty<TControl, TProperty>(this TControl control, Expression<Func<TControl, TProperty>> prop)
            where TControl : DotvvmBindableObject
        {
            var property = (prop.Body as MemberExpression)?.Member as PropertyInfo;
            if (property == null) throw new Exception($"Expression '{prop}' should be property access on the specified control.");
            return DotvvmProperty.ResolveProperty(property.DeclaringType!, property.Name) ?? throw new Exception($"Property '{property.DeclaringType!.Name}.{property.Name}' is not a registered DotvvmProperty.");
        }
        public static DotvvmProperty GetDotvvmProperty<TControl>(this TControl control, string propName)
            where TControl : DotvvmBindableObject
        {
            return DotvvmProperty.ResolveProperty(typeof(TControl), propName) ?? throw new Exception($"Property '{typeof(TControl)}.{propName}' is not a registered DotvvmProperty.");
        }

        public static TControl SetProperty<TControl, TProperty>(this TControl control, Expression<Func<TControl, TProperty>> prop, IBinding? binding)
            where TControl : DotvvmBindableObject
        {
            control.SetBinding(control.GetDotvvmProperty(prop), binding);
            return control;
        }

        public static TControl SetProperty<TControl, TProperty>(this TControl control, DotvvmProperty prop, IBinding? binding)
            where TControl : DotvvmBindableObject
        {
            control.SetBinding(prop, binding);
            return control;
        }
        public static TControl SetProperty<TControl>(this TControl control, string propName, IBinding? binding)
            where TControl : DotvvmBindableObject
        {
            control.SetBinding(control.GetDotvvmProperty(propName), binding);
            return control;
        }

        public static TControl SetProperty<TControl, TProperty>(this TControl control, Expression<Func<TControl, TProperty>> prop, TProperty value)
            where TControl : DotvvmBindableObject
        {
            control.SetValue(control.GetDotvvmProperty(prop), value);
            return control;
        }

        public static TControl SetProperty<TControl, TProperty>(this TControl control, Expression<Func<TControl, TProperty>> prop, ValueOrBinding<TProperty> value)
            where TControl : DotvvmBindableObject
        {
            control.SetValue(control.GetDotvvmProperty(prop), value);
            return control;
        }
        public static TControl SetProperty<TControl, TProperty>(this TControl control, string propName, ValueOrBinding<TProperty> valueOrBinding)
            where TControl : DotvvmBindableObject
        {
            control.SetProperty(control.GetDotvvmProperty(propName), valueOrBinding);
            return control;
        }

        public static TControl SetProperty<TControl, TProperty>(this TControl control, DotvvmProperty property, ValueOrBinding<TProperty> valueOrBinding)
            where TControl: DotvvmBindableObject
        {
            if (valueOrBinding.BindingOrDefault == null)
                control.SetValue(property, valueOrBinding.BoxedValue);
            else
                control.SetBinding(property, valueOrBinding.BindingOrDefault);
            return control;
        }

        public static TControl SetProperty<TControl, TProperty>(this TControl control, DotvvmProperty property, ValueOrBinding<TProperty>? valueOrBinding)
            where TControl: DotvvmBindableObject
        {
            if (valueOrBinding.HasValue)
                control.SetProperty(property, valueOrBinding.GetValueOrDefault());
            else
                control.SetValue(property, null);
            return control;
        }

        public static TControl SetProperty<TControl>(this TControl control, DotvvmProperty property, object value)
            where TControl: DotvvmBindableObject
        {
            control.SetValue(property, value);
            return control;
        }
        public static TControl SetProperty<TControl, TProperty>(this TControl control, string propName, object value)
            where TControl : DotvvmBindableObject
        {
            control.SetValue(control.GetDotvvmProperty(propName), value);
            return control;
        }

        public static TControl SetProperty<TControl, TProperty>(this TControl control, Func<TControl, VirtualPropertyGroupDictionary<TProperty>> prop, string key, IBinding? binding)
            where TControl : DotvvmBindableObject
        {
            var d = prop(control);
            d.AddBinding(key, binding);
            return control;
        }

        public static TControl SetProperty<TControl, TProperty>(this TControl control, Func<TControl, VirtualPropertyGroupDictionary<TProperty>> prop, string key, TProperty value)
            where TControl : DotvvmBindableObject
        {
            var d = prop(control);
            d.Add(key, value);
            return control;
        }

        public static TControl SetProperty<TControl, TProperty>(this TControl control, Func<TControl, VirtualPropertyGroupDictionary<TProperty>> prop, string key, ValueOrBinding<TProperty> value)
            where TControl : DotvvmBindableObject
        {
            var d = prop(control);
            d.Add(key, value);
            return control;
        }

        public static TControl SetAttribute<TControl>(this TControl control, string attribute, object value)
            where TControl : IControlWithHtmlAttributes
        {
            if (value is ValueOrBinding vob)
            {
                control.Attributes[attribute] = vob.BindingOrDefault ?? vob.BoxedValue;
            }
            else
            {
                control.Attributes[attribute] = value;
            }
            return control;
        }
        public static TControl SetAttribute<TControl, TProperty>(this TControl control, string attribute, ValueOrBinding<TProperty> value)
            where TControl : IControlWithHtmlAttributes
        {
            control.Attributes[attribute] = value.BindingOrDefault ?? value.BoxedValue;
            return control;
        }

        public static TControl SetCapability<TControl, TCapability>(this TControl control, [AllowNull] TCapability capability, string prefix = "")
            where TControl: DotvvmBindableObject
        {
            if (capability != null)
            {
                var c = DotvvmCapabilityProperty.Find(typeof(TControl), typeof(TCapability), prefix);
                if (c is null)
                    throw new Exception($"Capability {prefix}{typeof(TCapability)} is not defined on {typeof(TControl)}");
                c.SetValue(control, capability);
            }
            return control;
        }

        public static IValueBinding<TProperty>? GetValueBinding<TControl, TProperty>(this TControl control, Expression<Func<TControl, TProperty>> prop)
            where TControl : DotvvmBindableObject
            => (IValueBinding<TProperty>?)control.GetValueBinding(control.GetDotvvmProperty(prop));

        public static ICommandBinding<TProperty>? GetCommandBinding<TControl, TProperty>(this TControl control, Expression<Func<TControl, TProperty>> prop)<commit_msg>Updated helper extension methods for DotvvmBindableObject to ignore null values<commit_after>﻿#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using DotVVM.Framework.Binding;
using DotVVM.Framework.Binding.Expressions;
using DotVVM.Framework.Configuration;
using DotVVM.Framework.Hosting;

namespace DotVVM.Framework.Controls
{
    public static class DotvvmBindableObjectHelper
    {
        public static DotvvmProperty GetDotvvmProperty<TControl, TProperty>(this TControl control, Expression<Func<TControl, TProperty>> prop)
            where TControl : DotvvmBindableObject
        {
            var property = (prop.Body as MemberExpression)?.Member as PropertyInfo;
            if (property == null) throw new Exception($"Expression '{prop}' should be property access on the specified control.");
            return DotvvmProperty.ResolveProperty(property.DeclaringType!, property.Name) ?? throw new Exception($"Property '{property.DeclaringType!.Name}.{property.Name}' is not a registered DotvvmProperty.");
        }
        public static DotvvmProperty GetDotvvmProperty<TControl>(this TControl control, string propName)
            where TControl : DotvvmBindableObject
        {
            return DotvvmProperty.ResolveProperty(typeof(TControl), propName) ?? throw new Exception($"Property '{typeof(TControl)}.{propName}' is not a registered DotvvmProperty.");
        }

        public static TControl SetProperty<TControl, TProperty>(this TControl control, Expression<Func<TControl, TProperty>> prop, IBinding? binding)
            where TControl : DotvvmBindableObject
        {
            control.SetBinding(control.GetDotvvmProperty(prop), binding);
            return control;
        }

        public static TControl SetProperty<TControl, TProperty>(this TControl control, DotvvmProperty prop, IBinding? binding)
            where TControl : DotvvmBindableObject
        {
            control.SetBinding(prop, binding);
            return control;
        }
        public static TControl SetProperty<TControl>(this TControl control, string propName, IBinding? binding)
            where TControl : DotvvmBindableObject
        {
            control.SetBinding(control.GetDotvvmProperty(propName), binding);
            return control;
        }

        public static TControl SetProperty<TControl, TProperty>(this TControl control, Expression<Func<TControl, TProperty>> prop, TProperty value)
            where TControl : DotvvmBindableObject
        {
            control.SetValue(control.GetDotvvmProperty(prop), value);
            return control;
        }

        public static TControl SetProperty<TControl, TProperty>(this TControl control, Expression<Func<TControl, TProperty>> prop, ValueOrBinding<TProperty> value)
            where TControl : DotvvmBindableObject
        {
            control.SetValue(control.GetDotvvmProperty(prop), value);
            return control;
        }
        public static TControl SetProperty<TControl, TProperty>(this TControl control, string propName, ValueOrBinding<TProperty> valueOrBinding)
            where TControl : DotvvmBindableObject
        {
            control.SetProperty(control.GetDotvvmProperty(propName), valueOrBinding);
            return control;
        }

        public static TControl SetProperty<TControl, TProperty>(this TControl control, DotvvmProperty property, ValueOrBinding<TProperty> valueOrBinding)
            where TControl: DotvvmBindableObject
        {
            if (valueOrBinding.BindingOrDefault == null)
                control.SetValue(property, valueOrBinding.BoxedValue);
            else
                control.SetBinding(property, valueOrBinding.BindingOrDefault);
            return control;
        }

        public static TControl SetProperty<TControl, TProperty>(this TControl control, DotvvmProperty property, ValueOrBinding<TProperty>? valueOrBinding)
            where TControl: DotvvmBindableObject
        {
            if (valueOrBinding.HasValue)
                control.SetProperty(property, valueOrBinding.GetValueOrDefault());
            else
                control.Properties.Remove(property);
            return control;
        }

        public static TControl SetProperty<TControl>(this TControl control, DotvvmProperty property, object value)
            where TControl: DotvvmBindableObject
        {
            control.SetValue(property, value);
            return control;
        }
        public static TControl SetProperty<TControl, TProperty>(this TControl control, string propName, object value)
            where TControl : DotvvmBindableObject
        {
            control.SetValue(control.GetDotvvmProperty(propName), value);
            return control;
        }

        public static TControl SetProperty<TControl, TProperty>(this TControl control, Func<TControl, VirtualPropertyGroupDictionary<TProperty>> prop, string key, IBinding? binding)
            where TControl : DotvvmBindableObject
        {
            var d = prop(control);
            d.AddBinding(key, binding);
            return control;
        }

        public static TControl SetProperty<TControl, TProperty>(this TControl control, Func<TControl, VirtualPropertyGroupDictionary<TProperty>> prop, string key, TProperty value)
            where TControl : DotvvmBindableObject
        {
            var d = prop(control);
            d.Add(key, value);
            return control;
        }

        public static TControl SetProperty<TControl, TProperty>(this TControl control, Func<TControl, VirtualPropertyGroupDictionary<TProperty>> prop, string key, ValueOrBinding<TProperty> value)
            where TControl : DotvvmBindableObject
        {
            var d = prop(control);
            d.Add(key, value);
            return control;
        }

        public static TControl SetAttribute<TControl>(this TControl control, string attribute, object? value)
            where TControl : IControlWithHtmlAttributes
        {
            if (value is ValueOrBinding vob)
            {
                return SetAttribute(control, attribute, vob.BindingOrDefault ?? vob.BoxedValue);
            }

            if (value is not null)
            {
                control.Attributes[attribute] = value;
            }
            else
            {
                control.Attributes.Remove(attribute);
            }
            return control;
        }

        public static TControl SetAttribute<TControl, TProperty>(this TControl control, string attribute, ValueOrBinding<TProperty> value)
            where TControl : IControlWithHtmlAttributes
        {
            return SetAttribute(control, attribute, value.BindingOrDefault ?? value.BoxedValue);
        }

        public static TControl SetAttribute<TControl, TProperty>(this TControl control, string attribute, ValueOrBinding<TProperty>? value)
            where TControl : IControlWithHtmlAttributes
        {
            return SetAttribute(control, attribute, value?.BindingOrDefault ?? value?.BoxedValue);
        }

        public static TControl SetCapability<TControl, TCapability>(this TControl control, [AllowNull] TCapability capability, string prefix = "")
            where TControl: DotvvmBindableObject
        {
            if (capability != null)
            {
                var c = DotvvmCapabilityProperty.Find(typeof(TControl), typeof(TCapability), prefix);
                if (c is null)
                    throw new Exception($"Capability {prefix}{typeof(TCapability)} is not defined on {typeof(TControl)}");
                c.SetValue(control, capability);
            }
            return control;
        }

        public static T AppendChildren<T>(this T control, IEnumerable<DotvvmControl>? children) where T : DotvvmControl 
        {
            if (children != null)
            {
                foreach (var child in children)
                {
                    control.Children.Add(child);
                }
            }

            return control;
        }

        public static IValueBinding<TProperty>? GetValueBinding<TControl, TProperty>(this TControl control, Expression<Func<TControl, TProperty>> prop)
            where TControl : DotvvmBindableObject
            => (IValueBinding<TProperty>?)control.GetValueBinding(control.GetDotvvmProperty(prop));

        public static ICommandBinding<TProperty>? GetCommandBinding<TControl, TProperty>(this TControl control, Expression<Func<TControl, TProperty>> prop)
{'fraction_non_alphanumeric': 0.07599583919720981, 'fraction_numerical': 0.0, 'mean_word_length': 2.6719838238598066, 'pattern_counts': {'":': 0, '<': 101, '<?xml version=': 0, '>': 103, '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': '5393884', 'n_tokens_mistral': 4076, 'n_tokens_neox': 3956, 'n_words': 1002}