<commit_before>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Castle.DynamicProxy;
using IFramework.Infrastructure;
using MethodInfo = System.Reflection.MethodInfo;

namespace IFramework.DependencyInjection.Autofac
{
    public abstract class InterceptorBase : IInterceptor
    {
        protected readonly IObjectProvider ObjectProvider;

        protected InterceptorBase(IObjectProvider objectProvider)
        {
            ObjectProvider = objectProvider;
        }

        public virtual void Intercept(IInvocation invocation)
        {
            invocation.Proceed();
        }

        protected virtual object Process(IInvocation invocation)
        {
            invocation.Proceed();
            return invocation.ReturnValue;
        }

        protected Type GetTaskResultType(IInvocation invocation)
        {
            return invocation.Method.ReturnType.GetGenericArguments().FirstOrDefault();
        }

        protected static Task<T> ProcessTaskAsync<T>(IInvocation invocation)
        {
            invocation.Proceed();
            return invocation.ReturnValue as Task<T>;
        }

        protected static TAttribute GetMethodAttribute<TAttribute>(IInvocation invocation, TAttribute defaultValue = null)
            where TAttribute : Attribute
        {
            return invocation.Method.GetCustomAttribute<TAttribute>() ??
                   invocation.Method.DeclaringType?.GetCustomAttribute<TAttribute>() ??
                   invocation.MethodInvocationTarget?.GetCustomAttribute<TAttribute>() ??
                   invocation.MethodInvocationTarget?.DeclaringType?.GetCustomAttribute<TAttribute>() ??
                   defaultValue;
        }

        private static IEnumerable<InterceptorAttribute> GetInterceptorAttributes(MethodInfo methodInfo)
        {
            return methodInfo?.GetCustomAttributes(typeof(InterceptorAttribute), true).Cast<InterceptorAttribute>() ?? new InterceptorAttribute[0];
        }

        private static IEnumerable<InterceptorAttribute> GetInterceptorAttributes(Type type)
        {
            return type?.GetCustomAttributes(typeof(InterceptorAttribute), true).Cast<InterceptorAttribute>() ?? new InterceptorAttribute[0];
        }

        protected static InterceptorAttribute[] GetInterceptorAttributes(IInvocation invocation)
        {
            return GetInterceptorAttributes(invocation.Method)
                   .Union(GetInterceptorAttributes(invocation.Method.DeclaringType))
                   .Union(GetInterceptorAttributes(invocation.MethodInvocationTarget))
                   .Union(GetInterceptorAttributes(invocation.MethodInvocationTarget?.DeclaringType))
                   .OrderBy(i => i.Order)
                   .ToArray();
        }
    }

    public class DefaultInterceptor : InterceptorBase
    {
        public DefaultInterceptor(IObjectProvider objectProvider) : base(objectProvider) { }


        protected virtual Task<T> InvokeTargetMethod<T>(IInvocation invocation)
        {
            // TODO check if the target is Castle.Proxy, it should use invocation.Proceed() !
            MethodInfo targetMethod = invocation.GetConcreteMethodInvocationTarget();
            return targetMethod.Invoke(invocation.InvocationTarget, invocation.Arguments) as Task<T>;
        }

        protected virtual Task InvokeTargetMethod(IInvocation invocation)
        {
            MethodInfo targetMethod = invocation.GetConcreteMethodInvocationTarget();
            return targetMethod.Invoke(invocation.InvocationTarget, invocation.Arguments) as Task;
        }
        public virtual void InterceptAsync<T>(IInvocation invocation, InterceptorAttribute[] interceptorAttributes)
        {

            Func<Task<T>> processAsyncFunc = () => InvokeTargetMethod<T>(invocation);

            foreach (var interceptor in interceptorAttributes)
            {
                var func = processAsyncFunc;
                processAsyncFunc = () => interceptor.ProcessAsync(func,
                                                                  ObjectProvider,
                                                                  invocation.TargetType,
                                                                  invocation.InvocationTarget,
                                                                  invocation.Method,
                                                                  invocation.Arguments);
            }

            var returnValue = processAsyncFunc();
            invocation.ReturnValue = returnValue;
        }

