<commit_before>using System.Linq;
using System.Threading.Tasks;
using Castle.MicroKernel.Resolvers.SpecializedResolvers;
using MediatR.Pipeline;

namespace MediatR.Examples.Windsor;

using System;
using System.Collections.Generic;
using System.IO;
using Castle.MicroKernel.Registration;
using Castle.Windsor;

internal class Program
{
    private static Task Main(string[] args)
    {
        var writer = new WrappingWriter(Console.Out);
        var mediator = BuildMediator(writer);

        return Runner.Run(mediator, writer, "Castle.Windsor", true);
    }

    private static IMediator BuildMediator(WrappingWriter writer)
    {
        var container = new WindsorContainer();
        container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel));
        container.Kernel.AddHandlersFilter(new ContravariantFilter());

        // *** The default lifestyle for Windsor is Singleton
        // *** If you are using ASP.net, it's better to register your services with 'Per Web Request LifeStyle'.

        var fromAssemblyContainingPing = Classes.FromAssemblyContaining<Ping>();
        container.Register(fromAssemblyContainingPing.BasedOn(typeof(IRequestHandler<,>)).WithServiceAllInterfaces().AllowMultipleMatches());
        container.Register(fromAssemblyContainingPing.BasedOn(typeof(INotificationHandler<>)).WithServiceAllInterfaces().AllowMultipleMatches());
        container.Register(Component.For(typeof(IPipelineBehavior<,>)).ImplementedBy(typeof(RequestExceptionActionProcessorBehavior<,>)));
        container.Register(Component.For(typeof(IPipelineBehavior<,>)).ImplementedBy(typeof(RequestExceptionProcessorBehavior<,>)));
        container.Register(fromAssemblyContainingPing.BasedOn(typeof(IRequestExceptionHandler<,,>)).WithServiceAllInterfaces().AllowMultipleMatches());
        container.Register(fromAssemblyContainingPing.BasedOn(typeof(IStreamRequestHandler<,>)).WithServiceAllInterfaces().AllowMultipleMatches());
        container.Register(fromAssemblyContainingPing.BasedOn(typeof(IRequestPreProcessor<>)).WithServiceAllInterfaces().AllowMultipleMatches());
        container.Register(fromAssemblyContainingPing.BasedOn(typeof(IRequestPostProcessor<,>)).WithServiceAllInterfaces().AllowMultipleMatches());

        container.Register(Component.For<IMediator>().ImplementedBy<Mediator>());
        container.Register(Component.For<TextWriter>().Instance(writer));
        container.Register(Component.For<ServiceFactory>().UsingFactoryMethod<ServiceFactory>(k => (type =>
        {
            var enumerableType = type
                .GetInterfaces()
                .Concat(new[] { type })
                .FirstOrDefault(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable<>));

            var service = enumerableType?.GetGenericArguments()?[0];
            var resolvedType = enumerableType != null ? k.ResolveAll(service) : k.Resolve(type);
            var genericArguments = service?.GetGenericArguments();

            // Handle exceptions even using the base request types
            if (service == null
            || genericArguments == null
            || !service.IsInterface
            || !service.IsGenericType
            || !service.IsConstructedGenericType
            || !(service.GetGenericTypeDefinition()
            ?.IsAssignableTo(typeof(IRequestExceptionHandler<,,>)) ?? false)
            || genericArguments.Length != 3
            || !(genericArguments[0].BaseType?.IsClass ?? false))
            {
                return resolvedType;
            }
            
            var serviceFactory = k.Resolve<ServiceFactory>();
            var baseRequestType = genericArguments[0].BaseType;
            var response = genericArguments[1];
            var exceptionType = genericArguments[2];
            
            // Check if the base request type is valid
            if (!baseRequestType.IsClass
            || baseRequestType == typeof(object)
            || ((!baseRequestType.GetInterfaces()
                ?.Any(i => i.IsAssignableFrom(typeof(IRequest<>)))) ?? true))
            {
                return resolvedType;
            }

            var exceptionHandlerInterfaceType = typeof(IRequestExceptionHandler<,,>).MakeGenericType(baseRequestType, response, exceptionType);
            var enumerableExceptionHandlerInterfaceType = typeof(IEnumerable<>).MakeGenericType(exceptionHandlerInterfaceType);

            // This is assumed Array because this method calls ResolveAll when a IEnumerable<> is passed as argument
            var firstArray = serviceFactory.Invoke(enumerableExceptionHandlerInterfaceType) as Array;
            var secondArray = resolvedType is Array ? resolvedType as Array : new[] { resolvedType };
            var resultArray = Array.CreateInstance(typeof(object), firstArray.Length + secondArray.Length);
            Array.Copy(firstArray, resultArray, firstArray.Length);
            Array.Copy(secondArray, 0, resultArray, firstArray.Length, secondArray.Length);
            <commit_msg>Better checking of baseRequestType and checking assumptions with Debug.Assert instead of writing them as comments<commit_after>using System.Linq;
using System.Threading.Tasks;
using Castle.MicroKernel.Resolvers.SpecializedResolvers;
using MediatR.Pipeline;

namespace MediatR.Examples.Windsor;

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using Castle.MicroKernel.Registration;
using Castle.Windsor;

internal class Program
{
    private static Task Main(string[] args)
    {
        var writer = new WrappingWriter(Console.Out);
        var mediator = BuildMediator(writer);

        return Runner.Run(mediator, writer, "Castle.Windsor", true);
    }

    private static IMediator BuildMediator(WrappingWriter writer)
    {
        var container = new WindsorContainer();
        container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel));
        container.Kernel.AddHandlersFilter(new ContravariantFilter());

        // *** The default lifestyle for Windsor is Singleton
        // *** If you are using ASP.net, it's better to register your services with 'Per Web Request LifeStyle'.

        var fromAssemblyContainingPing = Classes.FromAssemblyContaining<Ping>();
        container.Register(fromAssemblyContainingPing.BasedOn(typeof(IRequestHandler<,>)).WithServiceAllInterfaces().AllowMultipleMatches());
        container.Register(fromAssemblyContainingPing.BasedOn(typeof(INotificationHandler<>)).WithServiceAllInterfaces().AllowMultipleMatches());
        container.Register(Component.For(typeof(IPipelineBehavior<,>)).ImplementedBy(typeof(RequestExceptionActionProcessorBehavior<,>)));
        container.Register(Component.For(typeof(IPipelineBehavior<,>)).ImplementedBy(typeof(RequestExceptionProcessorBehavior<,>)));
        container.Register(fromAssemblyContainingPing.BasedOn(typeof(IRequestExceptionHandler<,,>)).WithServiceAllInterfaces().AllowMultipleMatches());
        container.Register(fromAssemblyContainingPing.BasedOn(typeof(IStreamRequestHandler<,>)).WithServiceAllInterfaces().AllowMultipleMatches());
        container.Register(fromAssemblyContainingPing.BasedOn(typeof(IRequestPreProcessor<>)).WithServiceAllInterfaces().AllowMultipleMatches());
        container.Register(fromAssemblyContainingPing.BasedOn(typeof(IRequestPostProcessor<,>)).WithServiceAllInterfaces().AllowMultipleMatches());

        container.Register(Component.For<IMediator>().ImplementedBy<Mediator>());
        container.Register(Component.For<TextWriter>().Instance(writer));
        container.Register(Component.For<ServiceFactory>().UsingFactoryMethod<ServiceFactory>(k => (type =>
        {
            var enumerableType = type
                .GetInterfaces()
                .Concat(new[] { type })
                .FirstOrDefault(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable<>));

            var service = enumerableType?.GetGenericArguments()?[0];
            var resolvedType = enumerableType != null ? k.ResolveAll(service) : k.Resolve(type);
            var genericArguments = service?.GetGenericArguments();

            // Handle exceptions even using the base request types
            if (service == null
            || genericArguments == null
            || !service.IsInterface
            || !service.IsGenericType
            || !service.IsConstructedGenericType
            || !(service.GetGenericTypeDefinition()
            ?.IsAssignableTo(typeof(IRequestExceptionHandler<,,>)) ?? false)
            || genericArguments.Length != 3)
            {
                return resolvedType;
            }
            
            var serviceFactory = k.Resolve<ServiceFactory>();
            var baseRequestType = genericArguments[0].BaseType;
            var response = genericArguments[1];
            var exceptionType = genericArguments[2];

            // Check if the base request type is valid
            if (baseRequestType == null
            || !baseRequestType.IsClass
            || baseRequestType == typeof(object)
            || ((!baseRequestType.GetInterfaces()
                ?.Any(i => i.IsAssignableFrom(typeof(IRequest<>)))) ?? true))
            {
                return resolvedType;
            }

            var exceptionHandlerInterfaceType = typeof(IRequestExceptionHandler<,,>).MakeGenericType(baseRequestType, response, exceptionType);
            var enumerableExceptionHandlerInterfaceType = typeof(IEnumerable<>).MakeGenericType(exceptionHandlerInterfaceType);

            var firstArray = serviceFactory.Invoke(enumerableExceptionHandlerInterfaceType) as Array;
            Debug.Assert(firstArray != null, $"Array '{nameof(firstArray)}' should not be null because this method calls ResolveAll when a {typeof(IEnumerable<>).FullName} " +
                $"is passed as argument in argument named '{nameof(type)}'");

            var secondArray = resolvedType is Array ? resolvedType as Array : new[] { resolvedType };
            Debug.Assert(secondArray != null, $"Array '{nameof(secondArray)}' should not be null because '{nameof(resolvedType)}' is an array or created as an array");

            var resultArray = Array.CreateInstance(typeof(object), firstArray.Length + secondArray.Length);
            Array.Copy(firstArray, resultArray, firstArray.Length);
            Array.Copy(secondArray, 0, resultArray, firstArray.Length, secondArray.Length);
            
{'fraction_non_alphanumeric': 0.10666156933957756, 'fraction_numerical': 0.0012424734779699896, 'mean_word_length': 3.473706712270201, 'pattern_counts': {'":': 0, '<': 49, '<?xml version=': 0, '>': 57, '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': '3620567', 'n_tokens_mistral': 2578, 'n_tokens_neox': 2514, 'n_words': 482}