/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.commons.proxy2.stub;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;

import org.apache.commons.lang3.AnnotationUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.reflect.TypeUtils;
import org.apache.commons.proxy2.Interceptor;
import org.apache.commons.proxy2.Invocation;
import org.apache.commons.proxy2.Invoker;
import org.apache.commons.proxy2.ObjectProvider;
import org.apache.commons.proxy2.ProxyFactory;
import org.apache.commons.proxy2.ProxyUtils;
import org.apache.commons.proxy2.impl.AbstractProxyFactory;
import org.apache.commons.proxy2.provider.ObjectProviderUtils;

public class AnnotationBuilder<A extends Annotation> extends StubBuilder<A>
{
    // underlying proxyfactory implementation based on
    // org.apache.commons.proxy2.jdk.JdkProxyFactory

    private static class InterceptorInvocationHandler implements InvocationHandler, Serializable
    {
        /** Serialization version */
        private static final long serialVersionUID = 1L;

        private final ObjectProvider<?> provider;
        private final Interceptor methodInterceptor;

        public InterceptorInvocationHandler(ObjectProvider<?> provider, Interceptor methodInterceptor)
        {
            this.provider = provider;
            this.methodInterceptor = methodInterceptor;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
        {
            if (ProxyUtils.isHashCode(method))
            {
                return Integer.valueOf(AnnotationUtils.hashCode((Annotation) proxy));
            }
            if (ProxyUtils.isEqualsMethod(method))
            {
                return Boolean.valueOf(args[0] instanceof Annotation
                        && AnnotationUtils.equals((Annotation) proxy, (Annotation) args[0]));
            }
            if ("toString".equals(method.getName()) && method.getParameterTypes().length == 0)
            {
                return AnnotationUtils.toString((Annotation) proxy);
            }
            final ReflectionInvocation invocation = new ReflectionInvocation(provider.getObject(), method, args);
            return methodInterceptor.intercept(invocation);
        }

    }

    private static class ReflectionInvocation implements Invocation
    {
        private final Method method;
        private final Object[] arguments;
        private final Object target;

        public ReflectionInvocation(Object target, Method method, Object[] arguments)
        {
            this.method = method;
            this.arguments = ObjectUtils.defaultIfNull(ArrayUtils.clone(arguments), ProxyUtils.EMPTY_ARGUMENTS);
            this.target = target;
        }

        @Override
        public Object[] getArguments()
        {
            return arguments;
        }

        @Override
        public Method getMethod()
        {
            return method;
        }

        @Override
        public Object getProxy()
        {
            return target;
        }

        @Override
        public Object proceed() throws Throwable
        {
            try
            {
                return method.invoke(target, arguments);
            }
            catch (InvocationTargetException e)
            {
                throw e.getTargetException();
            }
        }
    }

    private static final ProxyFactory PROXY_FACTORY = new AbstractProxyFactory()
    {
        @Override
        @SuppressWarnings("unchecked")
        public <T> T createInvokerProxy(ClassLoader classLoader, final Invoker invoker, Class<?>... proxyClasses)
        {
            return (T) Proxy.newProxyInstance(classLoader, proxyClasses, new InvocationHandler()
            {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
                {
                    return invoker.invoke(proxy, method, args);
                }
            });
        }

        @Override
        @SuppressWarnings("unchecked")
        public <T> T createInterceptorProxy(ClassLoader classLoader, Object target, Interceptor interceptor,
                Class<?>... proxyClasses)
        {
            return (T) Proxy.newProxyInstance(classLoader, proxyClasses, new InterceptorInvocationHandler(
                    ObjectProviderUtils.constant(target), interceptor));
        }

        @Override
        @SuppressWarnings("unchecked")
        public <T> T createDelegatorProxy(ClassLoader classLoader, final ObjectProvider<?> delegateProvider,
                Class<?>... proxyClasses)
        {
            return (T) Proxy.newProxyInstance(classLoader, proxyClasses, new InterceptorInvocationHandler(
                    delegateProvider, new Interceptor()
                    {
                        private static final long serialVersionUID = 1L;

                        @Override
                        public Object intercept(Invocation invocation) throws Throwable
                        {
                            return invocation.proceed();
                        }
                    }));
        }
    };

    private class MapAnnotationTrainer extends AnnotationTrainer<A>
    {
        private final Map<String, ?> members;

        MapAnnotationTrainer(Map<String, ?> members)
        {
            super(annotationType);
            this.members = members;
        }

        @Override
        protected void train(A trainee)
        {
            WhenObject<Object> bud;
            AnnotationTrainer<A> dy = this;
            for (Map.Entry<String, ?> attr : members.entrySet())
            {
                final Method m;
                try
                {
                    m = traineeType.getDeclaredMethod(attr.getKey());
                }
                catch (Exception e1)
                {
                    throw new IllegalArgumentException(String.format("Could not detect annotation member %1$s",
                            attr.getKey()));
                }
                try
                {
                    bud = dy.when(m.invoke(trainee));
                }
                catch (Exception e)
                {
                    // it must have happened on the invoke, so we didn't call
                    // when... it shouldn't happen, but we'll simply skip:
                    continue;
                }
                final Object value = attr.getValue();
                Validate.isTrue(TypeUtils.isInstance(value, m.getReturnType()), "Value %s can not be assigned to %s",
                        value, m.getReturnType());
                dy = bud.thenReturn(value);
            }
        }
    }

    public static <A extends Annotation> A buildDefault(Class<A> type)
    {
        return of(type).build();
    }

    public static <A extends Annotation> AnnotationBuilder<A> of(Class<A> type)
    {
        return new AnnotationBuilder<A>(type, AnnotationInvoker.INSTANCE);
    }

    public static <A extends Annotation> AnnotationBuilder<A> of(Class<A> type, ObjectProvider<? extends A> provider)
    {
        return new AnnotationBuilder<A>(type, provider);
    }

    public static <A extends Annotation> AnnotationBuilder<A> of(Class<A> type, A target)
    {
        return new AnnotationBuilder<A>(type, target);
    }

    private final Class<A> annotationType;

    private AnnotationBuilder(Class<A> type, Invoker invoker)
    {
        super(PROXY_FACTORY, type, invoker);
        this.annotationType = type;
        train(new AnnotationTypeTrainer<A>(type));
    }

    private AnnotationBuilder(Class<A> type, ObjectProvider<? extends A> provider)
    {
        super(PROXY_FACTORY, type, provider);
        this.annotationType = type;
        train(new AnnotationTypeTrainer<A>(type));
    }

    private AnnotationBuilder(Class<A> type, A target)
    {
        super(PROXY_FACTORY, type, target);
        this.annotationType = type;
        train(new AnnotationTypeTrainer<A>(type));
    }

    public AnnotationBuilder<A> withMembers(Map<String, ?> members)
    {
        return train(new MapAnnotationTrainer(members));
    }

    @Override
    public <O> AnnotationBuilder<A> train(BaseTrainer<?, O> trainer)
    {
        return (AnnotationBuilder<A>) super.train(trainer);
    }
}
