package org.seasar.jsf.interceptor;

import java.lang.reflect.Field;

import org.aopalliance.intercept.MethodInvocation;
import org.seasar.framework.aop.interceptors.AbstractInterceptor;
import org.seasar.framework.beans.BeanDesc;
import org.seasar.framework.beans.PropertyDesc;
import org.seasar.framework.beans.factory.BeanDescFactory;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.SingletonS2ContainerFactory;
import org.seasar.framework.util.FieldUtil;
import org.seasar.jsf.util.BindingUtil;

/**
 * @author higa
 * 
 */
public class ActionBindingInterceptor extends AbstractInterceptor {

	public static final String EXPORT_SUFFIX = "_EXPORT";

	public static final String SESSION = "session";
	
	/**
	 * 
	 * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
	 */
	public Object invoke(MethodInvocation invocation) throws Throwable {
		Class targetClass = getTargetClass(invocation);
		BeanDesc beanDesc = BeanDescFactory.getBeanDesc(targetClass);
		S2Container container = SingletonS2ContainerFactory.getContainer();
		importVariables(invocation.getThis(), container, beanDesc);
		Object ret;
		try {
			ret = invocation.proceed();
		} finally {
			exportVariables(invocation.getThis(), container, beanDesc);
		}
		return ret;
	}

	protected void importVariables(Object component, S2Container container,
			BeanDesc beanDesc) {

		for (int i = 0; i < beanDesc.getPropertyDescSize(); ++i) {
			PropertyDesc pd = beanDesc.getPropertyDesc(i);
			if (pd.hasWriteMethod()) {
				Object var = BindingUtil.getValue(container.getRequest(), pd
						.getPropertyName());
				if (var != null) {
					pd.setValue(component, var);
				}
			}
		}
	}

	protected void exportVariables(Object component, S2Container container,
			BeanDesc beanDesc) {

		for (int i = 0; i < beanDesc.getPropertyDescSize(); ++i) {
			PropertyDesc pd = beanDesc.getPropertyDesc(i);
			if (pd.hasReadMethod()) {
				Object var = pd.getValue(component);
				if (var != null) {
					boolean useSession = false;
					String fieldName = pd.getPropertyName() + EXPORT_SUFFIX;
					if (beanDesc.hasField(fieldName)) {
						Field field = beanDesc.getField(fieldName);
						String value = (String) FieldUtil.get(field, null);
						if (SESSION.equalsIgnoreCase(value)) {
							useSession = true;
						}
					}
					if (useSession) {
						container.getSession().setAttribute(
								pd.getPropertyName(), var);
					} else {
						container.getRequest().setAttribute(
								pd.getPropertyName(), var);
					}
				}
			}
		}
	}

}