/*
 * Copyright (c) 2009 OrangeSignal.com All rights reserved.
 * 
 * これは Apache ライセンス Version 2.0 (以下、このライセンスと記述) に
 * 従っています。このライセンスに準拠する場合以外、このファイルを使用
 * してはなりません。このライセンスのコピーは以下から入手できます。
 * 
 * http://www.apache.org/licenses/LICENSE-2.0.txt
 * 
 * 適用可能な法律がある、あるいは文書によって明記されている場合を除き、
 * このライセンスの下で配布されているソフトウェアは、明示的であるか暗黙の
 * うちであるかを問わず、「保証やあらゆる種類の条件を含んでおらず」、
 * 「あるがまま」の状態で提供されるものとします。
 * このライセンスが適用される特定の許諾と制限については、このライセンス
 * を参照してください。
 */

package jp.sf.orangesignal.ta.data.annotation;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

/**
 * 注釈型に関するユーティリティを提供します。
 * 
 * @author 杉澤 浩二
 * @since 2.1
 */
abstract class AnnotationUtils {

	private static final String VALUE = "value";
/*
	@SuppressWarnings("unchecked")
    public static <T> List<Constructor<T>> getAnnotatedConstructors(final Class<T> clazz, final Class<? extends Annotation> annotationClass) {
		final Constructor<T>[] fields = (Constructor<T>[]) clazz.getDeclaredConstructors();
		final ArrayList<Constructor<T>> list = new ArrayList<Constructor<T>>(fields.length);
		for (final Constructor<T> field : fields) {
			if (field.getAnnotation(annotationClass) != null)
				list.add(field);
		}
		list.trimToSize();
		return list;
	}

	public static <T> List<Field> getAnnotatedFields(final Class<T> clazz, final Class<? extends Annotation> annotationClass) {
		final Field[] fields = clazz.getDeclaredFields();
		final ArrayList<Field> list = new ArrayList<Field>(fields.length);
		for (final Field field : fields) {
			if (field.getAnnotation(annotationClass) != null)
				list.add(field);
		}
		list.trimToSize();
		return list;
	}

	public static <T> List<Method> getAnnotatedMethods(final Class<T> clazz, final Class<? extends Annotation> annotationClass) {
		final Method[] methods = clazz.getDeclaredMethods();
		final ArrayList<Method> list = new ArrayList<Method>(methods.length);
		for (final Method method : methods) {
			if (method.getAnnotation(annotationClass) != null)
				list.add(method);
		}
		list.trimToSize();
		return list;
	}
*/
/*
	public static <A extends Annotation> A getAnnotation(Method method, Class<A> annotationType) {
		return BridgeMethodResolver.findBridgedMethod(method).getAnnotation(annotationType);
	}

	public static <A extends Annotation> A findAnnotation(final Method method, final Class<A> annotationType) {
		A annotation = getAnnotation(method, annotationType);
		Class<?> cl = method.getDeclaringClass();
		while (annotation == null) {
			cl = cl.getSuperclass();
			if (cl == null || cl.equals(Object.class)) {
				break;
			}
			try {
				Method equivalentMethod = cl.getDeclaredMethod(method.getName(), method.getParameterTypes());
				annotation = getAnnotation(equivalentMethod, annotationType);
			}
			catch (NoSuchMethodException ex) {
				// We're done...
			}
		}
		return annotation;
	}
*/
/*
	public static <A extends Annotation> A findAnnotation(final Class<?> clazz, final Class<A> annotationType) {
		if (clazz == null)
			throw new NullPointerException("Class must not be null");
		A annotation = clazz.getAnnotation(annotationType);
		if (annotation != null)
			return annotation;

		for (final Class<?> interfaceClass : clazz.getInterfaces()) {
			annotation = findAnnotation(interfaceClass, annotationType);
			if (annotation != null)
				return annotation;
		}
		if (clazz.getSuperclass() == null || Object.class.equals(clazz.getSuperclass())) {
			return null;
		}
		return findAnnotation(clazz.getSuperclass(), annotationType);
	}

	public static Class<?> findAnnotationDeclaringClass(final Class<?> clazz, final Class<? extends Annotation> annotationType) {
		if (annotationType == null)
			throw new NullPointerException("Annotation type must not be null");
		if (clazz == null || clazz.equals(Object.class))
			return null;
		return isAnnotationDeclaredLocally(clazz, annotationType) ?
				clazz : findAnnotationDeclaringClass(clazz.getSuperclass(), annotationType);
	}

	public static boolean isAnnotationDeclaredLocally(final Class<?> clazz, final Class<? extends Annotation> annotationType) {
		if (clazz == null)
			throw new NullPointerException("Class must not be null");
		if (annotationType == null)
			throw new NullPointerException("Annotation type must not be null");
		for (final Annotation annotation : clazz.getDeclaredAnnotations()) {
			if (annotation.annotationType().equals(annotationType))
				return true;
		}
		return false;
	}

	public static boolean isAnnotationInherited(final Class<?> clazz, final Class<? extends Annotation> annotationType) {
		if (clazz == null)
			throw new NullPointerException("Class must not be null");
		if (annotationType == null)
			throw new NullPointerException("Annotation type must not be null");
		return clazz.isAnnotationPresent(annotationType) && !isAnnotationDeclaredLocally(clazz, annotationType);
	}
*/
	public static Object getValue(final Annotation annotation) {
		return getValue(annotation, VALUE);
	}

	public static Object getValue(final Annotation annotation, final String attributeName) {
		try {
			final Method method = annotation.annotationType().getDeclaredMethod(attributeName, new Class[0]);
			return method.invoke(annotation);
		} catch (Exception e) {
			return null;
		}
	}

	public static Object getDefaultValue(final Annotation annotation) {
		return getDefaultValue(annotation, VALUE);
	}

	public static Object getDefaultValue(final Annotation annotation, final String attributeName) {
		return getDefaultValue(annotation.annotationType(), attributeName);
	}

	public static Object getDefaultValue(final Class<? extends Annotation> annotationType) {
		return getDefaultValue(annotationType, VALUE);
	}

	public static Object getDefaultValue(final Class<? extends Annotation> annotationType, final String attributeName) {
		try {
			final Method method = annotationType.getDeclaredMethod(attributeName, new Class[0]);
			return method.getDefaultValue();
		} catch (Exception e) {
			return null;
		}
	}

}
