package com.platform.utils;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.log4j.Logger;

import com.fasterxml.jackson.databind.PropertyNamingStrategy.UpperCamelCaseStrategy;

public class BeanCopy {
	
	@SuppressWarnings("static-access")
	public static Logger log = Configs.DAILY_ROLLING_LOGGER.getLogger(BeanCopy.class);
	
	/** 复制属性（子类父类等继承关系不可用）
	 * @param source 源对象
	 * @param dst 目标对象
	 * @param params 不复制的属性
	 * @throws Exception 
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 * @throws NoSuchFieldException
	 * @throws SecurityException
	 */
	public static synchronized void copyBean(Object source, Object dst, String... params){
		if (dst.getClass().getSuperclass() == source.getClass()) {
			fatherCopyChild(source, dst, params);
		}
		List<String> filter = new ArrayList<String>();
		filter.addAll(Arrays.asList(params));
		Field[] sourceField = source.getClass().getDeclaredFields();
		List<String> sourceFieldName = new ArrayList<String>();
		for (Field fie : sourceField) {
			sourceFieldName.add(fie.getName());
		}
		Field[] dstField = dst.getClass().getDeclaredFields();
		for (Field field : dstField) {
			String name = field.getName();
			if (filter.contains(name)) {
				continue;
			}
			if (sourceFieldName.contains(name)) {
				field.setAccessible(true);
				Object value;
					Method m;
					try {
						m = source.getClass().getMethod("get"+upperHeadChar(name));
						value = m.invoke(source);
		//				Field fie = source.getClass().getDeclaredField(name);
		//				fie.setAccessible(true);
		//				value = fie.get(source);
						if (null != value) 
							field.set(dst, value);
					} catch (Exception e) {
						log.error(e);
					}
			}
		}
		
	}
	
	public static synchronized void copyField(Object src, Object dst,String... filter) throws IntrospectionException {
		List<String> filters = Arrays.asList(filter);
		BeanInfo dstBeanInfo = Introspector.getBeanInfo(dst.getClass()); // 获取类属性
//        Object obj = type.newInstance(); // 创建 JavaBean 对象
		BeanInfo srcBeanInfo = Introspector.getBeanInfo(src.getClass()); // 获取类属性
	    PropertyDescriptor[] srcPropertyDescriptors =  srcBeanInfo.getPropertyDescriptors();
	    for (PropertyDescriptor property : srcPropertyDescriptors) {
	    	String pName = property.getName();
	    	if (filters.contains(pName)) {
				continue;
			}
	    	if (!"class".equals(pName)) {
	    		Method readMethod = property.getReadMethod();
	    		 try {
					Object result = readMethod.invoke(src, new Object[0]);
					if (null == result) {
						continue;
					}
					property.getWriteMethod().invoke(dst, new Object[]{result});
				} catch (IllegalAccessException e) {
					log.error(pName + " Access is false : AccessException");
				} catch (IllegalArgumentException e) {
					log.error(pName + " is inexist or null or OutOfRange : ArgumentException ");
				} catch (InvocationTargetException e) {
					log.error(pName + " is Invocation Exception");
				}
	    	}
		}
	}
	
	public static synchronized void copyFieldERR(Object src, Object dst,String... filter) {
		List<String> filters = Arrays.asList(filter);
		List<Field> fields = new ArrayList<Field>();
		Class<?> classobj = src.getClass();
		if (null != classobj) {
			Field[] fs = classobj.getDeclaredFields();
			for (Field field : fs) {
				field.setAccessible(true);
				fields.add(field);
			}
			fields = findFatherField(classobj, fields);
		}
		for (Field field : fields) {
			String name = field.getName();
			if (filters.contains(name)) {
				continue;
			}
			// dst  obj's property set value
			try {
				Method m = src.getClass().getMethod("get"+upperHeadChar(name));
				Object value = m.invoke(src);
				if (null != value) 
					field.set(dst, value);
//				field.set(dst, field.get(src));
			} catch (SecurityException e) {
				log.error(field.getName() + " is unsafe : SecurityException");
			} catch (IllegalArgumentException e) {
				log.error(field.getName() + " is inexist or null or OutOfRange : ArgumentException ");
			} catch (IllegalAccessException e) {
				log.error(field.getName() + " Access is false : AccessException");
			} catch (NoSuchMethodException e) {
				log.error(e.getMessage());
			} catch (InvocationTargetException e) {
				log.error(e.getMessage());
			}
		}
	}
	
	private static void fatherCopyChild(Object father, Object dst, String... params){
		List<String> filter = new ArrayList<String>();
		filter.addAll(Arrays.asList(params));
		if (dst.getClass().getSuperclass() == father.getClass()) {
			Class faClass = father.getClass();
			Field[] ff = faClass.getDeclaredFields();
			for (int i = 0; i < ff.length; i++) {
				Field f = ff[i];
				String name = f.getName();
				if (filter.contains(name)) {
					continue;
				}
				f.setAccessible(true);
				Class type = f.getType();
				Method m;
				try {
					m = faClass.getMethod("get"+upperHeadChar(f.getName()));
					Object obj = m.invoke(father);
					f.set(dst, obj);
				} catch (Exception e) {
					log.error(e.getStackTrace());
				}
			}
		}
	}
	
	private static List<Field> findFatherField(Class<?> classObj, List<Field> fields) {
		Class<?> classz = classObj.getSuperclass();
		if (null != classz) {
			Field[] field_array = classz.getDeclaredFields();
			if (field_array.length > 0) {
				for (Field field : field_array) {
					field.setAccessible(true);
					fields.add(field);
				}
				findFatherField(classz,fields);
			}
		}
		return fields;
	}
	
	private static String upperHeadChar(String in) {
		String head = in.substring(0,1);
		return head.toUpperCase()+in.substring(1, in.length());
	}

}
