package jp.sf.amateras.mirage.bean;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import jp.sf.amateras.mirage.util.ReflectionUtil;

public class PropertyDescImpl implements PropertyDesc {

	private BeanDesc parent;
	private String name;
	private Class<?> type;
	private Method getterMethod;
	private Method setterMethod;
	private Field field;

	public PropertyDescImpl(BeanDesc parent, String name, Class<?> type,
			Field field, Method getterMethod, Method setterMethod){
		this.parent = parent;
		this.name = name;
		this.type = type;
		this.field = field;
		this.getterMethod = getterMethod;
		this.setterMethod = setterMethod;
	}

	@Override
	public Object getValue(Object obj){
		try {
			if(getterMethod != null){
				return getterMethod.invoke(obj, (Object[]) null);
			} else {
				return field.get(obj);
			}
		} catch(Exception ex){
			throw new RuntimeException(ex);
		}
	}

	@Override
	public void setValue(Object obj, Object value){
		try {
			if(setterMethod != null){
				setterMethod.invoke(obj, value);
			} else {
				field.set(obj, value);
			}
		} catch(Exception ex){
			throw new RuntimeException(ex);
		}
	}

	@Override
	public boolean isReadable(){
		if(getterMethod != null || field != null){
			return true;
		}
		return false;
	}

	@Override
	public boolean isWritable(){
		if(setterMethod != null || field != null){
			return true;
		}
		return false;
	}

	@Override
	public Class<?> getPropertyType(){
		return type;
	}

	@Override
	public String getPropertyName(){
		return name;
	}

	@Override
	public Field getField(){
		return field;
	}

	@Override
	public <T extends Annotation> T getAnnotation(Class<T> type){
		T ann = null;
		if(field != null){
			ann = field.getAnnotation(type);
		}
		if(ann == null && setterMethod != null){
			ann = setterMethod.getAnnotation(type);
		}
		if(ann == null && getterMethod != null){
			ann = getterMethod.getAnnotation(type);
		}
		if(ann == null && field == null){
			Field field = ReflectionUtil.getField(parent.getType(), getPropertyName());
			if(field != null){
				ann = field.getAnnotation(type);
			}
		}
		return ann;
	}

}