/*******************************************************************************
 * Copyright (c) 2005, 2007 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.jdt.internal.compiler.apt.dispatch;

import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.ElementFilter;

import org.eclipse.jdt.internal.compiler.apt.model.Factory;
import org.eclipse.jdt.internal.compiler.apt.model.TypeElementImpl;
import org.eclipse.jdt.internal.compiler.apt.util.ManyToMany;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TagBits;

public class RoundEnvImpl implements RoundEnvironment
{
	private final BaseProcessingEnvImpl _processingEnv;
	private final boolean _isLastRound;
	private final CompilationUnitDeclaration[] _units;
	private final ManyToMany<TypeElement, Element> _annoToUnit;
	private final ReferenceBinding[] _binaryTypes;
	private final Factory _factory;
	private Set<Element> _rootElements = null;

	public RoundEnvImpl(CompilationUnitDeclaration[] units, ReferenceBinding[] binaryTypeBindings, boolean isLastRound, BaseProcessingEnvImpl env) {
		_processingEnv = env;
		_isLastRound = isLastRound;
		_units = units;
		_factory = _processingEnv.getFactory();
		
		// Discover the annotations that will be passed to Processor.process()
		AnnotationDiscoveryVisitor visitor = new AnnotationDiscoveryVisitor(_processingEnv);
		if (_units != null) {
			for (CompilationUnitDeclaration unit : _units) {
				unit.traverse(visitor, unit.scope);
			}
		}
		_annoToUnit = visitor._annoToElement;
		if (binaryTypeBindings != null) collectAnnotations(binaryTypeBindings);
		_binaryTypes = binaryTypeBindings;
	}

	private void collectAnnotations(ReferenceBinding[] referenceBindings) {
		for (ReferenceBinding referenceBinding : referenceBindings) {
			// collect all annotations from the binary types
			AnnotationBinding[] annotationBindings = referenceBinding.getAnnotations();
			for (AnnotationBinding annotationBinding : annotationBindings) {
				TypeElement anno = (TypeElement)_factory.newElement(annotationBinding.getAnnotationType()); 
				Element element = _factory.newElement(referenceBinding);
				_annoToUnit.put(anno, element);
			}
			FieldBinding[] fieldBindings = referenceBinding.fields();
			for (FieldBinding fieldBinding : fieldBindings) {
				annotationBindings = fieldBinding.getAnnotations();
				for (AnnotationBinding annotationBinding : annotationBindings) {
					TypeElement anno = (TypeElement)_factory.newElement(annotationBinding.getAnnotationType()); 
					Element element = _factory.newElement(fieldBinding);
					_annoToUnit.put(anno, element);
				}
			}
			MethodBinding[] methodBindings = referenceBinding.methods();
			for (MethodBinding methodBinding : methodBindings) {
				annotationBindings = methodBinding.getAnnotations();
				for (AnnotationBinding annotationBinding : annotationBindings) {
					TypeElement anno = (TypeElement)_factory.newElement(annotationBinding.getAnnotationType()); 
					Element element = _factory.newElement(methodBinding);
					_annoToUnit.put(anno, element);
				}
			}
			ReferenceBinding[] memberTypes = referenceBinding.memberTypes();
			collectAnnotations(memberTypes);
		}
	}

	/**
	 * Return the set of annotation types that were discovered on the root elements.
	 * This does not include inherited annotations, only those directly on the root
	 * elements.
	 * @return a set of annotation types, possibly empty.
	 */
	public Set<TypeElement> getRootAnnotations()
	{
		return Collections.unmodifiableSet(_annoToUnit.getKeySet());
	}

	@Override
	public boolean errorRaised()
	{
		return _processingEnv.errorRaised();
	}

	/**
	 * From the set of root elements and their enclosed elements, return the subset that are annotated
	 * with {@code a}.  If {@code a} is annotated with the {@link java.lang.annotations.Inherited} 
	 * annotation, include those elements that inherit the annotation from their superclasses.
	 * Note that {@link java.lang.annotations.Inherited} only applies to classes (i.e. TypeElements).
	 */
	@Override
	public Set<? extends Element> getElementsAnnotatedWith(TypeElement a)
	{
		if (a.getKind() != ElementKind.ANNOTATION_TYPE) {
			throw new IllegalArgumentException("Argument must represent an annotation type"); //$NON-NLS-1$
		}
		Binding annoBinding = ((TypeElementImpl)a)._binding;
		if (0 != (annoBinding.getAnnotationTagBits() & TagBits.AnnotationInherited)) {
			Set<Element> annotatedElements = new HashSet<Element>(_annoToUnit.getValues(a));
			// For all other root elements that are TypeElements, and for their recursively enclosed
			// types, add each element if it has a superclass are annotated with 'a'
			ReferenceBinding annoTypeBinding = (ReferenceBinding)((TypeElementImpl)a)._binding;
			for (TypeElement element : ElementFilter.typesIn(getRootElements())) {
				ReferenceBinding typeBinding = (ReferenceBinding)((TypeElementImpl)element)._binding;
				addAnnotatedElements(annoTypeBinding, typeBinding, annotatedElements);
			}
			return Collections.unmodifiableSet(annotatedElements);
		}
		return Collections.unmodifiableSet(_annoToUnit.getValues(a));
	}
	
	/**
	 * For every type in types that is a class and that is annotated with anno, either directly or by inheritance,
	 * add that type to result.  Recursively descend on each types's child classes as well.
	 * @param anno the compiler binding for an annotation type
	 * @param types a set of types, not necessarily all classes
	 * @param result must be a modifiable Set; will accumulate annotated classes
	 */
	private void addAnnotatedElements(ReferenceBinding anno, ReferenceBinding type, Set<Element> result) {
		if (type.isClass()) {
			if (inheritsAnno(type, anno)) {
				result.add(_factory.newElement(type));
			}
		}
		for (ReferenceBinding element : type.memberTypes()) {
			addAnnotatedElements(anno, element, result);
		}
	}
	
	/**
	 * Check whether an element has a superclass that is annotated with an @Inherited annotation.
	 * @param element must be a class (not an interface, enum, etc.).
	 * @param anno must be an annotation type, and must be @Inherited
	 * @return true if element has a superclass that is annotated with anno
	 */
	private boolean inheritsAnno(ReferenceBinding element, ReferenceBinding anno) {
		do {
			AnnotationBinding[] annos = element.getAnnotations();
			for (AnnotationBinding annoBinding : annos) {
				if (annoBinding.getAnnotationType() == anno) {
					// element is annotated with anno
					return true;
				}
			}
		} while (null != (element = element.superclass()));
		return false;
	}
	
	@Override
	public Set<? extends Element> getElementsAnnotatedWith(Class<? extends Annotation> a)
	{
		String canonicalName = a.getCanonicalName();
		if (canonicalName == null) {
			// null for anonymous and local classes or an array of those
			throw new IllegalArgumentException("Argument must represent an annotation type"); //$NON-NLS-1$
		}
		TypeElement annoType = _processingEnv.getElementUtils().getTypeElement(canonicalName);
		return getElementsAnnotatedWith(annoType);
	}

	@Override
	public Set<? extends Element> getRootElements()
	{
		if (_rootElements == null) {
			Set<Element> elements = new HashSet<Element>(_units.length);
			for (CompilationUnitDeclaration unit : _units) {
				if (null == unit.scope || null == unit.scope.topLevelTypes)
					continue;
				for (SourceTypeBinding binding : unit.scope.topLevelTypes) {
					Element element = _factory.newElement(binding);
					if (null == element) {
						throw new IllegalArgumentException("Top-level type binding could not be converted to element: " + binding); //$NON-NLS-1$
					}
					elements.add(element);
				}
			}
			if (this._binaryTypes != null) {
				for (ReferenceBinding typeBinding : _binaryTypes) {
					TypeElement element = (TypeElement)_factory.newElement(typeBinding);
					if (null == element) {
						throw new IllegalArgumentException("Top-level type binding could not be converted to element: " + typeBinding); //$NON-NLS-1$
					}
					elements.add(element);
				}
			}
			_rootElements = elements;
		}
		return _rootElements;
	}

	@Override
	public boolean processingOver()
	{
		return _isLastRound;
	}

}
