package com.hammurapi.reasoning.impl;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Future;

import com.hammurapi.flow.runtime.Invocable;
import com.hammurapi.flow.runtime.Invoker;
import com.hammurapi.flow.runtime.ProcessingPathElement;
import com.hammurapi.flow.runtime.PropertySet;
import com.hammurapi.flow.runtime.impl.Inlineable;
import com.hammurapi.util.Context;

/**
 * This transition passes through only invocations with single parameter of specified type.
 * @author Pavel Vlasov
 *
 */
public class TypeFilterTransition<F> extends ReasoningTransitionBase<F> implements Inlineable {
	
	private Class<F> type;

	public void setType(Class<F> type) {
		this.type = type;
	}

	@Override
	public Invocable<KnowledgeBase<F>,InferenceToken<F>> getInvocable() {
		return invocable;
	}
	
	private Invocable<KnowledgeBase<F>,InferenceToken<F>> next;
	
	private Invoker<KnowledgeBase<F>,InferenceToken<F>> invoker = new Invoker<KnowledgeBase<F>,InferenceToken<F>>() {

		@Override
		public void setInvocable(Invocable<KnowledgeBase<F>,InferenceToken<F>> invocable) {
			next = invocable;			
		}
		
	};
	
	private Invocable<KnowledgeBase<F>,InferenceToken<F>> invocable = new Invocable<KnowledgeBase<F>,InferenceToken<F>>() {

		@Override
		public Collection<Future<?>> invoke(
				KnowledgeBase<F> flowState,
				InferenceToken<F>[] args,				
				PropertySet properties,
				Context context, 
				List<ProcessingPathElement> processingPath) throws Exception {
			
			if (args!=null 
					&& args.length==1 
					&& !args[0].isConsumed()
					&& type.isInstance(knowledgeBase.get(args[0].getHandle()))) {
				return next.invoke(flowState, args, properties, context, processingPath);
			}
			return Collections.emptySet();
		}
		
	};

	@Override
	public Invoker<KnowledgeBase<F>,InferenceToken<F>> getInvoker() {
		return invoker;
	}

	@Override
	public boolean inline() {
		return true;
	}

}
