package Edo.util;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class Convert {
	
	
	public static Integer toInt(Object o){
		if(o==null)  o=0;
		return Integer.parseInt(o.toString());
	}
	public static Long toLong(Object o){
		if(o==null)  o=0;
		return Long.parseLong(o.toString());
	}
	public static Float toFloat(Object o){
		if(o==null)  o=0;
		return Float.parseFloat(o.toString());
	}
	public static Double toDouble(Object o){
		if(o==null)  o=0;
		return Double.parseDouble(o.toString());
	}
	public static Short toShort(Object o){
		if(o==null)  o=0;
		return Short.parseShort(o.toString());
	}
	public static Boolean toBoolean(Object o){
		if(o==null)  o=false;
		return Boolean.parseBoolean(o.toString());
	}	
	public static Character toChar(Object o){
		if(o==null)  o="";
		return (Character)o;
	}
	
	public static Object toClass(Object object, Class cls) throws Exception{	
		if(object == null) return null;
		if(cls ==Map.class) return (Map)object;
		if(cls ==HashMap.class) return (HashMap)object;		
		if(cls ==ArrayList.class) return (ArrayList)object;
		if(cls ==List.class) return (List)object;			
				
		if(cls == Boolean.class || cls == boolean.class) return Convert.toBoolean(object);		
		if(cls == Double.class || cls == double.class) return Convert.toDouble(object);
		if(cls == Float.class || cls == float.class) return Convert.toFloat(object);
		if(cls == Long.class || cls == long.class) return Convert.toLong(object);
		if(cls == Short.class || cls == short.class) return Convert.toShort(object);
		if(cls == Integer.class || cls == int.class) return Convert.toInt(object);
		if(cls == Character.class || cls == char.class) return (Character)object;
		if(cls == Byte.class) return (Byte)object;
		if(cls == String.class) return object.toString();
		if(cls == Date.class) return (Date)object;
		if(cls == Object.class) return (Object)object;		
		ArrayList l = new ArrayList();
				
		if(cls.isArray()){
			return toArray((List)object, cls);
		}
				
		return toClass((Map)object, cls);
	}
	public static Object toArray(List list, Class arrayClass) throws Exception{
		Class type = arrayClass.getComponentType();
		Object objs = Array.newInstance(type, list.size());
		
        for (int i = 0, l = list.size(); i < l; i++)
        {
            Object o = toClass(list.get(i), type);
            
            Array.set(objs, i, o);
        }
		
		return objs;
	}
	public static Object toClass(Map jso, Class clazz) throws Exception{
		if(jso == null) return null;
		Object instance = null;
		try {
		    instance = clazz.newInstance();
		} catch (Exception e) {
		    throw new Exception
			("can't instantiate bean " +
			 clazz.getName() + ": " + e.getMessage());
		}
		Object invokeArgs[] = new Object[1];
		Object fieldVal;
		Iterator i = jso.keySet().iterator();
		while(i.hasNext()) {
		    String field = (String)i.next();
		    
		    Method setMethod = (Method)getSetMethod(clazz, field);
		    if(setMethod != null) {
			try {
			    Class param[] = setMethod.getParameterTypes();
			    fieldVal = toClass(jso.get(field), param[0]);
			} catch (Exception e) {
			    throw new Exception("bean " + clazz.getName() +
							  " " + e.getMessage());
			}
			
			invokeArgs[0] = fieldVal;
			try {
			    setMethod.invoke(instance, invokeArgs);
			} catch (Throwable e) {
			    if(e instanceof InvocationTargetException)
				e = ((InvocationTargetException)e).
				    getTargetException();
			    throw new Exception
				("bean " + clazz.getName() + "can't invoke " +
				 setMethod.getName() + ": " + e.getMessage());
			}
		    }
		}
		return instance;
	}
	
	
	public static Method getSetMethod(Class clazz, String field) throws IntrospectionException{
		Map beanClass = getBeanClass(clazz);
		Map writableProps = (Map)beanClass.get("writableProps");
		Method setMethod = (Method)writableProps.get(field);
		return setMethod;		
	}
	public static Map beanClasses = new HashMap(); 
	public static Map getBeanClass(Class clazz) throws IntrospectionException{
		
		Map beanClass = (Map)beanClasses.get(clazz.toString());
		if(beanClass != null) return beanClass;
		
		beanClass = new HashMap();
		beanClasses.put(clazz.toString(), beanClass);
		
		BeanInfo beanInfo = Introspector.getBeanInfo(clazz, Object.class);
		Map readableProps = new HashMap();
		Map writableProps = new HashMap();
		
		PropertyDescriptor props[] = beanInfo.getPropertyDescriptors();
		
		for(int i=0; i < props.length; i++) {
		    if(props[i].getWriteMethod() != null) {
		    	writableProps.put(props[i].getName(), props[i].getWriteMethod());
		    }
		    if(props[i].getReadMethod() != null) {
		    	readableProps.put(props[i].getName(), props[i].getReadMethod());
		    }
		}
		
		beanClass.put("beanInfo", beanInfo);
		beanClass.put("readableProps", readableProps);
		beanClass.put("writableProps", writableProps);
		
		return beanClass;
	}
}
