<commit_before>﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace NDProperty
{
    public static partial class PropertyRegistar
    {

        private static readonly Dictionary<Type, List<IInternalNDReadOnlyProperty>> inheritedPropertys = new Dictionary<Type, List<IInternalNDReadOnlyProperty>>();

        public static NDProperty<TValue, TType> Register<TValue, TType>(Func<TType, OnChanged<TValue>> changedMethod, bool inherited, NullTreatment nullTreatment, bool isParent) where TType : class
        {
            var p = new NDProperty<TValue, TType>(changedMethod, inherited, nullTreatment);
            if (p.Inherited)
            {
                if (!inheritedPropertys.ContainsKey(typeof(TType)))
                    inheritedPropertys.Add(typeof(TType), new List<IInternalNDReadOnlyProperty>());
                inheritedPropertys[typeof(TType)].Add(p);
            }
            if (isParent)
                AddParentHandler(p);

            return p;
        }
        public static NDAttachedProperty<TValue, TType> RegisterAttached<TValue, TType>(OnChanged<TValue, TType> changedMethod, bool inherited, NullTreatment nullTreatment, bool isParent) where TType : class
        {
            var p = new NDAttachedProperty<TValue, TType>(changedMethod, inherited, nullTreatment);
            if (p.Inherited)
            {
                if (!inheritedPropertys.ContainsKey(typeof(TType)))
                    inheritedPropertys.Add(typeof(TType), new List<IInternalNDReadOnlyProperty>());
                inheritedPropertys[typeof(TType)].Add(p);
            }
            if (isParent)
                AddParentHandler(p);

            return p;
        }

        private static void AddParentHandler<TValue, TType>(NDReadOnlyProperty<TValue, TType> p) where TType : class
        {
            AddEventHandler(p, (sender, e) =>
            {
                var tree = Tree.GetTree(e.ChangedObject);
                var affectedItems = new List<(object affectedObject, object oldValue, IInternalNDReadOnlyProperty affectedProperty)>();
                if (inheritedPropertys.Count != 0)
                {
                    // Get all affacted decendents
                    Queue<Tree> queue = new Queue<Tree>();
                    queue.Enqueue(tree);

                    while (queue.Count != 0)
                    {
                        tree = queue.Dequeue();
                        if (inheritedPropertys.ContainsKey(tree.Current.GetType()))
                        {
                            foreach (var affectedProperty in inheritedPropertys[tree.Current.GetType()])
                                affectedItems.Add((tree.Current, affectedProperty.GetValue(tree.Current), affectedProperty));
                        }
                        foreach (var child in tree.Childrean)
                            queue.Enqueue(child);
                    }

                    // reset tree to its original value
                    tree = Tree.GetTree(e.ChangedObject);
                }
                System.Diagnostics.Debug.Assert(Equals(tree.Parent?.Current, e.OldValue));

                if (tree.Parent != null)
                    tree.Parent.Childrean.Remove(tree);

                tree.Parent = Tree.GetTree(e.NewValue);

                if (tree.Parent != null)
                    tree.Parent.Childrean.Add(tree);

                // Notify AffectedItems
                foreach (var item in affectedItems)
                {
                    var newValue = item.affectedProperty.GetValue(item.affectedObject);
                    if (newValue != item.oldValue)
                        item.affectedProperty.CallChangeHandler(item.affectedObject, sender, item.oldValue, newValue);
                }
            });
        }

        public static void SetValue<TValue, TType>(NDProperty<TValue, TType> property, TType changedObject, TValue value) where TType : class
        {
            var oldValue = GetValue(property, changedObject);
            var onChangedArg = OnChangedArg.Create(oldValue, value);
            property.changedMethod(changedObject)(onChangedArg);
            SetValueInternal(property, changedObject, value, onChangedArg);
        }
        public static void SetValue<TValue, TType>(NDAttachedProperty<TValue, TType> property, TType changedObject, TValue value) where TType : class
        {
            var oldValue = GetValue(property, changedObject);
            var onChangedArg = OnChangedArg.Create(changedObject, oldValue, value);
            property.changedMethod(onChangedArg);
            SetValueInternal(property, changedObject, value, onChangedArg);
        }

        private static void SetValueInternal<TValue, TType>(NDReadOnlyProperty<TValue, TType> property, TType obj, TValue value, OnChangedArg<TValue> onChangedArg) where TType : class
        {<commit_msg>Allow Change Handler to Mutate Value<commit_after>﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace NDProperty
{
    public static partial class PropertyRegistar
    {

        private static readonly Dictionary<Type, List<IInternalNDReadOnlyProperty>> inheritedPropertys = new Dictionary<Type, List<IInternalNDReadOnlyProperty>>();

        public static NDProperty<TValue, TType> Register<TValue, TType>(Func<TType, OnChanged<TValue>> changedMethod, bool inherited, NullTreatment nullTreatment, bool isParent) where TType : class
        {
            var p = new NDProperty<TValue, TType>(changedMethod, inherited, nullTreatment);
            if (p.Inherited)
            {
                if (!inheritedPropertys.ContainsKey(typeof(TType)))
                    inheritedPropertys.Add(typeof(TType), new List<IInternalNDReadOnlyProperty>());
                inheritedPropertys[typeof(TType)].Add(p);
            }
            if (isParent)
                AddParentHandler(p);

            return p;
        }
        public static NDAttachedProperty<TValue, TType> RegisterAttached<TValue, TType>(OnChanged<TValue, TType> changedMethod, bool inherited, NullTreatment nullTreatment, bool isParent) where TType : class
        {
            var p = new NDAttachedProperty<TValue, TType>(changedMethod, inherited, nullTreatment);
            if (p.Inherited)
            {
                if (!inheritedPropertys.ContainsKey(typeof(TType)))
                    inheritedPropertys.Add(typeof(TType), new List<IInternalNDReadOnlyProperty>());
                inheritedPropertys[typeof(TType)].Add(p);
            }
            if (isParent)
                AddParentHandler(p);

            return p;
        }

        private static void AddParentHandler<TValue, TType>(NDReadOnlyProperty<TValue, TType> p) where TType : class
        {
            AddEventHandler(p, (sender, e) =>
            {
                var tree = Tree.GetTree(e.ChangedObject);
                var affectedItems = new List<(object affectedObject, object oldValue, IInternalNDReadOnlyProperty affectedProperty)>();
                if (inheritedPropertys.Count != 0)
                {
                    // Get all affacted decendents
                    Queue<Tree> queue = new Queue<Tree>();
                    queue.Enqueue(tree);

                    while (queue.Count != 0)
                    {
                        tree = queue.Dequeue();
                        if (inheritedPropertys.ContainsKey(tree.Current.GetType()))
                        {
                            foreach (var affectedProperty in inheritedPropertys[tree.Current.GetType()])
                                affectedItems.Add((tree.Current, affectedProperty.GetValue(tree.Current), affectedProperty));
                        }
                        foreach (var child in tree.Childrean)
                            queue.Enqueue(child);
                    }

                    // reset tree to its original value
                    tree = Tree.GetTree(e.ChangedObject);
                }
                System.Diagnostics.Debug.Assert(Equals(tree.Parent?.Current, e.OldValue));

                if (tree.Parent != null)
                    tree.Parent.Childrean.Remove(tree);

                tree.Parent = Tree.GetTree(e.NewValue);

                if (tree.Parent != null)
                    tree.Parent.Childrean.Add(tree);

                // Notify AffectedItems
                foreach (var item in affectedItems)
                {
                    var newValue = item.affectedProperty.GetValue(item.affectedObject);
                    if (newValue != item.oldValue)
                        item.affectedProperty.CallChangeHandler(item.affectedObject, sender, item.oldValue, newValue);
                }
            });
        }

        public static void SetValue<TValue, TType>(NDProperty<TValue, TType> property, TType changedObject, TValue value) where TType : class
        {
            var oldValue = GetValue(property, changedObject);
            var onChangedArg = OnChangedArg.Create(oldValue, value);
            property.changedMethod(changedObject)(onChangedArg);
            SetValueInternal(property, changedObject, value, onChangedArg);
        }
        public static void SetValue<TValue, TType>(NDAttachedProperty<TValue, TType> property, TType changedObject, TValue value) where TType : class
        {
            var oldValue = GetValue(property, changedObject);
            var onChangedArg = OnChangedArg.Create(changedObject, oldValue, value);
            property.changedMethod(onChangedArg);
            SetValueInternal(property, changedObject, onChangedArg.MutatedValue, onChangedArg);
        }

        private static void SetValueInternal<TValue, TType>(NDReadOnlyProperty<TValue, TType> property, TType obj, TValue value, OnChangedArg<TValue> onChangedArg) where TType : class
        {
{'fraction_non_alphanumeric': 0.08758753679082514, 'fraction_numerical': 0.0004059677255658175, 'mean_word_length': 1.9960474308300395, 'pattern_counts': {'":': 0, '<': 57, '<?xml version=': 0, '>': 59, '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': '1668346', 'n_tokens_mistral': 2538, 'n_tokens_neox': 2388, 'n_words': 529}