package br.com.caelum.vraptor4.interceptor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import br.com.caelum.vraptor4.AfterCall;
import br.com.caelum.vraptor4.BeforeCall;
import br.com.caelum.vraptor4.VRaptorException;
import br.com.caelum.vraptor4.core.InterceptorHandler;
import br.com.caelum.vraptor4.core.InterceptorStack;
import br.com.caelum.vraptor4.ioc.Container;
import br.com.caelum.vraptor4.restfulie.controller.ControllerMethod;

public class AspectStyleInterceptorHandler implements InterceptorHandler {

	private final StepInvoker stepInvoker;
	private final Container container;
	private final Class<?> interceptorClass;
	private static final Logger logger = LoggerFactory
			.getLogger(AspectStyleInterceptorHandler.class);
	private final InterceptorMethodParametersResolver parametersResolver;
	private StepExecutor<Boolean> acceptsExecutor;
	private StepExecutor<?> after;
	private StepExecutor<?> around;
	private StepExecutor<?> before;


	public AspectStyleInterceptorHandler(Class<?> interceptorClass,
			StepInvoker stepInvoker, Container container) {
		this.interceptorClass = interceptorClass;
		this.stepInvoker = stepInvoker;
		this.container = container;
		parametersResolver = new InterceptorMethodParametersResolver(
				stepInvoker, container);
		configure();

	}

	private void configure() {
		after = new NoStackParameterStepExecutor(stepInvoker, AfterCall.class);
		if(!after.accept(interceptorClass)){
			after = new DoNothingStepExecutor();
		}

		around = new AroundExecutor(stepInvoker,parametersResolver, container);
		if(!around.accept(interceptorClass)){
			around = new StackNextExecutor(container);
		}

		before = new NoStackParameterStepExecutor(stepInvoker, BeforeCall.class);
		if(!before.accept(interceptorClass)){
			before = new DoNothingStepExecutor();
		}

		CustomAcceptsExecutor customAcceptsExecutor = new CustomAcceptsExecutor(stepInvoker, container);
		InterceptorAcceptsExecutor interceptorAcceptsExecutor = new InterceptorAcceptsExecutor(stepInvoker, parametersResolver);
		boolean customAccepts = customAcceptsExecutor.accept(interceptorClass);
		boolean internalAccepts = interceptorAcceptsExecutor.accept(interceptorClass);
		if(customAccepts && internalAccepts){
			throw new VRaptorException("Interceptor "+interceptorClass+" must declare internal accepts or custom, not both.");
		}

		this.acceptsExecutor = customAccepts?customAcceptsExecutor:interceptorAcceptsExecutor;




	}

	public void execute(InterceptorStack stack,
			ControllerMethod controllerMethod, Object currentController) {
		Object interceptor = container.instanceFor(interceptorClass);

		logger.debug("Invoking interceptor {}", interceptor.getClass()
				.getSimpleName());

		if (acceptsExecutor.execute(interceptor)) {
			before.execute(interceptor);
			around.execute(interceptor);
			after.execute(interceptor);
		} else {
			stack.next(controllerMethod, currentController);
		}

	}

}

@@ -175,24 +175,77 @@
 BeforeCall;%0A
+import br.com.caelum.vraptor4.InterceptionException;%0A
 import br.co
@@ -1385,16 +1385,17 @@
 ure() %7B%0A
+%0A
 %09%09after 
@@ -1466,176 +1466,320 @@
 ;%0A%09%09
-if(!after.accept(interceptorClass))%7B%0A%09%09%09after = new DoNothingStepExecutor();%0A%09%09%7D%0A%0A%09%09around = new AroundExecutor(stepInvoker,parametersResolver, conta
+around = new AroundExecutor(stepInvoker,parametersResolver, container);%0A%09%09before = new NoStackParameterStepExecutor(stepInvoker, BeforeCall.class);%0A%0A%09%09boolean doNotAcceptAfter = !after.accept(interceptorClass);%0A%09%09boolean doNotAcceptAround = !around.accept(
 in
+t
 er
-);%0A%09%09if(!around
+ceptorClass);%0A%09%09boolean doNotAcceptBefore = !before
 .acc
@@ -1803,216 +1803,440 @@
 ass)
-)%7B%0A%09%09%09around = new StackNextExecutor(container);%0A%09%09%7D%0A%0A%09%09before = new NoStackParameterStepExecutor(stepInvoker, BeforeCall.class);%0A%09%09if(!before.accept(interceptorClass))%7B%0A%09%09%09before = new DoNothingStepExecutor(
+;%0A%0A%09%09if(doNotAcceptAfter) after = new DoNothingStepExecutor();%0A%09%09if(doNotAcceptAround) around = new StackNextExecutor(container);%0A%09%09if(doNotAcceptBefore) before = new DoNothingStepExecutor();%0A%0A%09%09if (doNotAcceptAfter && doNotAcceptAround && doNotAcceptBefore) %7B%0A%09%09%09throw new InterceptionException(%22Interceptor %22 + interceptorClass + %22 must declare %22 +%0A%09%09%09%09%22at least one method whith @AfterCall, @AroundCall or @BeforeCall annotation%22
 );%0A%09
@@ -2779,16 +2779,17 @@
 );%0A%09%09%7D%0A%0A
+%0A
 %09%09this.a
@@ -2869,20 +2869,16 @@
 ecutor;%0A
-%0A%0A%0A%0A
 %09%7D%0A%0A%09pub

Throw new InterceptionException when Interceptor does not have any callable method #15