/*
 * Copyright 2011-2016 B2i Healthcare Pte Ltd, http://b2i.sg
 * 
 * Licensed 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 com.b2international.index.util;

import static com.google.common.collect.Sets.newHashSet;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;

import com.b2international.index.IndexException;

/**
 * @since 4.7
 */
public class Reflections {

	private Reflections() {
	}
	
	public static Object getValue(Object object, Field field) {
		try {
			return field.get(object);
		} catch (IllegalArgumentException | IllegalAccessException e) {
			throw new IndexException("Couldn't get value from field " + field, e);
		}
	}
	
	public static Collection<Field> getFields(Class<?> type) {
		if (type == Object.class) {
			return Collections.emptySet();
		}
		final Set<Field> fields = newHashSet();
		if (type.getSuperclass() != null) {
			fields.addAll(getFields(type.getSuperclass()));
		}
		for (Field field : type.getDeclaredFields()) {
			field.setAccessible(true);
			fields.add(field);
		}
		return fields;
	}
	
	public static Class<?> getType(Field field) {
		final Type fieldType = field.getGenericType();
		if (fieldType instanceof ParameterizedType) {
			final ParameterizedType pType = (ParameterizedType) fieldType;
			return (Class<?>) pType.getActualTypeArguments()[0];
		} else if (fieldType instanceof Class) {
			return (Class<?>) fieldType;
		} else {
			throw new UnsupportedOperationException("Unsupported field type: " + fieldType.getClass());
		}
	}

	public static Field getField(Class<?> type, String field) {
		try {
			return type.getDeclaredField(field);
		} catch (NoSuchFieldException | SecurityException e) {
			throw new IndexException("Couldn't find field " + field, e);
		}
	}

	public static Class<?> getFieldType(Class<?> type, String field) {
		return getType(getField(type, field));
	}
	
}

@@ -2198,112 +2198,101 @@
 %7B%0A%09%09
-try %7B%0A%09%09%09return type.getDeclaredField(field);%0A%09%09%7D catch (NoSuchFieldException %7C SecurityException e) %7B%0A%09
+for (Field f : getFields(type)) %7B%0A%09%09%09if (f.getName().equals(field)) %7B%0A%09%09%09%09return f;%0A%09%09%09%7D%0A%09%09%7D%0A
 %09%09th
@@ -2340,33 +2340,63 @@
 ld %22 + field
-, e);%0A%09%09%7D
+ + %22 on type %22 + type.getName(), null);
 %0A%09%7D%0A%0A%09public

fix lookup of nested fields