/*
 * 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.webbeans.inject.impl;

import org.apache.webbeans.annotation.AnnotationManager;
import org.apache.webbeans.annotation.NamedLiteral;
import org.apache.webbeans.config.WebBeansContext;
import org.apache.webbeans.exception.WebBeansConfigurationException;
import org.apache.webbeans.portable.events.generics.GProcessInjectionPoint;
import org.apache.webbeans.util.AnnotationUtil;
import org.apache.webbeans.util.Asserts;

import javax.enterprise.event.Observes;
import javax.enterprise.event.ObservesAsync;
import javax.enterprise.inject.Disposes;
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.AnnotatedCallable;
import javax.enterprise.inject.spi.AnnotatedConstructor;
import javax.enterprise.inject.spi.AnnotatedField;
import javax.enterprise.inject.spi.AnnotatedMethod;
import javax.enterprise.inject.spi.AnnotatedParameter;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.inject.Inject;
import javax.inject.Named;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class InjectionPointFactory
{
    private final WebBeansContext webBeansContext;

    public InjectionPointFactory(WebBeansContext webBeansContext)
    {
        this.webBeansContext = webBeansContext;
    }

    public <X> Set<InjectionPoint> buildInjectionPoints(Bean<X> owner, AnnotatedType<X> annotatedType)
    {
        Set<InjectionPoint> injectionPoints = new HashSet<>();
        boolean constructorFound = false;
        for (AnnotatedConstructor<X> constructor: annotatedType.getConstructors())
        {
            if (constructor.isAnnotationPresent(Inject.class))
            {
                if (constructorFound)
                {
                    throw new WebBeansConfigurationException("There are more than one constructor with @Inject annotation in annotation type : "
                            + annotatedType);
                }
                constructorFound = true;
                validateInitializerConstructor(constructor);
                buildInjectionPoints(owner, constructor, injectionPoints);
            }
        }
        for (AnnotatedField<? super X> field: annotatedType.getFields())
        {
            if (owner != null && Modifier.isPublic(field.getJavaMember().getModifiers()) && !field.isStatic())
            {
                if (webBeansContext.getBeanManagerImpl().isNormalScope(owner.getScope()))
                {
                    throw new WebBeansConfigurationException("If bean has a public field, bean scope must be defined as @Scope. Bean is : "
                            + owner.getBeanClass().getName());
                }
            }                
            if (field.isAnnotationPresent(Inject.class))
            {
                injectionPoints.add(buildInjectionPoint(owner, field));
            }
        }
        for (AnnotatedMethod<? super X> method: webBeansContext.getAnnotatedElementFactory().getFilteredAnnotatedMethods(annotatedType))
        {
            if (method.isAnnotationPresent(Inject.class) && !Modifier.isStatic(method.getJavaMember().getModifiers()))
            {
                validateInitializerMethod(method);
                buildInjectionPoints(owner, method, injectionPoints);
            }
        }
        return injectionPoints;
    }

    public <X> InjectionPoint buildInjectionPoint(Bean<?> owner, AnnotatedField<X> annotField, boolean fireEvent)
    {
        Asserts.assertNotNull(annotField, "annotField");

        Annotation[] annots = AnnotationUtil.asArray(annotField.getAnnotations());
        Annotation[] qualifierAnnots = webBeansContext.getAnnotationManager().getQualifierAnnotations(annots);

        //@Named update for injection fields!
        for (int i = 0; i < qualifierAnnots.length; i++)
        {
            Annotation qualifier = qualifierAnnots[i];
            if (qualifier.annotationType().equals(Named.class))
            {
                Named named = (Named) qualifier;
                String value = named.value();

                if (value == null || value.isEmpty())
                {
                    NamedLiteral namedLiteral = new NamedLiteral();
                    namedLiteral.setValue(annotField.getJavaMember().getName());
                    qualifierAnnots[i] = namedLiteral;
                }

                break;
            }
        }

        InjectionPoint injectionPoint = new InjectionPointImpl(owner, Arrays.asList(qualifierAnnots), annotField);

        if (fireEvent)
        {
            GProcessInjectionPoint event = webBeansContext.getWebBeansUtil().fireProcessInjectionPointEvent(injectionPoint);
            injectionPoint = event.getInjectionPoint();
            event.setStarted();
        }

        return injectionPoint;

    }

    public <X> InjectionPoint buildInjectionPoint(Bean<?> owner, AnnotatedField<X> annotField)
    {
        return buildInjectionPoint(owner, annotField, true);
    }

    public <X> InjectionPoint buildInjectionPoint(Bean<?> owner, AnnotatedParameter<X> parameter, boolean fireEvent)
    {
        Asserts.assertNotNull(parameter, "annotatedParameter");
        Set<Annotation> anns = parameter.getAnnotations();
        Annotation[] qualifierAnnots = webBeansContext.getAnnotationManager().getQualifierAnnotations(anns.toArray(new Annotation[anns.size()]));
        InjectionPointImpl injectionPoint = new InjectionPointImpl(owner, Arrays.asList(qualifierAnnots), parameter);
        if (fireEvent)
        {
            GProcessInjectionPoint event = webBeansContext.getWebBeansUtil().fireProcessInjectionPointEvent(injectionPoint);
            InjectionPoint ip = event.getInjectionPoint();
            event.setStarted();
            return ip;
        }
        return injectionPoint;
    }

    public <X> List<InjectionPoint> buildInjectionPoints(Bean<?> owner, AnnotatedCallable<X> callable)
    {
        List<InjectionPoint> lists = new ArrayList<>();
        buildInjectionPoints(owner, callable, lists);
        return lists;
    }

    private <X> void buildInjectionPoints(Bean<?> owner, AnnotatedCallable<X> callable, Collection<InjectionPoint> lists)
    {
        List<AnnotatedParameter<X>> parameters = callable.getParameters();

        for (AnnotatedParameter<?> parameter : parameters)
        {
            // @Observes and @ObservesAsync are not injection point type for method parameters
            if (parameter.getAnnotation(Observes.class) == null && parameter.getAnnotation(ObservesAsync.class) == null)
            {
                lists.add(buildInjectionPoint(owner, parameter, true));
            }
        }
    }

    public static InjectionPoint getPartialInjectionPoint(Bean<?> owner, AnnotatedParameter<?> parameter, Collection<Annotation> bindings)
    {
        return new InjectionPointImpl(owner, bindings, parameter);
    }

    /**
     * This method gets used for InjectionPoints needed during programmatic lookup.
     */
    public static InjectionPoint getVirtualInjectionPoint(Bean<?> bean)
    {
        return new InjectionPointImpl(bean);
    }

    private void validateInitializerConstructor(AnnotatedConstructor<?> constructor)
    {
        for (AnnotatedParameter<?> parameter: constructor.getParameters())
        {
            if (parameter.isAnnotationPresent(Disposes.class))
            {
                throw new WebBeansConfigurationException("Constructor parameter annotations can not contain @Disposes annotation in annotated constructor : " + constructor);
            }

            if(parameter.isAnnotationPresent(Observes.class) || parameter.isAnnotationPresent(ObservesAsync.class))
            {
                throw new WebBeansConfigurationException("Constructor parameter annotations can not contain @Observes nor @ObservesAsync annotation in annotated constructor : "
                                                         + constructor);
            }
        }
    }

    /**
     * add the definitions for a &#x0040;Initializer method.
     */
    private void validateInitializerMethod(AnnotatedMethod<?> annotatedMethod)
    {
        Method method = annotatedMethod.getJavaMember();
        
        TypeVariable<?>[] args = method.getTypeParameters();
        if(args.length > 0)
        {
            throw new WebBeansConfigurationException("Error in defining injected methods in annotated method : " + annotatedMethod+ 
                    ". Reason : Initializer methods must not be generic.");
        }
        
        if (annotatedMethod.isAnnotationPresent(Produces.class))
        {
            throw new WebBeansConfigurationException("Error in defining injected methods in annotated method : " + annotatedMethod+ 
            ". Reason : Initializer method can not be annotated with @Produces.");
        
        }

        AnnotationManager annotationManager = webBeansContext.getAnnotationManager();

        for (AnnotatedParameter<?> annotatedParameter : annotatedMethod.getParameters())
        {
            annotationManager.checkForNewQualifierForDeployment(annotatedParameter.getBaseType(), annotatedMethod.getDeclaringType().getJavaClass(),
                    method.getName(), AnnotationUtil.asArray(annotatedParameter.getAnnotations()));

            if (annotatedParameter.isAnnotationPresent(Disposes.class) ||
                annotatedParameter.isAnnotationPresent(Observes.class) ||
                annotatedParameter.isAnnotationPresent(ObservesAsync.class))
            {
                throw new WebBeansConfigurationException("Error in defining injected methods in annotated method : " + annotatedMethod+ 
                ". Reason : Initializer method parameters does not contain @Observes, @ObservesAsync or @Dispose annotations.");
                
            }
        }
    }
}
