package <%=binderClassPackage%>;

import java.util.HashSet;
import java.util.Set;

import com.hammurapi.eventbus.AbstractEventBus;
import com.hammurapi.eventbus.AbstractEventBus.Handle;
import com.hammurapi.eventbus.AbstractEventHandler;
import com.hammurapi.eventbus.EventDispatchContext;
import com.hammurapi.eventbus.EventHandler;
import com.hammurapi.eventbus.JavaBinder;
import com.hammurapi.extract.Predicate;
import com.hammurapi.eventbus.EventHandlerBase.Mode;

/**
 * <%=binderClassComment%>

 */
public class <%=binderClassName%><%=genericParameters%> implements JavaBinder<<%=E%>, <%=C%>, <%=K%>, <%=H%>, <%=S%>, <%=B%>, <%=I%>> {

	@Override
	public Set<<%=K%>> bind(<%=I%> instance, <%=B%> bus) {
		Set<<%=K%>> ret = new HashSet<<%=K%>>();
		
		<% for (Object bindMethod: bindHelper.getBindMethods()) { %>
		ret.add(<%=bindMethod.getName()%>(instance, bus));
		<% } %>
		
		return ret;
	}
	
	<% for (Object bindMethod: bindHelper.getBindMethods()) { %>
	
	private <%=K%> <%=bindMethod.getName()%>(final <%=I%> instance, <%=B%> bus) {
		
		Predicate<<%=E%>, <%=C%>>[] predicates = new Predicate[<%=bindMethod.getPredicates().length%>];
		
		<% for (int pIdx=0; pIdx<bindMethod.getPredicates().length; ++pIdx) { %>
		
		predicates[<%=pIdx%>] = <%=bindMethod.inlinePredicate(pIdx)%>;
		<% } %>
		
		EventHandler<<%=E%>, <%=P%>, <%=C%>, <%=H%>, <%=S%>> eventHandler = new AbstractEventHandler<<%=E%>, <%=P%>, <%=C%>, <%=H%>, <%=S%>>(
			<%=bindMethod.getParameterTypes().length%>, 
			<%=bindMethod.getHandlerAnnotation().priority()%>, 
			instance, 
			<%=bindMethod.getHandlerAnnotation().consumes()%>, 
			<%=bindMethod.getHandlerAnnotation().oneOff()%>, 
			Mode.<%=bindMethod.getHandlerAnnotation().mode()%>, 
			predicates) {

			@Override
			public void post(EventDispatchContext<<%=E%>, <%=P%>, <%=C%>, <%=H%>, <%=S%>> context, <%=E%>... events) {
				<% if (!bindMethod.isVoid()) {%> <%=bindMethod.getMethod().getReturnType().getCanonicalName()%> toPost  = <% } %> instance.<%=bindMethod.getMethod().getName()%>(
						<% if (bindMethod.getOffset()==1) { %>
							<% if (bindMethod.getEventDispatchContext()!=null) { %>
							
						wrap(context), 
							<% } else {%>
							context,
							<% } %>
						<% } %>
						<% for (int pIdx=0; pIdx < bindMethod.getParameterTypes().length; ++pIdx) { %>
						
						<%=bindMethod.getParameterTypeCast(pIdx)%> events[<%=pIdx%>]<% if (pIdx<bindMethod.getParameterTypes().length-1) { %>,<% } %>
						<% } %>
						
				);
				
				<% if (!bindMethod.isVoid()) {%> 
				
				if (<%=E%>.class.isInstance(toPost)) {
					context.post(toPost);
				}
				<% } %> 				
			}
			
			public String toString() {
				return "Compiled event handler for method <%=bindMethod.getMethod()%>, cardinality="+getCardinality();
			}
	
			<% if (bindMethod.getEventDispatchContext()!=null) { %>			
			private <%=bindMethod.getEventDispatchContext().getType()%> wrap(final EventDispatchContext<<%=E%>, <%=P%>, <%=C%>, <%=H%>, <%=S%>> context) {
				return new <%=bindMethod.getEventDispatchContext().getType()%>() {
		
					@Override
					public void post(<%=bindMethod.getEventDispatchContext().getEventType()%> event, Predicate<<%=bindMethod.getEventDispatchContext().getEventType()%>, <%=bindMethod.getEventDispatchContext().getStoreType()%>>... validators) {
						context.post(event, validators);
					}
		
					@Override
					public void consume(int index) {
						context.consume(index);
					}
		
					@Override
					public void consume(<%=bindMethod.getEventDispatchContext().getEventType()%> event) {
						context.consume(event);
					}
		
					@Override
					public void update(<%=bindMethod.getEventDispatchContext().getEventType()%> event) {
						context.update(event);
					}
		
					@Override
					public void removeHandler() {
						context.removeHandler();
					}
		
					@Override
					public <%=bindMethod.getEventDispatchContext().getStoreType()%> getEventStore() {
						return context.getEventStore();
					}
		
					<% if (bindMethod.getEventDispatchContext().isJoin()) { %>
					
					@Override
					public void consumeJoin(int index) {
						context.consume(index);
					}
		
					@Override
					public void consumeJoin(<%=bindMethod.getEventDispatchContext().getEventType()%> event) {
						context.consume(event);
					}
					
					@Override
					public com.hammurapi.eventbus.EventHandlerBase.Mode getMode() {
						return context.getMode();
					}
					<% } %>
					
				};
			}
			<% } %>
	
		};
		
		return bus.addHandler(eventHandler);		
	}

	<% } %>
	
}