        public virtual void InterceptAsync(IInvocation invocation, InterceptorAttribute[] interceptorAttributes)
        {
            Func<Task> processAsyncFunc = () => InvokeTargetMethod(invocation);

            foreach (var interceptor in interceptorAttributes)
            {
                var func = processAsyncFunc;
                processAsyncFunc = () => interceptor.ProcessAsync(func,
                                                                  ObjectProvider,
                                                                  invocation.TargetType,
                                                                  invocation.InvocationTarget,
                                                                  invocation.Method,
                                                                  invocation.Arguments);
            }

            var returnValue = processAsyncFunc();
            invocation.ReturnValue = returnValue;
        }

        public override void Intercept(IInvocation invocation)
        {
            var isTaskResult = typeof(Task).IsAssignableFrom(invocation.Method.ReturnType);
            var interceptorAttributes = GetInterceptorAttributes(invocation);

            if (interceptorAttributes.Length > 0)
            {
                if (isTaskResult)
                {
                    var resultType = GetTaskResultType(invocation);
                    if (resultType == null)
                    {
                        InterceptAsync(invocation, interceptorAttributes);
                    }
                    else
                    {
                        this.InvokeGenericMethod(nameof(InterceptAsync),
                                                 new object[] { invocation, interceptorAttributes },
                                                 resultType);
                    }
                }
                else
                {
                    if (invocation.Method.ReturnType != typeof(void))
                    {<commit_msg>add workaround for Castle.Proxies async interceptor<commit_after>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Castle.DynamicProxy;
using IFramework.Infrastructure;
using MethodInfo = System.Reflection.MethodInfo;

namespace IFramework.DependencyInjection.Autofac
{
    public abstract class InterceptorBase : IInterceptor
    {
        protected readonly IObjectProvider ObjectProvider;

        protected InterceptorBase(IObjectProvider objectProvider)
        {
            ObjectProvider = objectProvider;
        }

        public virtual void Intercept(IInvocation invocation)
        {
            invocation.Proceed();
        }

        protected virtual object Process(IInvocation invocation)
        {
            invocation.Proceed();
            return invocation.ReturnValue;
        }

        protected Type GetTaskResultType(IInvocation invocation)
        {
            return invocation.Method.ReturnType.GetGenericArguments().FirstOrDefault();
        }

        protected static Task<T> ProcessTaskAsync<T>(IInvocation invocation)
        {
            invocation.Proceed();
            return invocation.ReturnValue as Task<T>;
        }

        protected static TAttribute GetMethodAttribute<TAttribute>(IInvocation invocation, TAttribute defaultValue = null)
            where TAttribute : Attribute
        {
            return invocation.Method.GetCustomAttribute<TAttribute>() ??
                   invocation.Method.DeclaringType?.GetCustomAttribute<TAttribute>() ??
                   invocation.MethodInvocationTarget?.GetCustomAttribute<TAttribute>() ??
                   invocation.MethodInvocationTarget?.DeclaringType?.GetCustomAttribute<TAttribute>() ??
                   defaultValue;
        }

        private static IEnumerable<InterceptorAttribute> GetInterceptorAttributes(MethodInfo methodInfo)
        {
            return methodInfo?.GetCustomAttributes(typeof(InterceptorAttribute), true).Cast<InterceptorAttribute>() ?? new InterceptorAttribute[0];
        }

        private static IEnumerable<InterceptorAttribute> GetInterceptorAttributes(Type type)
        {
            return type?.GetCustomAttributes(typeof(InterceptorAttribute), true).Cast<InterceptorAttribute>() ?? new InterceptorAttribute[0];
        }

        protected static InterceptorAttribute[] GetInterceptorAttributes(IInvocation invocation)
        {
            return GetInterceptorAttributes(invocation.Method)
                   .Union(GetInterceptorAttributes(invocation.Method.DeclaringType))
                   .Union(GetInterceptorAttributes(invocation.MethodInvocationTarget))
                   .Union(GetInterceptorAttributes(invocation.MethodInvocationTarget?.DeclaringType))
                   .OrderBy(i => i.Order)
                   .ToArray();
        }
    }

    public class DefaultInterceptor : InterceptorBase
    {
        public DefaultInterceptor(IObjectProvider objectProvider) : base(objectProvider) { }


        protected virtual Task<T> InvokeTargetMethod<T>(IInvocation invocation)
        {
            // check if the target is Castle.Proxy, it should use invocation.Proceed() !
            if (invocation.InvocationTarget.GetType() == invocation.Proxy.GetType())
            {
                invocation.Proceed();
                return invocation.ReturnValue as Task<T>;
            }

            MethodInfo targetMethod = invocation.GetConcreteMethodInvocationTarget();
            return targetMethod.Invoke(invocation.InvocationTarget, invocation.Arguments) as Task<T>;
        }

        protected virtual Task InvokeTargetMethod(IInvocation invocation)
        {
            if (invocation.InvocationTarget.GetType() == invocation.Proxy.GetType())
            {
                invocation.Proceed();
                return invocation.ReturnValue as Task;
            }

            MethodInfo targetMethod = invocation.GetConcreteMethodInvocationTarget();
            return targetMethod.Invoke(invocation.InvocationTarget, invocation.Arguments) as Task;
        }

        public virtual void InterceptAsync<T>(IInvocation invocation, InterceptorAttribute[] interceptorAttributes)
        {
            Func<Task<T>> processAsyncFunc = () => InvokeTargetMethod<T>(invocation);

            foreach (var interceptor in interceptorAttributes)
            {
                var func = processAsyncFunc;
                processAsyncFunc = () => interceptor.ProcessAsync(func,
                                                                  ObjectProvider,
                                                                  invocation.TargetType,
                                                                  invocation.InvocationTarget,
                                                                  invocation.Method,
                                                                  invocation.Arguments);
            }

            var returnValue = processAsyncFunc();
            invocation.ReturnValue = returnValue;
        }

        public virtual void InterceptAsync(IInvocation invocation, InterceptorAttribute[] interceptorAttributes)
        {
            Func<Task> processAsyncFunc = () => InvokeTargetMethod(invocation);

            foreach (var interceptor in interceptorAttributes)
            {
                var func = processAsyncFunc;
                processAsyncFunc = () => interceptor.ProcessAsync(func,
                                                                  ObjectProvider,
                                                                  invocation.TargetType,
                                                                  invocation.InvocationTarget,
                                                                  invocation.Method,
                                                                  invocation.Arguments);
            }

            var returnValue = processAsyncFunc();
            invocation.ReturnValue = returnValue;
        }

        public override void Intercept(IInvocation invocation)
        {
            var isTaskResult = typeof(Task).IsAssignableFrom(invocation.Method.ReturnType);
            var interceptorAttributes = GetInterceptorAttributes(invocation);

            if (interceptorAttributes.Length > 0)
            {
                if (isTaskResult)
                {
                    var resultType = GetTaskResultType(invocation);
                    if (resultType == null)
                    {
                        InterceptAsync(invocation, interceptorAttributes);
                    }
                    else
                    {
                        this.InvokeGenericMethod(nameof(InterceptAsync),
                                                 new object[] {invocation, interceptorAttributes},
                                                 resultType);
                    }
                }
                else
                {
                    if (invocation.Method.ReturnType != typeof(void))
                    {
{'fraction_non_alphanumeric': 0.06689524365334111, 'fraction_numerical': 0.0004377006127808579, 'mean_word_length': 1.6470361073566326, 'pattern_counts': {'":': 0, '<': 44, '<?xml version=': 0, '>': 56, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 48, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4233930', 'n_tokens_mistral': 2843, 'n_tokens_neox': 2673, 'n_words': 524}