<commit_before>﻿namespace AgileObjects.AgileMapper.Members
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Reflection;
    using Extensions;
    using ReadableExpressions.Extensions;

    internal static class MemberExtensions
    {
        public static string GetFullName(this IEnumerable<Member> members)
            => string.Join(string.Empty, members.Select(m => m.JoiningName));

        public static string GetFriendlySourcePath(this IQualifiedMember sourceMember, IMemberMapperData rootMapperData)
            => GetMemberPath(sourceMember, rootMapperData.SourceMember);

        public static string GetFriendlyTargetPath(this IQualifiedMember targetMember, IMemberMapperData rootMapperData)
            => GetMemberPath(targetMember, rootMapperData.TargetMember);

        private static string GetMemberPath(IQualifiedMember member, IQualifiedMember rootMember)
        {
            var rootTypeName = rootMember.Type.GetFriendlyName();
            var memberPath = member.GetPath();

            if (memberPath == rootMember.Name)
            {
                return rootTypeName;
            }

            if (memberPath.StartsWith(rootMember.Name, StringComparison.Ordinal))
            {
                return rootTypeName + memberPath.Substring(rootMember.Name.Length);
            }

            var rootMemberNameIndex = memberPath.IndexOf("." + rootMember.Name + ".", StringComparison.Ordinal);

            if (rootMemberNameIndex == -1)
            {
                return rootTypeName + memberPath;
            }

            var rootMemberString = memberPath.Substring(rootMemberNameIndex + rootMember.Name.Length + 2);
            var path = rootTypeName + "." + rootMemberString;

            return path;
        }

        public static Expression GetQualifiedAccess(this IEnumerable<Member> memberChain, Expression instance)
        {
            // Skip(1) because the 0th member is the instance:
            return memberChain.Skip(1).Aggregate(instance, (accessSoFar, member) => member.GetAccess(accessSoFar));
        }

        public static bool IsEnumerableElement(this Member member) => member.MemberType == MemberType.EnumerableElement;

        public static ICollection<string> ExtendWith(
            this ICollection<string> parentJoinedNames,
            string[] memberMatchingNames,
            MapperContext mapperContext)
        {
            return mapperContext.NamingSettings.ExtendJoinedNames(parentJoinedNames, memberMatchingNames);
        }

        public static bool CouldMatch(this IEnumerable<string> memberNames, IEnumerable<string> otherMemberNames)
        {
            return otherMemberNames
                .Any(otherJoinedName => memberNames
                    .Any(joinedName => otherJoinedName.StartsWith(joinedName, StringComparison.OrdinalIgnoreCase)));
        }

        public static bool Match(this IEnumerable<string> memberNames, IEnumerable<string> otherMemberNames)
        {
            return memberNames
                .Intersect(otherMemberNames, StringComparer.OrdinalIgnoreCase)
                .Any();
        }

        public static IQualifiedMember GetElementMember(this IQualifiedMember enumerableMember)
            => enumerableMember.Append(enumerableMember.Type.GetElementMember());

        public static Member GetElementMember(this Type enumerableType)
            => GlobalContext.Instance.MemberFinder.GetSourceMembers(enumerableType).First();

        public static Member[] RelativeTo(this Member[] memberChain, Member[] otherMemberChain)
        {
            var otherMembersLeafMember = otherMemberChain.Last();
            Member[] relativeMemberChain = null;

            var startIndex = memberChain.Length - 1;

            if ((memberChain.Length > 2) &&
                memberChain[startIndex] == memberChain[startIndex - 1])
            {
                // The member chain ends in a 1-to-1, immediately recursive
                // relationship; skip the last element:
                --startIndex;
            }

            for (var i = startIndex; i >= 0; --i)
            {
                var member = memberChain[i];

                if (member != otherMembersLeafMember)
                {
                    continue;
                }

                relativeMemberChain = new Member[memberChain.Length - i];

                for (var j = 0; j < relativeMemberChain.Length; j++)
                {
                    relativeMemberChain[j] = memberChain[j + i];
                }

                break;
            }

            return relativeMemberChain;
        }

        #region PopulationFactoriesByMemberType

        private delegate Expression PopulationFactory(Expression instance, Member member, Expression value);

        private static readonly Dictionary<MemberType, PopulationFactory> _populationFactoriesByMemberType =
            new Dictionary<MemberType, PopulationFactory>
            {
                { MemberType.Field, AssignMember },
                { MemberType.Property, AssignMember },
                { MemberType.SetMethod, CallSetMethod }
            };

        private static Expression AssignMember(Expression instance, Member targetMember, Expression value)
            => targetMember.GetAccess(instance).AssignTo(value);

        private static Expression CallSetMethod(Expression instance, Member targetMember, Expression value)
            => Expression.Call(instance, targetMember.Name, Constants.NoTypeArguments, value);

        #endregion

        public static Expression GetPopulation(this Member targetMember, Expression instance, Expression value)
        {
            var populationFactory = _populationFactoriesByMemberType[targetMember.MemberType];
            var population = populationFactory.Invoke(instance, targetMember, value);<commit_msg>Removing local variable use from member chain .RelativeTo()<commit_after>﻿namespace AgileObjects.AgileMapper.Members
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Reflection;
    using Extensions;
    using ReadableExpressions.Extensions;

    internal static class MemberExtensions
    {
        public static string GetFullName(this IEnumerable<Member> members)
            => string.Join(string.Empty, members.Select(m => m.JoiningName));

        public static string GetFriendlySourcePath(this IQualifiedMember sourceMember, IMemberMapperData rootMapperData)
            => GetMemberPath(sourceMember, rootMapperData.SourceMember);

        public static string GetFriendlyTargetPath(this IQualifiedMember targetMember, IMemberMapperData rootMapperData)
            => GetMemberPath(targetMember, rootMapperData.TargetMember);

        private static string GetMemberPath(IQualifiedMember member, IQualifiedMember rootMember)
        {
            var rootTypeName = rootMember.Type.GetFriendlyName();
            var memberPath = member.GetPath();

            if (memberPath == rootMember.Name)
            {
                return rootTypeName;
            }

            if (memberPath.StartsWith(rootMember.Name, StringComparison.Ordinal))
            {
                return rootTypeName + memberPath.Substring(rootMember.Name.Length);
            }

            var rootMemberNameIndex = memberPath.IndexOf("." + rootMember.Name + ".", StringComparison.Ordinal);

            if (rootMemberNameIndex == -1)
            {
                return rootTypeName + memberPath;
            }

            var rootMemberString = memberPath.Substring(rootMemberNameIndex + rootMember.Name.Length + 2);
            var path = rootTypeName + "." + rootMemberString;

            return path;
        }

        public static Expression GetQualifiedAccess(this IEnumerable<Member> memberChain, Expression instance)
        {
            // Skip(1) because the 0th member is the instance:
            return memberChain.Skip(1).Aggregate(instance, (accessSoFar, member) => member.GetAccess(accessSoFar));
        }

        public static bool IsEnumerableElement(this Member member) => member.MemberType == MemberType.EnumerableElement;

        public static ICollection<string> ExtendWith(
            this ICollection<string> parentJoinedNames,
            string[] memberMatchingNames,
            MapperContext mapperContext)
        {
            return mapperContext.NamingSettings.ExtendJoinedNames(parentJoinedNames, memberMatchingNames);
        }

        public static bool CouldMatch(this IEnumerable<string> memberNames, IEnumerable<string> otherMemberNames)
        {
            return otherMemberNames
                .Any(otherJoinedName => memberNames
                    .Any(joinedName => otherJoinedName.StartsWith(joinedName, StringComparison.OrdinalIgnoreCase)));
        }

        public static bool Match(this IEnumerable<string> memberNames, IEnumerable<string> otherMemberNames)
        {
            return memberNames
                .Intersect(otherMemberNames, StringComparer.OrdinalIgnoreCase)
                .Any();
        }

        public static IQualifiedMember GetElementMember(this IQualifiedMember enumerableMember)
            => enumerableMember.Append(enumerableMember.Type.GetElementMember());

        public static Member GetElementMember(this Type enumerableType)
            => GlobalContext.Instance.MemberFinder.GetSourceMembers(enumerableType).First();

        public static Member[] RelativeTo(this Member[] memberChain, Member[] otherMemberChain)
        {
            var otherMembersLeafMember = otherMemberChain.Last();
            var startIndex = memberChain.Length - 1;

            if ((memberChain.Length > 2) &&
                memberChain[startIndex] == memberChain[startIndex - 1])
            {
                // The member chain ends in a 1-to-1, immediately recursive
                // relationship; skip the last element:
                --startIndex;
            }

            while (startIndex >= 0)
            {
                var member = memberChain[startIndex];

                if (member == otherMembersLeafMember)
                {
                    break;
                }

                --startIndex;
            }

            var relativeMemberChain = new Member[memberChain.Length - startIndex];

            for (var i = 0; i < relativeMemberChain.Length; i++)
            {
                relativeMemberChain[i] = memberChain[i + startIndex];
            }

            return relativeMemberChain;
        }

        #region PopulationFactoriesByMemberType

        private delegate Expression PopulationFactory(Expression instance, Member member, Expression value);

        private static readonly Dictionary<MemberType, PopulationFactory> _populationFactoriesByMemberType =
            new Dictionary<MemberType, PopulationFactory>
            {
                { MemberType.Field, AssignMember },
                { MemberType.Property, AssignMember },
                { MemberType.SetMethod, CallSetMethod }
            };

        private static Expression AssignMember(Expression instance, Member targetMember, Expression value)
            => targetMember.GetAccess(instance).AssignTo(value);

        private static Expression CallSetMethod(Expression instance, Member targetMember, Expression value)
            => Expression.Call(instance, targetMember.Name, Constants.NoTypeArguments, value);

        #endregion

        public static Expression GetPopulation(this Member targetMember, Expression instance, Expression value)
        {
            var populationFactory = _populationFactoriesByMemberType[targetMember.MemberType];
            var population = populationFactory.Invoke(instance, targetMember, value);
{'fraction_non_alphanumeric': 0.07456251585087496, 'fraction_numerical': 0.002028911995942176, 'mean_word_length': 2.3703703703703702, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 51, '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': '3615701', 'n_tokens_mistral': 2827, 'n_tokens_neox': 2683, 'n_words': 636}