public ILanguageDependentBuilder <TLanguages> AddLanguages <TLanguages>(Func <Func <Language.Builder>, TLanguages> languages)
            {
                var langs         = languages(() => Language.Builder.Create());
                var languageCount = 0;

                using (new Section(_textWriter, "Languages"))
                {
                    foreach (var typesProperty in langs.GetType().GetProperties())
                    {
                        var entries = new NameValueCollection
                        {
                            { "Name", typesProperty.Name }
                        };

                        var setupType = typesProperty.GetValue(langs);

                        var converter = new PropertiesToNameValuePairsConverter(_propertyFormatter);
                        entries.Add(converter.ConvertTo(setupType, typeof(NameValueCollection)) as NameValueCollection);

                        _textWriter.WriteLine(entries.Format());

                        languageCount++;
                    }
                }

                return(new LanguageDependentBuilder <TLanguages>(_textWriter, langs, _methods, languageCount));
            }
                            private IList <TEntry> AddEntries <TEntry, TBuilder>(
                                string sectionName,
                                Func <TBuilder> builderFactory,
                                Func <Func <TBuilder>, TLanguages, TSetupTypes, TCustomMessages, TMessages, TComponents, TTasks, IEnumerable <TEntry> > builder,
                                TLanguages languages,
                                TSetupTypes setupTypes,
                                TCustomMessages customMessages,
                                TMessages messages,
                                TComponents components,
                                TTasks tasks,
                                Action <TEntry> newEntryHandler = null) where TEntry : ICustomizable, IPredicated
                            {
                                var entries = builder(builderFactory, languages, setupTypes, customMessages, messages, components, tasks).ToList();

                                if (entries.Count > 0)
                                {
                                    var typeConverterFactory = new Func <System.ComponentModel.TypeConverterAttribute, System.ComponentModel.TypeConverter>(attr =>
                                    {
                                        var type          = typeof(DelegateExpressionToStringConverter <Func <string, bool> >);
                                        var converterType = Type.GetType(attr.ConverterTypeName);

                                        if (converterType == type)
                                        {
                                            return(new DelegateExpressionToStringConverter <Func <string, bool> >(methodInfo =>
                                            {
                                                if (!_methods.Any(im => im.MetadataToken == methodInfo.MetadataToken))
                                                {
                                                    _methods.Add(new InstallationMethod(methodInfo));
                                                }
                                            }));
                                        }

                                        return((System.ComponentModel.TypeConverter)Activator.CreateInstance(converterType));
                                    });

                                    using (new Section(_textWriter, sectionName))
                                    {
                                        foreach (var entry in entries)
                                        {
                                            newEntryHandler?.Invoke(entry);

                                            var converter = new PropertiesToNameValuePairsConverter(_propertyFormatter, typeConverterFactory);
                                            var pairs     = converter.ConvertTo(entry, typeof(NameValueCollection)) as NameValueCollection;

                                            _textWriter.WriteLine(pairs.Format());
                                        }
                                    }
                                }

                                return(entries);
                            }
                        public IContentBuilder <TLanguages, TSetupTypes, TCustomMessages, TMessages, TComponents, TTasks> AddTasks <TTasks>(Func <TLanguages, TSetupTypes, TCustomMessages, TMessages, TComponents, TTasks> tasks)
                        {
                            var taskEntries = tasks(_languages, _setupTypes, _customMessages, _messages, _components);

                            using (new Section(_textWriter, "Tasks"))
                            {
                                void TransformTask(object tasks, string prefix = null)
                                {
                                    prefix ??= string.Empty;

                                    foreach (var taskProperty in tasks.GetType().GetProperties())
                                    {
                                        var entries = new NameValueCollection
                                        {
                                            { "Name", Path.Combine(prefix, taskProperty.Name) }
                                        };

                                        var tasksValue = taskProperty.GetValue(tasks);

                                        var converter = new PropertiesToNameValuePairsConverter(_propertyFormatter);
                                        entries.Add(converter.ConvertTo(tasksValue, typeof(NameValueCollection)) as NameValueCollection);

                                        _textWriter.WriteLine(entries.Format());

                                        var childrenType = tasksValue.GetType().GetProperty(nameof(Task <object> .Children), BindingFlags.Public | BindingFlags.Instance);
                                        var children     = childrenType.GetValue(tasksValue);

                                        TransformTask(children, taskProperty.Name);
                                    }
                                }

                                TransformTask(taskEntries);
                            }


                            return(new ContentBuilder <TTasks>(_textWriter, _languages, _setupTypes, _customMessages, _messages, _components, taskEntries, _methods));
                        }
                public IComponentsBuilder <TLanguages, TSetupTypes, TCustomMessages, TMessages> Add <TSetupTypes, TCustomMessages, TMessages>(
                    Func <Func <SetupType.Builder>, TLanguages, TSetupTypes> types,
                    Func <TLanguages, TCustomMessages> customMessagesFactory,
                    Func <TLanguages, TMessages> messagesFactory)
                {
                    var setupTypes = types(() => SetupType.Builder.Create(), _languages);

                    using (new Section(_textWriter, "Types"))
                    {
                        foreach (var typesProperty in setupTypes.GetType().GetProperties())
                        {
                            var entries = new NameValueCollection
                            {
                                { "Name", typesProperty.Name }
                            };

                            var setupType = typesProperty.GetValue(setupTypes);

                            var converter = new PropertiesToNameValuePairsConverter(_propertyFormatter);
                            entries.Add(converter.ConvertTo(setupType, typeof(NameValueCollection)) as NameValueCollection);

                            _textWriter.WriteLine(entries.Format());
                        }
                    }

                    var messages = messagesFactory(_languages);

                    using (new Section(_textWriter, "Messages"))
                    {
                        foreach (var messageProperty in messages.GetType().GetProperties())
                        {
                            if (messageProperty.GetValue(messages) is Message message)
                            {
                                var format = _languageCount > 1 && !string.IsNullOrEmpty(message.Qualifier) ? "{0}.{1}={2}" : "{1}={2}";

                                _textWriter.WriteLine(string.Format(format, message.Qualifier, messageProperty.Name, message.Text));
                            }
                            else
                            {
                                throw new NotSupportedException($"Messages of type {messageProperty.PropertyType.Name} are not supported");
                            }
                        }
                    }


                    var customMessages = customMessagesFactory(_languages);

                    using (new Section(_textWriter, "CustomMessages"))
                    {
                        var format = _languageCount > 1 ? "{0}.{1}={2}" : "{1}={2}";

                        foreach (var customMessageProperty in customMessages.GetType().GetProperties())
                        {
                            if (customMessageProperty.GetValue(customMessages) is Message customMessage)
                            {
                                _textWriter.WriteLine(string.Format(format, customMessage.Qualifier, customMessageProperty.Name, customMessage.Text));
                            }
                            else
                            {
                                throw new NotSupportedException($"Custom messages of type {customMessageProperty.PropertyType.Name} are not supported");
                            }
                        }
                    }

                    return(new ComponentsBuilder <TSetupTypes, TCustomMessages, TMessages>(_textWriter, _languages, setupTypes, customMessages, messages, _methods));
                }
        private void TestConversion <T>(NameValueCollection expected, T obj)
        {
            var converter = new PropertiesToNameValuePairsConverter();
            var values    = converter.ConvertTo(obj, typeof(NameValueCollection)) as NameValueCollection;

            Assert.True(expected.AllKeys.OrderBy(k => k).Select(k => (k, expected[k]))