package org.seasar.framework.aop.impl;

import java.io.Serializable;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.util.Map;

import net.sf.cglib.proxy.MethodProxy;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

/**
 * @author higa
 *
 */
public class MethodInvocationImpl implements MethodInvocation, Serializable {

	static final long serialVersionUID = 0L;
	
	private Object target_;
	private Method method_;
	private Object[] arguments_;
	private MethodProxy methodProxy_;
	private MethodInterceptor[] interceptors_;
	private Class targetClass_;
	private Map parameters_;
	private int interceptorsIndex_ = 0;
	private MethodInvocationImpl parent_;

	public MethodInvocationImpl(
		Object target,
		Method method,
		Object[] arguments,
		MethodProxy methodProxy,
		MethodInterceptor[] interceptors,
		Class targetClass,
		Map parameters) {

		if (target == null) {
			throw new NullPointerException("target");
		}
		if (method == null) {
			throw new NullPointerException("method");
		}
		if (methodProxy == null) {
			throw new NullPointerException("methodProxy");
		}
		if (interceptors == null) {
			throw new NullPointerException("interceptors");
		}
		if (targetClass == null) {
			throw new NullPointerException("targetClass");
		}
		target_ = target;
		method_ = method;
		arguments_ = arguments;
		methodProxy_ = methodProxy;
		interceptors_ = interceptors;
		targetClass_ = targetClass;
		parameters_ = parameters;
	}
	
	public MethodInvocationImpl(MethodInvocationImpl parent, MethodInterceptor[] interceptors) {
        parent_ = parent;
        target_ = parent.target_;
        method_ = parent.method_;
        arguments_ = parent.arguments_;
        interceptors_ = interceptors;
        targetClass_ = parent.targetClass_;
        parameters_ = parent.parameters_;
    }

	/**
	 * @see org.aopalliance.intercept.MethodInvocation#getMethod()
	 */
	public Method getMethod() {
		return method_;
	}

	/**
	 * @see org.aopalliance.intercept.Invocation#getArguments()
	 */
	public Object[] getArguments() {
		return arguments_;
	}

	/**
	 * @see org.aopalliance.intercept.Joinpoint#proceed()
	 */
	public Object proceed() throws Throwable {
		while (interceptorsIndex_ < interceptors_.length) {
			return interceptors_[interceptorsIndex_++].invoke(this);
		}
		if (parent_ != null) {
            return parent_.proceed();
        }
		return methodProxy_.invokeSuper(target_, arguments_);
	}

	/**
	 * @see org.aopalliance.intercept.Joinpoint#getThis()
	 */
	public Object getThis() {
		return target_;
	}

	/**
	 * @see org.aopalliance.intercept.Joinpoint#getStaticPart()
	 */
	public AccessibleObject getStaticPart() {
		return method_;
	}
	
	public Class getTargetClass() {
		return targetClass_;
	}
	
	public Object getParameter(String name) {
		if (parameters_ == null) {
			return null;
		}
		return parameters_.get(name);
	}

}
