<commit_before>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;
using System.Linq.Expressions;
using System.Globalization;
using System.ComponentModel;
using DynamicExpresso;

namespace CalcBinding
{
    /// <summary>
    /// Binding with advantages
    /// </summary>
    public class Binding : MarkupExtension
    {
        public String Path { get; set; }

        /// <summary>
        /// False to visibility. Default: False = Collapsed
        /// </summary>
        public FalseToVisibility FalseToVisibility 
        {
            get { return falseToVisibility; }
            set { falseToVisibility = value; }
        }
        private FalseToVisibility falseToVisibility = FalseToVisibility.Collapsed;

        public Binding()
        {

        }

        public Binding(String path)
        {
            Path = path;
        }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            //provider with reflection of binding and target object
            var providerValuetarget = (IProvideValueTarget)serviceProvider
              .GetService(typeof(IProvideValueTarget));
      
            Type propertyType;
            if (providerValuetarget.TargetProperty is DependencyProperty)
            {
                propertyType = ((DependencyProperty)providerValuetarget.TargetProperty).PropertyType;
            }
            else
            {
                propertyType = providerValuetarget.TargetProperty.GetType();
            }

            var normPath = normalizePath(Path);
            var pathsList = getPathes(normPath);
            
            var uniquePathList = pathsList
                .Select(path => path.Item1)
                .ToList();

            // logic critical code: order of params must be only {0}..{1}..{2} etc, 
            // and not another. We can't unsynchronize order of parameters[] and params occure
            // in expression template (bug 3).
            // There is an example in description of bug 3 in bug tracker
            var orderedPathes = uniquePathList
                .Select((path, index) => new Tuple<string, int>(path, index))
                .OrderByDescending(path => path.Item1.Length).ToList();

            var exprTemplate = normPath;

            //bug detected: Math.Abs(A) => replace A -> a => Math.abs(A), 
            // not resolved
            exprTemplate = getNormExprTemplate(exprTemplate, orderedPathes, pathsList);

            // end of critical code
            //exprTemplate = "{1} {2} {0}" (AA C BBB)
            var mathConverter = new CalcConverter
            {
                FalseToVisibility = FalseToVisibility,
                StringFormatDefined = StringFormat != null
            };

            BindingBase resBinding;

            // possibility of twoway mode. Out of the box it is only 
            // one variable or negative from bool variable
            if (uniquePathList.Count() == 1)
            {
                var binding = new System.Windows.Data.Binding(uniquePathList.Single())
                {
                    Mode = Mode,
                    NotifyOnSourceUpdated = NotifyOnSourceUpdated,
                    NotifyOnTargetUpdated = NotifyOnTargetUpdated,
                    NotifyOnValidationError = NotifyOnValidationError,
                    UpdateSourceExceptionFilter = UpdateSourceExceptionFilter,
                    UpdateSourceTrigger = UpdateSourceTrigger,
                    ValidatesOnDataErrors = ValidatesOnDataErrors,
                    ValidatesOnExceptions = ValidatesOnExceptions,
                    ValidatesOnNotifyDataErrors = ValidatesOnNotifyDataErrors,
                };

                if (Source != null)
                    binding.Source = Source;

                if (ElementName != null)
                    binding.ElementName = ElementName;

                if (RelativeSource != null)
                    binding.RelativeSource = RelativeSource;

                if (StringFormat != null)
                    binding.StringFormat = StringFormat;

                // we don't use converter if binding is trivial - {0}, except type convertion from bool to visibility
                if (exprTemplate != "{0}" || propertyType == typeof(Visibility))
                {
                    binding.Converter = mathConverter;
                    binding.ConverterParameter = exprTemplate;
                    binding.ConverterCulture = ConverterCulture;
                }
                resBinding = binding;
            }
            else
            {
                var mBinding = new MultiBinding
                {
                    Converter = mathConverter,
                    ConverterParameter = exprTemplate,
                    ConverterCulture = ConverterCulture,
                    Mode = BindingMode.OneWay,
                    NotifyOnSourceUpdated = NotifyOnSourceUpdated,
                    NotifyOnTargetUpdated = NotifyOnTargetUpdated,
                    NotifyOnValidationError = NotifyOnValidationError,
                    UpdateSourceExceptionFilter = UpdateSourceExceptionFilter,
                    UpdateSourceTrigger = UpdateSourceTrigger,
                    ValidatesOnDataErrors = ValidatesOnDataErrors,
                    ValidatesOnExceptions = ValidatesOnExceptions,
                    ValidatesOnNotifyDataErrors = ValidatesOnNotifyDataErrors,
                };

                if (StringFormat != null)
                    mBinding.StringFormat = StringFormat;

                foreach (var path in uniquePathList)
                {
                    var binding = new System.Windows.Data.Binding(path);

                    if (Source != null)
                        binding.Source = Source;

                    if (ElementName != null)
                        binding.ElementName = ElementName;

                    mBinding.Bindings.Add(binding);
                }

                resBinding = mBinding;
            }
            
            return resBinding.ProvideValue(serviceProvider);
        }

