package org.arefgard.container.aop;

import java.util.Map;

/**
 * クラスのデータ構造。
 * @author T.A.K.A.Dark
 *
 */
public class ClassStructure {
	private String packageName;
	private String className;
	private Map<String, FieldStructure> fields = new java.util.HashMap<String, FieldStructure>();
	private Map<String, MethodStructure> methods = new java.util.HashMap<String, MethodStructure>();
	private Map<String, ConstructorStructure> constructors = new java.util.HashMap<String, ConstructorStructure>();
	public ClassStructure(String className) {
		this.className = className;
	}
	
	public ClassStructure(String packageName, String className) {
		this.packageName = packageName;
		this.className = className;
	}

	public static ClassStructure parse(Object object) {
		Class cls = object.getClass();
		return parse(cls);
	}
	
	public static ClassStructure parse(Class cls) {
		String className = cls.getSimpleName();
		String packageName = cls.getPackage().getName();
		ClassStructure structure = new ClassStructure(packageName, className);
		
		ConstructorStructure[] constructors = ConstructorStructure.parse(cls);
		int length = constructors.length;
		for(int i = 0; i < length; i++) {
			structure.addConstructor(constructors[i]);
		}
		MethodStructure[] methods = MethodStructure.parse(cls);
		length = methods.length;
		for(int i = 0; i < length; i++) {
			structure.addMethod(methods[i]);
		}
		FieldStructure[] fields = FieldStructure.parse(cls);
		length = fields.length;
		for(int i = 0; i < length; i++) {
			structure.addField(fields[i]);
		}
		return structure;
	}

	public void addConstructor(ConstructorStructure constructor) {
		StringBuffer sb = new StringBuffer();
		int size = constructor.length();
		for(int i = 0; i < size; i++) {
			if(i != 0) {
				sb.append("_");
			}
			sb.append(constructor.getParameterType(i));
		}
		this.constructors .put(sb.toString(), constructor);
	}
	
	public ConstructorStructure getConstructor(Object[] object) {
		StringBuffer sb = new StringBuffer();
		int size = object.length;
		for(int i = 0; i < size; i++) {
			if(i != 0) {
				sb.append("_");
			}
			sb.append(getType(object[i].getClass().getName()));
		}
		return constructors.get(sb.toString());
	}

	public void addMethod(MethodStructure method) {
		StringBuffer sb = new StringBuffer();
		sb.append(method.getMethodName());
		int size = method.length();
		for(int i = 0; i < size; i++) {
			sb.append("_");
			sb.append(method.getParameterType(i));
		}
		this.methods.put(sb.toString(), method);
	}
	
	public MethodStructure getMethod(String name) {
		return this.methods.get(name);
	}

	public void addField(FieldStructure fs) {
		this.fields.put(fs.getFieldName(), fs);
		
	}
	
	public FieldStructure getField(String name) {
		return this.fields.get(name);
	}

	public String getClassName() {
		return className;
	}

	public void setClassName(String className) {
		this.className = className;
	}

	public String getPackageName() {
		return packageName;
	}

	public void setPackageName(String packageName) {
		this.packageName = packageName;
	}

	public MethodStructure getMethod(String methodName, Object[] params) {
		StringBuffer sb = new StringBuffer();
		sb.append(methodName);
		int length = params.length;
		for(int i = 0; i < length; i++) {
			sb.append("_");
			sb.append(getType(params[i].getClass().getName()));
		}
		return this.methods.get(sb.toString());
	}
	
	public MethodStructure getSetter(String property, Class cls) {
		StringBuffer sb = new StringBuffer();
		sb.append("set");
		sb.append(property.substring(0, 1).toUpperCase());
		sb.append(property.substring(1));
		sb.append("_");
		sb.append(cls.getName());
		return this.methods.get(sb.toString());
	}
	
	private static String getType(String typeName) {
		if(typeName == null || typeName.equals("")) {
			return null;
		}
		if(typeName.equals("boolean")) {
			return "java.lang.Boolean";
		}else if(typeName.equals("byte")) {
			return "java.lang.Byte";
		}else if(typeName.equals("char")) {
			return "java.lang.Character";
		}else if(typeName.equals("double")) {
			return "java.lang.Double";
		}else if(typeName.equals("float")) {
			return "java.lang.Float";
		}else if(typeName.equals("int")) {
			return "java.lang.Integer";
		}else if(typeName.equals("long")) {
			return "java.lang.Long";
		}else if(typeName.equals("short")) {
			return "java.lang.Short";
		}else if(typeName.equals("void")) {
			return "java.lang.Void";
		}else {
			return typeName;
		}
	}
	
}
