/*
 * 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.osgi.util.converter;

import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NavigableMap;
import java.util.NavigableSet;
import java.util.Queue;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentNavigableMap;
import java.util.concurrent.ConcurrentSkipListMap;

/**
 * @author $Id$
 */
class ConvertingImpl extends AbstractSpecifying<Converting>
		implements Converting, InternalConverting {
	private static final Map<Class< ? >,Class< ? >>	INTERFACE_IMPLS;
	// Interfaces with no methods are also not considered
	private static final Collection<Class< ? >>		NO_MAP_VIEW_TYPES;
	static {

		Map<Class< ? >,Class< ? >> cim = new HashMap<>();
		cim.put(Collection.class, ArrayList.class);
		// Lists
		cim.put(List.class, ArrayList.class);
		// Sets
		cim.put(Set.class, LinkedHashSet.class); // preserves insertion order
		cim.put(NavigableSet.class, TreeSet.class);
		cim.put(SortedSet.class, TreeSet.class);
		// Queues
		cim.put(Queue.class, LinkedList.class);
		cim.put(Deque.class, LinkedList.class);

		Map<Class< ? >,Class< ? >> iim = new HashMap<>(cim);
		// Maps
		iim.put(Map.class, LinkedHashMap.class); // preserves insertion order
		iim.put(ConcurrentMap.class, ConcurrentHashMap.class);
		iim.put(ConcurrentNavigableMap.class, ConcurrentSkipListMap.class);
		iim.put(NavigableMap.class, TreeMap.class);
		iim.put(SortedMap.class, TreeMap.class);

		Set<Class< ? >> nmv = new HashSet<>(cim.keySet());
		nmv.addAll(Arrays.<Class< ? >> asList(String.class, Class.class,
				Comparable.class, CharSequence.class, Map.Entry.class));
		// The following classes are only available from Java 12 onwards
		addClassIfAvailable("java.lang.constant.Constable", nmv);
		addClassIfAvailable("java.lang.constant.ConstantDesc", nmv);

		INTERFACE_IMPLS = Collections.unmodifiableMap(iim);
		NO_MAP_VIEW_TYPES = Collections.unmodifiableSet(nmv);
	}

	private static void addClassIfAvailable(String cls, Collection<Class<?>> collection) {
	    try {
	        Class<?> clazz = ConvertingImpl.class.getClassLoader().loadClass(cls);
	        collection.add(clazz);
	    } catch (Exception ex) {
	        // Class not available, to nothing
	    }
	}

	private final InternalConverter converter;
	private volatile Object		object;
	private volatile Class< ? >	sourceClass;
	private volatile Class< ? >	targetClass;
	private volatile Type[]		typeArguments;
	private volatile Type		targetType;

	ConvertingImpl(InternalConverter c, Object obj) {
		converter = c;
		object = obj;
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> T to(Class<T> cls) {
		Type type = cls;
		return (T) to(type);
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> T to(TypeReference<T> ref) {
		return (T) to(ref.getType());
	}

	@SuppressWarnings("unchecked")
	@Override
	public Object to(Type type) {
	    return to(type, converter);
	}

	@SuppressWarnings("unchecked")
    @Override
    public Object to(Type type, InternalConverter c) {
		// Wildcard types are strange - we immediately resolve them to something
		// that we can actually use.
		if (type instanceof WildcardType) {
			WildcardType wt = (WildcardType) type;
			Type[] lowerBounds = wt.getLowerBounds();
			if(lowerBounds.length != 0) {
				// This is a ? super X generic, why on earth would you do this?
				throw new ConversionException("The authors of this implementation have no idea what to do with the type variable " +
				wt.getTypeName() + ". The use of <? super ...> is highly ambiguous for the converter");
			} else {
				type = wt.getUpperBounds()[0];
			}
		}

		Class< ? > cls = null;
		if (type instanceof Class) {
			cls = (Class< ? >) type;
		} else if (type instanceof ParameterizedType) {
			ParameterizedType pt = (ParameterizedType) type;
			Type rt = pt.getRawType();
			typeArguments = pt.getActualTypeArguments();
			if (rt instanceof Class)
				cls = (Class< ? >) rt;
		} else if (type instanceof GenericArrayType) {
			GenericArrayType pt = (GenericArrayType) type;
			Type rt = pt.getGenericComponentType();
			if (rt instanceof Class)
				cls = (Class< ? >) rt;
			else if (rt instanceof ParameterizedType) {
				Type rt2 = ((ParameterizedType) rt).getRawType();
				if (rt2 instanceof Class) {
					cls = (Class< ? >) rt2;
				}
			}

		}
		targetType = type;
		if (cls == null)
			return null;

		if (object == null)
			return handleNull(cls, c);

		targetClass = Util.primitiveToBoxed(cls);
		if (targetAsClass == null)
			targetAsClass = targetClass;

		sourceClass = sourceAsClass != null ? sourceAsClass : object.getClass();

		if (!isCopyRequiredType(targetAsClass)
				&& targetAsClass.isAssignableFrom(sourceClass)) {
			return object;
		}

		Object res = trySpecialCases(c);
		if (res != null)
			return res;

		if (targetAsClass.isArray()) {
			return convertToArray(targetAsClass.getComponentType(),
					targetAsClass.getComponentType(), c);
		} else if (type instanceof GenericArrayType) {
			return convertToArray(targetAsClass,
					((GenericArrayType) type).getGenericComponentType(), c);
		} else if (Collection.class.isAssignableFrom(targetAsClass)) {
			return convertToCollectionType(c);
		} else if (isMapType(targetAsClass, targetAsJavaBean, targetAsDTO)) {
			return convertToMapType(c);
		}

		// At this point we know that the target is a 'singular' type: not a
		// map, collection or array
		if (Collection.class.isAssignableFrom(sourceClass)) {
			return convertCollectionToSingleValue(targetAsClass, c);
		} else if (isMapType(sourceClass, sourceAsJavaBean, sourceAsDTO)) {
			return convertMapToSingleValue(targetAsClass, c);
		} else if (object instanceof Map.Entry) {
			return convertMapEntryToSingleValue(targetAsClass, c);
		} else if ((object = asBoxedArray(object)) instanceof Object[]) {
			return convertArrayToSingleValue(targetAsClass, c);
		}

		Object res2 = tryStandardMethods();
		if (res2 != null) {
			return res2;
		} else {
			if (hasDefault)
				return c.convert(defaultValue)
						.sourceAs(sourceAsClass)
						.targetAs(targetAsClass)
						.to(targetClass);
			else
				throw new ConversionException(
						"Cannot convert " + object + " to " + targetAsClass);
		}
	}

	private Object convertArrayToSingleValue(Class< ? > cls, InternalConverter c) {
		Object[] arr = (Object[]) object;
		if (arr.length == 0)
			return null;
		else
			return c.convert(arr[0]).to(cls);
	}

	private Object convertCollectionToSingleValue(Class< ? > cls, InternalConverter c) {
		Collection< ? > coll = (Collection< ? >) object;
		if (coll.size() == 0)
			return null;
		else
			return c.convert(coll.iterator().next()).to(cls);
	}

	private Object convertMapToSingleValue(Class< ? > cls, InternalConverter c) {
		Map< ? , ? > m = mapView(object, sourceClass, c);
		if (m.size() > 0) {
			return c.convert(m.entrySet().iterator().next()).to(cls);
		} else {
			return null;
		}
	}

	@SuppressWarnings("rawtypes")
	private Object convertMapEntryToSingleValue(Class< ? > cls, InternalConverter c) {
		Map.Entry entry = (Map.Entry) object;

		Class keyCls = entry.getKey() != null ? entry.getKey().getClass()
				: null;
		Class valueCls = entry.getValue() != null ? entry.getValue().getClass()
				: null;

		if (cls.equals(keyCls)) {
			return c.convert(entry.getKey()).to(cls);
		} else if (cls.equals(valueCls)) {
			return c.convert(entry.getValue()).to(cls);
		} else if (keyCls != null && cls.isAssignableFrom(keyCls)) {
			return c.convert(entry.getKey()).to(cls);
		} else if (valueCls != null && cls.isAssignableFrom(valueCls)) {
			return c.convert(entry.getValue()).to(cls);
		} else if (entry.getKey() instanceof String) {
			return c.convert(entry.getKey()).to(cls);
		} else if (entry.getValue() instanceof String) {
			return c.convert(entry.getValue()).to(cls);
		}

		return c.convert(c.convert(entry.getKey()).to(String.class))
				.to(cls);
	}

	@SuppressWarnings("unchecked")
	private <T> T convertToArray(Class< ? > componentClz, Type componentType, InternalConverter c) {
		Collection< ? > collectionView = collectionView(c);
		Iterator< ? > itertor = collectionView.iterator();
		try {
			Object array = Array.newInstance(componentClz,
					collectionView.size());
			for (int i = 0; i < collectionView.size()
					&& itertor.hasNext(); i++) {
				Object next = itertor.next();
				Object converted = c.convert(next)
						.to(componentType);
				Array.set(array, i, converted);
			}
			return (T) array;
		} catch (Exception e) {
			return null;
		}
	}

	@SuppressWarnings("unchecked")
	private <T> T convertToCollectionType(InternalConverter c) {
		Collection< ? > res = convertToCollectionDelegate(c);
		if (res != null)
			return (T) res;

		return convertToCollection(c);
	}

	private Collection< ? > convertToCollectionDelegate(InternalConverter c) {
		if (!liveView)
			return null;

		if (List.class.equals(targetClass)
				|| Collection.class.equals(targetClass)) {
			if (sourceClass.isArray()) {
				return ListDelegate.forArray(object, this, c);
			} else if (Collection.class.isAssignableFrom(sourceClass)) {
				return ListDelegate.forCollection((Collection< ? >) object,
						this, c);
			}
		} else if (Set.class.equals(targetClass)) {
			if (sourceClass.isArray()) {
				return SetDelegate.forCollection(
						ListDelegate.forArray(object, this, c), this, c);
			} else if (Collection.class.isAssignableFrom(sourceClass)) {
				return SetDelegate.forCollection((Collection< ? >) object,
						this, c);
			}
		}
		return null;
	}

	@SuppressWarnings({
			"rawtypes", "unchecked"
	})
	private <T> T convertToCollection(InternalConverter c) {
		Collection< ? > cv = collectionView(c);
		Class< ? > targetElementType = null;
		if (typeArguments != null && typeArguments.length > 0
				&& typeArguments[0] instanceof Class) {
			targetElementType = (Class< ? >) typeArguments[0];
		}

		Class< ? > ctrCls = INTERFACE_IMPLS.get(targetAsClass);
		Class< ? > targetCls;
		if (ctrCls != null)
			targetCls = ctrCls;
		else
			targetCls = targetAsClass;

		Collection instance = (Collection) createMapOrCollection(targetCls,
				cv.size());
		if (instance == null)
			return null;

		for (Object o : cv) {
			if (targetElementType != null) {
				try {
					o = c.convert(o).to(targetElementType);
				} catch (ConversionException ce) {
					if (hasDefault) {
						return (T) defaultValue;
					}
				}
			}

			instance.add(o);
		}

		return (T) instance;
	}

	@SuppressWarnings({
			"rawtypes", "unchecked"
	})
	private <T> T convertToDTO(Class< ? > sourceCls, Class< ? > targetAsCls, InternalConverter c) {
		Map m = mapView(object, sourceCls, c);

		try {
			String prefix = Util.getPrefix(targetAsCls);

			T dto = (T) targetClass.newInstance();

			List<String> names = getNames(targetAsClass);
			for (Map.Entry entry : (Set<Map.Entry>) m.entrySet()) {
				Object key = entry.getKey();
				if (key == null)
					continue;

				String fieldName = Util.mangleName(prefix, key.toString(), names);
				if (fieldName == null)
					continue;

				Field f = null;
				try {
					f = targetAsCls.getField(fieldName);
				} catch (NoSuchFieldException e) {
					// There is no field with this name
					if (keysIgnoreCase) {
						// If enabled, try again but now ignore case
						for (Field fs : targetAsCls.getFields()) {
							if (fs.getName().equalsIgnoreCase(fieldName)) {
								f = fs;
								break;
							}
						}

						if (f == null) {
							for (Field fs : targetAsCls.getFields()) {
								if (fs.getName()
										.equalsIgnoreCase(fieldName)) {
									f = fs;
									break;
								}
							}
						}
					}
				}

				if (f != null) {
					Object val = entry.getValue();
					if (sourceAsDTO && DTOUtil.isDTOType(f.getType(), false))
						val = c.convert(val).sourceAsDTO().to(
								f.getType());
					else {
						Type genericType = reifyType(f.getGenericType(),
								targetAsClass, typeArguments);
						val = c.convert(val).to(genericType);
					}
					f.set(dto, val);
				}
			}

			return dto;
		} catch (Exception e) {
			throw new ConversionException("Cannot create DTO " + targetClass,
					e);
		}
	}

	static Type reifyType(Type typeToReify, Class< ? > ownerClass,
			Type[] typeArgs) {

		if (typeToReify instanceof TypeVariable) {
			String name = ((TypeVariable< ? >) typeToReify).getName();
			for (int i = 0; i < ownerClass.getTypeParameters().length; i++) {
				TypeVariable< ? > typeVariable = ownerClass
						.getTypeParameters()[i];
				if (typeVariable.getName().equals(name)) {
					return typeArgs[i];
				}
			}

			// The direct type variable wasn't found, maybe it was already
			// bound in this class.

			Type currentType = ownerClass;
			while (currentType != null) {
				if (currentType instanceof Class) {
					currentType = ((Class< ? >) currentType)
							.getGenericSuperclass();
				} else if (currentType instanceof ParameterizedType) {
					currentType = ((ParameterizedType) currentType)
							.getRawType();
				}

				if (currentType instanceof ParameterizedType) {
					ParameterizedType pt = (ParameterizedType) currentType;
					Type rawType = pt.getRawType();
					if (rawType instanceof Class) {
						return reifyType(typeToReify, (Class< ? >) rawType,
								pt.getActualTypeArguments());
					}
				}
			}
		} else if (typeToReify instanceof ParameterizedType) {
			final ParameterizedType parameterizedType = (ParameterizedType) typeToReify;
			Type[] parameters = parameterizedType.getActualTypeArguments();
			boolean useCopy = false;
			final Type[] copiedParameters = new Type[parameters.length];

			for (int i = 0; i < parameters.length; i++) {
				copiedParameters[i] = reifyType(parameters[i], ownerClass,
						typeArgs);
				useCopy |= copiedParameters[i] != parameters[i];
			}

			if (useCopy) {
				return new ParameterizedType() {

					@Override
					public Type getRawType() {
						return parameterizedType.getRawType();
					}

					@Override
					public Type getOwnerType() {
						return parameterizedType.getOwnerType();
					}

					@Override
					public Type[] getActualTypeArguments() {
						return Arrays.copyOf(copiedParameters,
								copiedParameters.length);
					}
				};
			}
		} else if (typeToReify instanceof GenericArrayType) {
			GenericArrayType type = (GenericArrayType) typeToReify;
			Type genericComponentType = type.getGenericComponentType();
			final Type reifiedType = reifyType(genericComponentType, ownerClass,
					typeArgs);

			if (reifiedType != genericComponentType) {
				return new GenericArrayType() {

					@Override
					public Type getGenericComponentType() {
						return reifiedType;
					}
				};
			}
		}

		return typeToReify;
	}

	private List<String> getNames(Class< ? > cls) {
		List<String> names = new ArrayList<>();
		for (Field field : cls.getFields()) {
			int modifiers = field.getModifiers();
			if (Modifier.isStatic(modifiers))
				continue;

			String name = field.getName();
			if (!names.contains(name))
				names.add(name);

		}
		return names;
	}

	@SuppressWarnings({
			"rawtypes", "unchecked"
	})
	private Map convertToMap(InternalConverter c) {
		Map m = mapView(object, sourceClass, c);
		if (m == null)
			return null;

		Class< ? > ctrCls = INTERFACE_IMPLS.get(targetClass);
		if (ctrCls == null)
			ctrCls = targetClass;

		Map instance = (Map) createMapOrCollection(ctrCls, m.size());
		if (instance == null)
			return null;

		for (Map.Entry entry : (Set<Entry>) m.entrySet()) {
			Object key = entry.getKey();
			Object value = entry.getValue();
			key = convertMapKey(key, c);
			value = convertMapValue(value, c);
			instance.put(key, value);
		}

		return instance;
	}

	Object convertCollectionValue(Object element, InternalConverter c) {
		Type type = null;
		if (typeArguments != null && typeArguments.length > 0) {
			type = typeArguments[0];
		}

		if (element != null) {
			if (type != null) {
				element = c.convert(element).to(type);
			} else {
				Class< ? > cls = element.getClass();
				if (isCopyRequiredType(cls)) {
					cls = getConstructableType(cls);
				}
				// Either force source as DTO, or lenient DTO type
				if (sourceAsDTO || DTOUtil.isDTOType(cls, true))
					element = c.convert(element).sourceAsDTO().to(cls);
				else
					element = c.convert(element).to(cls);
			}
		}
		return element;
	}

	Object convertMapKey(Object key, InternalConverter c) {
		return convertMapElement(key, 0, c);
	}

	Object convertMapValue(Object value, InternalConverter c) {
		return convertMapElement(value, 1, c);
	}

	private Object convertMapElement(Object element, int typeIdx, InternalConverter c) {
		Type type = null;
		if (typeArguments != null && typeArguments.length > typeIdx) {
			type = typeArguments[typeIdx];
		}

		if (element != null) {
			if (type != null) {
				element = c.convert(element).to(type);
			} else {
				Class< ? > cls = element.getClass();
				if (isCopyRequiredType(cls)) {
					cls = getConstructableType(cls);
				}
				// Either force source as DTO, or DTO type
				if (sourceAsDTO || DTOUtil.isDTOType(cls, false))
					element = c.convert(element).sourceAsDTO().to(cls);
				else
					element = c.convert(element).to(cls);
			}
		}
		return element;
	}

	@SuppressWarnings({
			"unchecked", "rawtypes"
	})
	private Map convertToMapDelegate(InternalConverter c) {
		if (Map.class.isAssignableFrom(sourceClass)) {
			return MapDelegate.forMap((Map) object, this, c);
		} else if (Dictionary.class.isAssignableFrom(sourceClass)) {
			return MapDelegate.forDictionary((Dictionary) object, this, c);
		} else if (DTOUtil.isDTOType(sourceClass, true) || sourceAsDTO) {
			return MapDelegate.forDTO(object, sourceClass, this, c);
		} else if (sourceAsJavaBean) {
			return MapDelegate.forBean(object, sourceClass, this, c);
		} else if (hasGetProperties(sourceClass)) {
			return null; // Handled in convertToMap()
		}

		// Assume it's an interface
		Set<Class< ? >> interfaces = getInterfaces(sourceClass);
		if (interfaces.size() > 0) {
			return MapDelegate.forInterface(object,
					interfaces.iterator().next(), this, c);
		}
		return null;
	}

	@SuppressWarnings("rawtypes")
	private Object convertToMapType(InternalConverter c) {
		if (!isMapType(sourceClass, sourceAsJavaBean, sourceAsDTO)) {
			throw new ConversionException(
					"Cannot convert " + object + " to " + targetAsClass);
		}

		if (Map.class.equals(targetClass) && liveView) {
			Map res = convertToMapDelegate(c);
			if (res != null)
				return res;
		}

		if (Map.class.isAssignableFrom(targetAsClass))
			return convertToMap(c);
		else if (Dictionary.class.isAssignableFrom(targetAsClass))
			return convertToDictionary(c);
		else if (targetAsDTO || DTOUtil.isDTOType(targetAsClass, false))
			return convertToDTO(sourceClass, targetAsClass, c);
		else if (targetAsClass.isInterface())
			return convertToInterface(sourceClass, targetAsClass, c);
		else if (targetAsJavaBean)
			return convertToJavaBean(sourceClass, targetAsClass, c);
		throw new ConversionException(
				"Cannot convert " + object + " to " + targetAsClass);
	}

	@SuppressWarnings({
			"unchecked", "rawtypes"
	})
	private Object convertToDictionary(InternalConverter c) {
		return new Hashtable(
				(Map) c.convert(object).to(new ParameterizedType() {
					@Override
					public Type getRawType() {
						return HashMap.class;
					}

					@Override
					public Type getOwnerType() {
						return null;
					}

					@SuppressWarnings("synthetic-access")
					@Override
					public Type[] getActualTypeArguments() {
						return typeArguments;
					}
				}));
	}

	private Object convertToJavaBean(Class< ? > sourceCls,
			Class< ? > targetCls, InternalConverter c) {
		String prefix = Util.getPrefix(targetCls);

		@SuppressWarnings("rawtypes")
		Map m = mapView(object, sourceCls, c);
		try {
			Object res = targetClass.newInstance();
			for (Method setter : getSetters(targetCls)) {
				String setterName = setter.getName();
				StringBuilder propName = new StringBuilder(Character
						.valueOf(Character.toLowerCase(setterName.charAt(3)))
						.toString());
				if (setterName.length() > 4)
					propName.append(setterName.substring(4));

				Class< ? > setterType = setter.getParameterTypes()[0];
				String key = propName.toString();
				Object val = m.get(Util.unMangleName(prefix, key));
				setter.invoke(res, c.convert(val).to(setterType));
			}
			return res;
		} catch (Exception e) {
			throw new ConversionException(
					"Cannot convert to class: " + targetCls.getName()
							+ ". Not a JavaBean with a Zero-arg Constructor.",
					e);
		}
	}

	@SuppressWarnings("rawtypes")
	private Object convertToInterface(Class< ? > sourceCls,
			final Class< ? > targetCls, InternalConverter c) {
		InternalConverting ic = c.convert(object);
		ic.sourceAs(sourceAsClass).view();
		if (sourceAsDTO)
			ic.sourceAsDTO();
		if (sourceAsJavaBean)
			ic.sourceAsBean();
		final Map m = ic.to(Map.class);

		return createProxy(targetCls, m, c);
	}

	private Object createProxy(final Class< ? > cls, final Map< ? , ? > data, final InternalConverter c) {
		return Proxy.newProxyInstance(cls.getClassLoader(), new Class[] {
				cls
		}, new InvocationHandler() {
			@SuppressWarnings("boxing")
			@Override
			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				Class< ? > mdDecl = method.getDeclaringClass();
				if (mdDecl.equals(Object.class))
					switch (method.getName()) {
						case "equals" :
							return proxy == args[0];
						case "hashCode" :
							return System.identityHashCode(proxy);
						case "toString" :
							return "Proxy for " + cls;
						default :
							throw new UnsupportedOperationException("Method "
									+ method + " not supported on proxy for "
									+ cls);
					}
				if (mdDecl.equals(Annotation.class)) {
					if ("annotationType".equals(method.getName())
							&& method.getParameterTypes().length == 0) {
						return cls;
					}
				}

				String propName = Util.getInterfacePropertyName(method,
						Util.getSingleElementAnnotationKey(cls, proxy),
						proxy);
				if (propName == null)
					return null;

				Object val = data.get(propName);
				if (val == null && keysIgnoreCase) {
					// try in a case-insensitive way
					for (Iterator< ? > it = data.keySet().iterator(); it
							.hasNext()
							&& val == null;) {
						String k = it.next().toString();
						if (propName.equalsIgnoreCase(k)) {
							val = data.get(k);
						}
					}
				}

				// If no value is available take the default if specified
				if (val == null) {
					if (cls.isAnnotation()) {
						val = method.getDefaultValue();
					}

					if (val == null) {
						if (args != null && args.length == 1) {
							val = args[0];
						} else {
							throw new ConversionException(
									"No value for property: " + propName);
						}
					}
				}

				@SuppressWarnings("synthetic-access")
				Type genericType = reifyType(method.getGenericReturnType(),
						targetAsClass, typeArguments);
				return c.convert(val).to(genericType);
			}
		});
	}

	@SuppressWarnings("boxing")
	private Object handleNull(Class< ? > cls, InternalConverter c) {
		if (hasDefault)
			return c.convert(defaultValue).to(cls);

		Class< ? > boxed = Util.primitiveToBoxed(cls);
		if (boxed.equals(cls)) {
			if (cls.isArray()) {
				int i = 1;
				Class<?> componentType = cls.getComponentType();
				while(componentType.isArray()) {
					i++;
					componentType = componentType.getComponentType();
				}

				if(i == 1) {
					return Array.newInstance(componentType, 0);
				} else {
					return Array.newInstance(componentType, new int[i]);
				}
			} else if (Collection.class.isAssignableFrom(cls)) {
				return c.convert(Collections.emptyList()).to(cls);
			}
			// This is not a primitive, just return null
			return null;
		}

		return c.convert(0).to(cls);
	}

	private static boolean isMapType(Class< ? > cls, boolean asJavaBean,
			boolean asDTO) {
		if (asDTO)
			return true;

		// All interface types that are not Collections are treated as maps
		if (Map.class.isAssignableFrom(cls))
			return true;
		else if (getInterfaces(cls).size() > 0)
			return true;
		else if (DTOUtil.isDTOType(cls, true))
			return true;
		else if (asJavaBean && isWriteableJavaBean(cls))
			return true;
		else
			return Dictionary.class.isAssignableFrom(cls);
	}

	@SuppressWarnings("boxing")
	private Object trySpecialCases(InternalConverter c) {
		if (Boolean.class.equals(targetAsClass)) {
			if (object instanceof Collection
					&& ((Collection< ? >) object).size() == 0) {
				return Boolean.FALSE;
			}
		} else if (Number.class.isAssignableFrom(targetAsClass)) {
			if (object instanceof Boolean) {
				return ((Boolean) object).booleanValue() ? 1 : 0;
			} else if (object instanceof Number) {
				if (Byte.class.isAssignableFrom(targetAsClass)) {
					return ((Number) object).byteValue();
				} else if (Short.class.isAssignableFrom(targetAsClass)) {
					return ((Number) object).shortValue();
				} else if (Integer.class.isAssignableFrom(targetAsClass)) {
					return ((Number) object).intValue();
				} else if (Long.class.isAssignableFrom(targetAsClass)) {
					return ((Number) object).longValue();
				} else if (Float.class.isAssignableFrom(targetAsClass)) {
					return ((Number) object).floatValue();
				} else if (Double.class.isAssignableFrom(targetAsClass)) {
					return ((Number) object).doubleValue();
				}
			}
		} else if (Enum.class.isAssignableFrom(targetAsClass)) {
			if (object instanceof Number) {
				try {
					Method m = targetAsClass.getMethod("values");
					Object[] values = (Object[]) m.invoke(null);
					return values[((Number) object).intValue()];
				} catch (Exception e) {
					throw new RuntimeException(e);
				}
			} else {
				try {
					Method m = targetAsClass.getMethod("valueOf", String.class);
					return m.invoke(null, object.toString());
				} catch (Exception e) {
					try {
						// Case insensitive fallback
						Method m = targetAsClass.getMethod("values");
						for (Object v : (Object[]) m.invoke(null)) {
							if (v.toString()
									.equalsIgnoreCase(object.toString())) {
								return v;
							}
						}
					} catch (Exception e1) {
						throw new RuntimeException(e1);
					}
				}
			}
		} else if (Annotation.class.isAssignableFrom(sourceClass)
				&& isMarkerAnnotation(sourceClass)) {
			// Special treatment for marker annotations
			String key = Util.getMarkerAnnotationKey(sourceClass, object);
			return c.convert(Collections.singletonMap(key, Boolean.TRUE))
					.targetAs(targetAsClass)
					.to(targetType);
		} else if (Annotation.class.isAssignableFrom(targetAsClass)
				&& isMarkerAnnotation(targetAsClass)) {
			Map<String,Boolean> representation = Converters.standardConverter()
					.convert(object)
					.to(new TypeReference<Map<String,Boolean>>() {
						/* empty subclass */
					});
			if (Boolean.TRUE.equals(
					representation.get(Util.toSingleElementAnnotationKey(
							targetAsClass.getSimpleName())))) {
				return createProxy(targetClass, Collections.emptyMap(), c);
			} else {
				throw new ConversionException("Cannot convert " + object
						+ " to marker annotation " + targetAsClass);
			}
		}
		return null;
	}

	private static boolean isMarkerAnnotation(Class< ? > annClass) {
		for (Method m : annClass.getMethods()) {
			if (m.getDeclaringClass() != annClass) {
				// this is a base annotation or object method
				continue;
			}
			return false;
		}
		return true;
	}

	@SuppressWarnings("unchecked")
	private <T> T tryStandardMethods() {
		try {
			// Section 707.4.2.3 and 707.4.2.5 require valueOf to be public and static
			Method m = targetAsClass.getMethod("valueOf", String.class);
			if (m != null && Modifier.isStatic(m.getModifiers())) {
				return (T) m.invoke(null, object.toString());
			}
		} catch (Exception e) {
			try {
				Constructor< ? > ctr = targetAsClass
						.getConstructor(String.class);
				return (T) ctr.newInstance(object.toString());
			} catch (Exception e2) {
				// Ignore
			}
		}
		return null;
	}

	private Collection< ? > collectionView(InternalConverter conv) {
		if (object == null)
			return null;

		Collection< ? > c = asCollection(conv);
		if (c == null)
			return Collections.singleton(object);
		else
			return c;
	}

	private Collection< ? > asCollection(InternalConverter c) {
		if (object instanceof Collection)
			return (Collection< ? >) object;
		else if ((object = asBoxedArray(object)) instanceof Object[])
			return Arrays.asList((Object[]) object);
		else if (isMapType(sourceClass, sourceAsJavaBean, sourceAsDTO))
			return mapView(object, sourceClass, c).entrySet();
		else
			return null;
	}

	private static Object asBoxedArray(Object obj) {
		Class< ? > objClass = obj.getClass();
		if (!objClass.isArray())
			return obj;

		int len = Array.getLength(obj);
		Object arr = Array.newInstance(
				Util.primitiveToBoxed(objClass.getComponentType()), len);
		for (int i = 0; i < len; i++) {
			Object val = Array.get(obj, i);
			Array.set(arr, i, val);
		}
		return arr;
	}

	@SuppressWarnings("rawtypes")
	private static Map createMapFromBeanAccessors(Object obj,
			Class< ? > sourceCls) {
		Set<String> invokedMethods = new HashSet<>();

		Map result = new HashMap();
		// Bean accessors must be public
		for (Method md : sourceCls.getMethods()) {
			handleBeanMethod(obj, md, invokedMethods, result);
		}

		return result;
	}

	@SuppressWarnings("rawtypes")
	private Map createMapFromDTO(Object obj, InternalConverter ic) {
		Set<String> handledFields = new HashSet<>();

		Map result = new HashMap();
		// We only use public fields for mapping a DTO
		for (Field f : obj.getClass().getFields()) {
			handleDTOField(obj, f, handledFields, result, ic);
		}
		return result;
	}

	@SuppressWarnings({"unchecked","rawtypes"})
	private static Map createMapFromInterface(Object obj, Class< ? > srcCls) {
		Map result = new HashMap();

		if(Annotation.class.isAssignableFrom(srcCls) && isMarkerAnnotation(((Annotation)obj).annotationType())) {
			// We special case this if the source is a marker annotation because we will end up with no
			// interface methods otherwise
			result.put(Util.getMarkerAnnotationKey(((Annotation)obj).annotationType(), obj), Boolean.TRUE);
			return result;
		} else {
			for (Class i : getInterfaces(srcCls)) {
				for (Method md : i.getMethods()) {
					handleInterfaceMethod(obj, i, md, new HashSet<String>(),
							result);
				}
				if (result.size() > 0)
					return result;
			}
		}
		throw new ConversionException("Cannot be converted to map: " + obj);
	}

	@SuppressWarnings("boxing")
	private static Object createMapOrCollection(Class< ? > cls,
			int initialSize) {
		try {
			Constructor< ? > ctor = cls.getConstructor(int.class);
			return ctor.newInstance(initialSize);
		} catch (Exception e1) {
			try {
				Constructor< ? > ctor2 = cls.getConstructor();
				return ctor2.newInstance();
			} catch (Exception e2) {
				// ignore
			}
		}
		return null;
	}

	private static Class< ? > getConstructableType(Class< ? > targetCls) {
		if (targetCls.isArray())
			return targetCls;

		Class< ? > cls = targetCls;
		do {
			try {
				cls.getConstructor(int.class);
				return cls; // If no exception the constructor is there
			} catch (NoSuchMethodException e) {
				try {
					cls.getConstructor();
					return cls; // If no exception the constructor is there
				} catch (NoSuchMethodException e1) {
					// There is no constructor with this name
				}
			}
			for (Class< ? > intf : cls.getInterfaces()) {
				Class< ? > impl = INTERFACE_IMPLS.get(intf);
				if (impl != null)
					return impl;
			}

			cls = cls.getSuperclass();
		} while (!Object.class.equals(cls));

		return null;
	}

	// Returns an ordered set
	private static Set<Class< ? >> getInterfaces(Class< ? > cls) {
		if (NO_MAP_VIEW_TYPES.contains(cls))
			return Collections.emptySet();

		Set<Class< ? >> interfaces = getInterfaces0(cls);
		outer: for (Iterator<Class< ? >> it = interfaces.iterator(); it.hasNext();) {
			Class< ? > intf = it.next();
			for (Method method : intf.getMethods()) {
				if(method.getDeclaringClass() == intf) {
					continue outer;
				}
			}
			it.remove();
		}

		interfaces.removeAll(NO_MAP_VIEW_TYPES);

		return interfaces;
	}

	// Returns an ordered set
	private static Set<Class< ? >> getInterfaces0(Class< ? > cls) {
		if (cls == null)
			return Collections.emptySet();

		Set<Class< ? >> classes = new LinkedHashSet<>();
		if (cls.isInterface()) {
			classes.add(cls);
		}
		for (Class< ? > intf : cls.getInterfaces()) {
			classes.addAll(getInterfaces(intf));
		}

		classes.addAll(getInterfaces(cls.getSuperclass()));

		return classes;
	}

	@SuppressWarnings({
			"rawtypes", "unchecked"
	})
	private void handleDTOField(Object obj, Field field,
			Set<String> handledFields, Map result, InternalConverter ic) {
		String fn = Util.getDTOKey(field);
		if (fn == null)
			return;

		if (handledFields.contains(fn))
			return; // Field with this name was already handled

		try {
			Object fVal = field.get(obj);
			result.put(fn, fVal);
			handledFields.add(fn);
		} catch (Exception e) {
			// Ignore
		}
	}

	@SuppressWarnings({
			"rawtypes", "unchecked"
	})
	private static void handleBeanMethod(Object obj, Method md,
			Set<String> invokedMethods, Map res) {
		String bp = Util.getBeanKey(md);
		if (bp == null)
			return;

		if (invokedMethods.contains(bp))
			return; // method with this name already invoked

		try {
			res.put(bp, md.invoke(obj));
			invokedMethods.add(bp);
		} catch (Exception e) {
			// Ignore
		}
	}

	@SuppressWarnings({
			"rawtypes", "unchecked"
	})
	private static void handleInterfaceMethod(Object obj, Class< ? > intf,
			Method md, Set<String> invokedMethods, Map res) {
		String mn = md.getName();
		if (invokedMethods.contains(mn))
			return; // method with this name already invoked

		String propName = Util.getInterfacePropertyName(md,
				Util.getSingleElementAnnotationKey(intf, obj), obj);
		if (propName == null)
			return;

		try {
			Object r = Util.getInterfaceProperty(obj, md);
			if (r == null)
				return;

			res.put(propName, r);
			invokedMethods.add(mn);
		} catch (Exception e) {
			// Ignore
		}
	}

	private Map< ? , ? > mapView(Object obj, Class< ? > sourceCls,
			InternalConverter ic) {
		if (Map.class.isAssignableFrom(sourceCls)
				|| (DTOUtil.isDTOType(sourceCls, true) && obj instanceof Map))
			return (Map< ? , ? >) obj;
		else if (Dictionary.class.isAssignableFrom(sourceCls))
			return MapDelegate.forDictionary((Dictionary< ? , ? >) object,
					this, ic);
		else if (DTOUtil.isDTOType(sourceCls, true) || sourceAsDTO)
			return createMapFromDTO(obj, ic);
		else if (sourceAsJavaBean) {
			Map< ? , ? > m = createMapFromBeanAccessors(obj, sourceCls);
			if (m.size() > 0)
				return m;
		} else if (hasGetProperties(sourceCls)) {
			return getPropertiesDelegate(obj, sourceCls, ic);
		}
		return createMapFromInterface(obj, sourceClass);
	}

	private boolean hasGetProperties(Class< ? > cls) {
		try {
			// Section 707.4.4.4.8 says getProperties must be public
			Method m = cls.getMethod("getProperties");
			return m != null;
		} catch (Exception e) {
			return false;
		}
	}

	private Map< ? , ? > getPropertiesDelegate(Object obj, Class< ? > cls, InternalConverter c) {
		try {
			// Section 707.4.4.4.8 says getProperties must be public
			Method m = cls.getMethod("getProperties");

			return c.convert(m.invoke(obj)).to(Map.class);
		} catch (Exception e) {
			return Collections.emptyMap();
		}
	}

	private static boolean isCopyRequiredType(Class< ? > cls) {
		if (cls.isEnum())
			return false;
		return Map.class.isAssignableFrom(cls)
				|| Collection.class.isAssignableFrom(cls)
				|| DTOUtil.isDTOType(cls, true) || cls.isArray();
	}

	private static boolean isWriteableJavaBean(Class< ? > cls) {
		boolean hasNoArgCtor = false;
		for (Constructor< ? > ctor : cls.getConstructors()) {
			if (ctor.getParameterTypes().length == 0)
				hasNoArgCtor = true;
		}
		if (!hasNoArgCtor)
			return false; // A JavaBean must have a public no-arg constructor

		return getSetters(cls).size() > 0;
	}

	private static Set<Method> getSetters(Class< ? > cls) {
		Set<Method> setters = new HashSet<>();
		while (!Object.class.equals(cls)) {
			Set<Method> methods = new HashSet<>();
			// Only public methods can be Java Bean setters
			methods.addAll(Arrays.asList(cls.getMethods()));
			for (Method md : methods) {
				if (md.getParameterTypes().length != 1)
					continue; // Only setters with a single argument
				String name = md.getName();
				if (name.length() < 4)
					continue;
				if (name.startsWith("set")
						&& Character.isUpperCase(name.charAt(3)))
					setters.add(md);
			}
			cls = cls.getSuperclass();
		}
		return setters;
	}
}
