<commit_before>﻿using System.Linq;
using Stronk.Policies;
using Stronk.PropertySelection;
using Stronk.SourceValueSelection;
using Stronk.ValueConversion;

namespace Stronk
{
	public class ConfigBuilder
	{
		private readonly StronkOptions _options;

		public ConfigBuilder(StronkOptions options)
		{
			_options = options;
		}

		public void Populate(object target, IConfigurationSource configSource)
		{
			var propertySelectors = _options.PropertySelectors.ToArray();

			_options.WriteLog(
				"Populating '{typeName}', from {sourceTypeName} using\nPropertySelectors: {propertySelectors}\nSourceValueSelectors: {valueSelectors}\nValueConverters: {valueConverters}.",
				target.GetType().Name,
				configSource.GetType().Name,
				propertySelectors.SelectTypeNames(),
				_options.ValueSelectors.SelectTypeNames(),
				_options.ValueConverters.SelectTypeNames());

			var propertySelectorArgs = new PropertySelectorArgs(
				_options.Logger,
				target.GetType());

			var properties = propertySelectors
				.SelectMany(selector => selector.Select(propertySelectorArgs))
				.ToArray();

			_options.WriteLog(
				"Selected {count} properties to populate: {properties}",
				properties.Length,
				properties.Select(p => p.Name));
			var applicator = new Applicator(_options);

			var values = properties
				.Select(property => NewPropertyConversionUnit(configSource, property))
				.Where(descriptor =>
				{
					if (descriptor.Value != null)
						return true;

					_options.WriteLog("Unable to find a value for {propertyName}", descriptor.Property.Name);

					_options.ErrorPolicy.OnSourceValueNotFound.Handle(new SourceValueNotFoundArgs
					{
						ValueSelectors = _options.ValueSelectors,
						Property = descriptor.Property
					});

					return false;
				})
				.Where(descriptor =>
				{
					if (descriptor.Converters.Any())
						return true;

					_options.WriteLog("Unable to any converters for {typeName} for property {propertyName}", descriptor.Property.Type.Name, descriptor.Property.Name);

					_options.ErrorPolicy.OnConverterNotFound.Handle(new ConverterNotFoundArgs
					{
						AvailableConverters = _options.ValueConverters,
						Property = descriptor.Property
					});

					return false;
				});

			foreach (var descriptor in values)
			{
				applicator.Apply(descriptor, target);
			}
		}

		private PropertyConversionUnit NewPropertyConversionUnit(IConfigurationSource configSource, PropertyDescriptor property)
		{
			var selectionArgs = new ValueSelectorArgs(_options.Logger, configSource, property);
			
			return new PropertyConversionUnit
			{
				Property = property,
				Converters = _options.ValueConverters.Where(c => c.CanMap(property.Type)).ToArray(),
				Value = _options.ValueSelectors.Select(x => x.Select(selectionArgs)).FirstOrDefault(v => v != null)
			};
		}
	}
}
<commit_msg>configBuilder: refactor linq steps to methods<commit_after>﻿using System.Linq;
using Stronk.Policies;
using Stronk.PropertySelection;
using Stronk.SourceValueSelection;

namespace Stronk
{
	public class ConfigBuilder
	{
		private readonly StronkOptions _options;

		public ConfigBuilder(StronkOptions options)
		{
			_options = options;
		}

		public void Populate(object target, IConfigurationSource configSource)
		{
			var propertySelectors = _options.PropertySelectors.ToArray();

			_options.WriteLog(
				"Populating '{typeName}', from {sourceTypeName} using\nPropertySelectors: {propertySelectors}\nSourceValueSelectors: {valueSelectors}\nValueConverters: {valueConverters}.",
				target.GetType().Name,
				configSource.GetType().Name,
				propertySelectors.SelectTypeNames(),
				_options.ValueSelectors.SelectTypeNames(),
				_options.ValueConverters.SelectTypeNames());

			var propertySelectorArgs = new PropertySelectorArgs(
				_options.Logger,
				target.GetType());

			var properties = propertySelectors
				.SelectMany(selector => selector.Select(propertySelectorArgs))
				.ToArray();

			_options.WriteLog(
				"Selected {count} properties to populate: {properties}",
				properties.Length,
				properties.Select(p => p.Name));

			var applicator = new Applicator(_options);

			var values = properties
				.Select(property => NewPropertyConversionUnit(configSource, property))
				.Where(SelectedValueIsValid)
				.Where(SelectedConvertersAreValid);

			foreach (var descriptor in values)
			{
				applicator.Apply(descriptor, target);
			}
		}

		private bool SelectedConvertersAreValid(PropertyConversionUnit descriptor)
		{
			if (descriptor.Converters.Any())
				return true;

			_options.WriteLog("Unable to any converters for {typeName} for property {propertyName}", descriptor.Property.Type.Name, descriptor.Property.Name);

			_options.ErrorPolicy.OnConverterNotFound.Handle(new ConverterNotFoundArgs
			{
				AvailableConverters = _options.ValueConverters,
				Property = descriptor.Property
			});

			return false;
		}

		private bool SelectedValueIsValid(PropertyConversionUnit descriptor)
		{
			if (descriptor.Value != null)
				return true;

			_options.WriteLog("Unable to find a value for {propertyName}", descriptor.Property.Name);

			_options.ErrorPolicy.OnSourceValueNotFound.Handle(new SourceValueNotFoundArgs
			{
				ValueSelectors = _options.ValueSelectors,
				Property = descriptor.Property
			});

			return false;
		}

		private PropertyConversionUnit NewPropertyConversionUnit(IConfigurationSource configSource, PropertyDescriptor property)
		{
			var selectionArgs = new ValueSelectorArgs(_options.Logger, configSource, property);
			
			return new PropertyConversionUnit
			{
				Property = property,
				Converters = _options.ValueConverters.Where(c => c.CanMap(property.Type)).ToArray(),
				Value = _options.ValueSelectors.Select(x => x.Select(selectionArgs)).FirstOrDefault(v => v != null)
			};
		}
	}
}

{'fraction_non_alphanumeric': 0.09749784296807593, 'fraction_numerical': 0.0, 'mean_word_length': 4.416822429906542, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 17, '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': '93428', 'n_tokens_mistral': 1981, 'n_tokens_neox': 1601, 'n_words': 325}