        private string getNormExprTemplate(string source, List<Tuple<string, int>> orderedPathes, List<Tuple<string, List<int>>> pathsList)
        {
            var result = "";
            var sourceIndex = 0;

            while (sourceIndex < source.Length)<commit_msg>#9 relativeSource support<commit_after>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;
using System.Linq.Expressions;
using System.Globalization;
using System.ComponentModel;
using DynamicExpresso;

namespace CalcBinding
{
    /// <summary>
    /// Binding with advantages
    /// </summary>
    public class Binding : MarkupExtension
    {
        public String Path { get; set; }

        /// <summary>
        /// False to visibility. Default: False = Collapsed
        /// </summary>
        public FalseToVisibility FalseToVisibility 
        {
            get { return falseToVisibility; }
            set { falseToVisibility = value; }
        }
        private FalseToVisibility falseToVisibility = FalseToVisibility.Collapsed;

        public Binding()
        {

        }

        public Binding(String path)
        {
            Path = path;
        }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            //provider with reflection of binding and target object
            var providerValuetarget = (IProvideValueTarget)serviceProvider
              .GetService(typeof(IProvideValueTarget));
      
            Type propertyType;
            if (providerValuetarget.TargetProperty is DependencyProperty)
            {
                propertyType = ((DependencyProperty)providerValuetarget.TargetProperty).PropertyType;
            }
            else
            {
                propertyType = providerValuetarget.TargetProperty.GetType();
            }

            var normPath = normalizePath(Path);
            var pathsList = getPathes(normPath);
            
            var uniquePathList = pathsList
                .Select(path => path.Item1)
                .ToList();

            // logic critical code: order of params must be only {0}..{1}..{2} etc, 
            // and not another. We can't unsynchronize order of parameters[] and params occure
            // in expression template (bug 3).
            // There is an example in description of bug 3 in bug tracker
            var orderedPathes = uniquePathList
                .Select((path, index) => new Tuple<string, int>(path, index))
                .OrderByDescending(path => path.Item1.Length).ToList();

            var exprTemplate = normPath;

            //bug detected: Math.Abs(A) => replace A -> a => Math.abs(A), 
            // not resolved
            exprTemplate = getNormExprTemplate(exprTemplate, orderedPathes, pathsList);

            // end of critical code
            //exprTemplate = "{1} {2} {0}" (AA C BBB)
            var mathConverter = new CalcConverter
            {
                FalseToVisibility = FalseToVisibility,
                StringFormatDefined = StringFormat != null
            };

            BindingBase resBinding;

            // possibility of twoway mode. Out of the box it is only 
            // one variable or negative from bool variable
            if (uniquePathList.Count() == 1)
            {
                var binding = new System.Windows.Data.Binding(uniquePathList.Single())
                {
                    Mode = Mode,
                    NotifyOnSourceUpdated = NotifyOnSourceUpdated,
                    NotifyOnTargetUpdated = NotifyOnTargetUpdated,
                    NotifyOnValidationError = NotifyOnValidationError,
                    UpdateSourceExceptionFilter = UpdateSourceExceptionFilter,
                    UpdateSourceTrigger = UpdateSourceTrigger,
                    ValidatesOnDataErrors = ValidatesOnDataErrors,
                    ValidatesOnExceptions = ValidatesOnExceptions,
                    ValidatesOnNotifyDataErrors = ValidatesOnNotifyDataErrors,
                };

                if (Source != null)
                    binding.Source = Source;

                if (ElementName != null)
                    binding.ElementName = ElementName;

                if (RelativeSource != null)
                    binding.RelativeSource = RelativeSource;

                if (StringFormat != null)
                    binding.StringFormat = StringFormat;

                // we don't use converter if binding is trivial - {0}, except type convertion from bool to visibility
                if (exprTemplate != "{0}" || propertyType == typeof(Visibility))
                {
                    binding.Converter = mathConverter;
                    binding.ConverterParameter = exprTemplate;
                    binding.ConverterCulture = ConverterCulture;
                }
                resBinding = binding;
            }
            else
            {
                var mBinding = new MultiBinding
                {
                    Converter = mathConverter,
                    ConverterParameter = exprTemplate,
                    ConverterCulture = ConverterCulture,
                    Mode = BindingMode.OneWay,
                    NotifyOnSourceUpdated = NotifyOnSourceUpdated,
                    NotifyOnTargetUpdated = NotifyOnTargetUpdated,
                    NotifyOnValidationError = NotifyOnValidationError,
                    UpdateSourceExceptionFilter = UpdateSourceExceptionFilter,
                    UpdateSourceTrigger = UpdateSourceTrigger,
                    ValidatesOnDataErrors = ValidatesOnDataErrors,
                    ValidatesOnExceptions = ValidatesOnExceptions,
                    ValidatesOnNotifyDataErrors = ValidatesOnNotifyDataErrors,
                };

                if (StringFormat != null)
                    mBinding.StringFormat = StringFormat;

                foreach (var path in uniquePathList)
                {
                    var binding = new System.Windows.Data.Binding(path);

                    if (Source != null)
                        binding.Source = Source;

                    if (ElementName != null)
                        binding.ElementName = ElementName;

                    if (RelativeSource != null)
                        binding.RelativeSource = RelativeSource;

                    mBinding.Bindings.Add(binding);
                }

                resBinding = mBinding;
            }
            
            return resBinding.ProvideValue(serviceProvider);
        }

        private string getNormExprTemplate(string source, List<Tuple<string, int>> orderedPathes, List<Tuple<string, List<int>>> pathsList)
        {
            var result = "";
            var sourceIndex = 0;

            while (sourceIndex < source.Length)
{'fraction_non_alphanumeric': 0.07059359344162745, 'fraction_numerical': 0.0022013056019432216, 'mean_word_length': 1.592483274301456, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 35, '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': '5970934', 'n_tokens_mistral': 3070, 'n_tokens_neox': 2820, 'n_words': 740}