001    package com.hammurapi.reasoning.impl;
002    
003    import java.util.ArrayList;
004    import java.util.Collection;
005    import java.util.Iterator;
006    import java.util.List;
007    import java.util.concurrent.Future;
008    
009    import com.hammurapi.flow.runtime.ProcessingPathElement;
010    import com.hammurapi.flow.runtime.PropertySet;
011    import com.hammurapi.flow.runtime.impl.Joiner.InputConsumer;
012    import com.hammurapi.reasoning.ReasoningException;
013    import com.hammurapi.util.Context;
014    
015    
016    /**
017     * Base class for condition nodes.
018     * 
019     * @author Pavel Vlasov
020     * 
021     */
022    public abstract class ConditionNode<F> extends ReasoningNodeBase<F> {
023    
024            /**
025             * Dispatch inputs to outputs.
026             */
027            @SuppressWarnings("unchecked")
028            @Override
029            protected Collection<Future<?>> process(
030                            KnowledgeBase<F> flowState,
031                            List<InferenceToken<F>>[] inputs, 
032                            PropertySet properties,
033                            Context context, 
034                            List<ProcessingPathElement> processingPath,
035                            InputConsumer consumer,
036                            int activator) throws Exception {
037                    
038                    Collection<Future<?>> ret = new ArrayList<Future<?>>();
039                    
040                    boolean dispatched = false; 
041                    Z: for (PinEntry<F> pin: pins) {
042                            if (pin.getName().startsWith(Constants.OUTPUT)) {
043                                    for (Object alt: pin.config) {
044                                            List<TokenInfo> lti=(List<TokenInfo>) alt;
045                                            InferenceToken<F>[] out = match(inputs, lti);
046                                            if (out!=null) {
047                                                    dispatched = true;
048                                                    for (Output<F> output: pin.outputs) {
049                                                            ret.addAll(output.invocable.invoke(flowState, out, properties, context, processingPath));
050                                                    }
051                                                    
052                                                    continue Z;
053                                            }
054                                    }
055                            }
056                    }
057                    if (!dispatched) {
058                            throw new IllegalArgumentException("Condition output was not dispatched to any output pins");
059                    }
060                    return ret;
061            }
062            
063            /**
064             * Matches input tokens with output config.
065             * @param inputs
066             * @param outputConfig
067             * @return Filled out output array or null if there is no match.
068             * @throws ReasoningException 
069             */
070            @SuppressWarnings("unchecked")
071            private InferenceToken<F>[] match(List<InferenceToken<F>>[] inputs, List<TokenInfo> outputConfig) throws ReasoningException {
072                    InferenceToken<F>[] out = new InferenceToken[outputConfig.size()];
073                    Iterator<TokenInfo> outputConfigIterator = outputConfig.iterator();
074                    Z: for (int outputIdx=0; outputConfigIterator.hasNext(); ++outputIdx) {
075                            TokenInfo outputTokenInfo = outputConfigIterator.next();
076                            Iterator<PinEntry<F>> inputPinIterator = getInputPins().iterator();
077                            for (int inputPinIndex=0; inputPinIterator.hasNext(); ++inputPinIndex) {
078                                    PinEntry<F> inputPin = inputPinIterator.next();
079                                    List<TokenInfo> pinConfig = (List<TokenInfo>) inputPin.config;
080                                    Iterator<TokenInfo> inputTokenInfoIterator = pinConfig.iterator();
081                                    for (int inputTokenIndex=0; inputTokenInfoIterator.hasNext(); ++inputTokenIndex) {
082                                            TokenInfo inputTokenInfo = inputTokenInfoIterator.next();
083                                            if (outputTokenInfo.getParameterIndex() == inputTokenInfo.getParameterIndex()) {
084                                                    InferenceToken<F> it = inputs[inputPinIndex].get(inputTokenIndex);
085                                                    if (it.isConsumed()) {
086                                                            return null;
087                                                    }
088                                                    
089                                                    if (!outputTokenInfo.getType().isInstance(knowledgeBase.get(it.getHandle()))) {
090                                                            return null;
091                                                    }
092                                                    
093                                                    out[outputIdx] = it;
094                                                    continue Z;
095                                            }                                                               
096                                    }
097                            }
098                            throw new IllegalArgumentException("Could not find input for output index "+outputIdx);                 
099                    }               
100                    return out;
101            }
102            
103    }