/*
@license.text@
 */
package com.hammurapi.convert;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;

import com.hammurapi.common.Context;



/**
 * @author Pavel Vlasov
 */
public abstract class AbstractReflectiveAtomicConvertersBundle implements AtomicConvertersBundle {

	@SuppressWarnings("unchecked")
	@Override
	public Collection<AtomicConverter<? extends Object, ? extends Object>> getConverters() {
		Collection<AtomicConverter<? extends Object, ? extends Object>> ret = new ArrayList<AtomicConverter<? extends Object,? extends Object>>();
		Z: for (final Method m: this.getClass().getMethods()) {						
			Class<?>[] pta = m.getParameterTypes();
			Class<Object> targetType = (Class<Object>) m.getReturnType();
			if (m.getAnnotation(ConverterMethod.class)!=null && !void.class.equals(targetType) && pta.length>0) {
				for (int i=1; i<pta.length; ++i) {
					if (!(Context.class.equals(pta[i]) || Converter.class.equals(pta[i]))) {
						continue Z;
					}
				}
				Class<Object> sourceType = (Class<Object>) pta[0];
				AtomicConverterBase<Object, Object> converter = new AtomicConverterBase<Object, Object>(sourceType, targetType) {
					
					@Override
					public Object convert(Object source, Converter master, Context context, ClassLoader classLoader) {
						try {
							Class<?>[] pt = m.getParameterTypes();
							Object[] args = new Object[pt.length];
							args[0] = source;
							for (int i=1; i<pt.length; ++i) {
								if (Context.class.equals(pt[i])) {
									args[i] = context;
								} else if (Converter.class.equals(pt[i])) {
									args[i] = master;
								}											
							}
							return m.invoke(AbstractReflectiveAtomicConvertersBundle.this, args);
						} catch (Exception e) {
							throw new ConversionException(e);
						}
					}
				};
				ret.add(converter);
			}
		}
		return ret;
	}

		
}
