001    package com.hammurapi.reasoning.impl;
002    
003    import java.util.ArrayList;
004    import java.util.List;
005    import java.util.Map;
006    
007    import org.eclipse.emf.common.util.TreeIterator;
008    import org.eclipse.emf.ecore.EObject;
009    
010    import com.hammurapi.flow.Flow;
011    import com.hammurapi.flow.Node;
012    import com.hammurapi.flow.Pin;
013    import com.hammurapi.flow.Transition;
014    import com.hammurapi.flow.runtime.impl.PassThroughTransition;
015    
016    /**
017     * Optimizes flow by finding equal conditions emanating from
018     * the same pin and merging them.
019     * @author Pavel Vlasov
020     *
021     */
022    public class ConditionSharingOptimizer implements RuleSetFlowOptimizer {
023    
024            // TODO - Copy connection keys during optimization.
025            
026            /*
027             * Algorithm:
028             * 1. Iterate over pins
029             * 2. For a pin iterate over all permutations of two outbound transitions.
030             * 3. If transitions are passthrough or mapping, and the nodes on the other ends are conditional, check two nodes for equality.
031             * 4. If nodes are equal or mappingly equal, check that all inbound transitions can be re-connected from one node's pins to the other's pins.
032             * 5. Reconnect transitions, change pass-through to mapping or change mapping where required.  
033             */
034            
035            @Override
036            public void optimize(Flow ruleSetFlow) {                
037                    boolean optimized;
038                    Z: do {
039                            optimized = false;
040                            TreeIterator<EObject> rcit = ruleSetFlow.eAllContents();
041                            N: while (rcit.hasNext()) {
042                                    EObject next = rcit.next();
043                                    if (next instanceof Pin) {                                      
044                                            Pin pin = (Pin) next;
045                                            Transition[] outputs = pin.getOutput().toArray(new Transition[pin.getOutput().size()]);
046                                            /* For every two outbound transitions from the pin we check if the transitions
047                                             * are pass-through
048                                             */
049                                            for (int idx1=0; idx1<outputs.length-1; ++idx1) {
050                                                    for (int idx2=idx1+1; idx2<outputs.length; ++idx2) {
051                                                            if (isPassThrhoughOrMapping(outputs[idx1]) && isPassThrhoughOrMapping(outputs[idx2])) {
052                                                                    Pin pin1 = outputs[idx1].getToPin();
053                                                                    Pin pin2 = outputs[idx2].getToPin();
054                                                                    /*
055                                                                     * If target pins belong to condition nodes
056                                                                     */
057                                                                    if (ConditionNode.class.equals(pin1.getNode().getType()) &&     ConditionNode.class.equals(pin2.getNode().getType())) {
058                                                                            /* List of parameter mappings with which conditions are equal. Maps parameters of the second node to 
059                                                                             * parameters of the first node. */                                                                     
060                                                                            List<Map<Integer, Integer>> paramMaps = new ArrayList<Map<Integer, Integer>>();
061                                                                            if (equal(pin1.getNode(), pin2.getNode(), paramMaps)) {
062                                                                                    throw new UnsupportedOperationException();
063                                                                            }
064                                                                    }
065                                                            }
066                                                    }
067                                            }
068                                            
069                                    }
070                            }                                               
071                    } while (optimized);            
072            }
073    
074            private boolean sameName(String name, String name2) {
075                    return name==null ? name2==null : name.equals(name2);
076            }
077    
078            /**
079             * Compares conditions.
080             * @param name
081             * @param node
082             * @return
083             */
084            private boolean equal(Node node1, Node node2, List<Map<Integer,Integer>> paramMaps) {
085                    // TODO Auto-generated method stub
086                    return false;
087            }
088    
089            private boolean isPassThrhoughOrMapping(Transition transition) {
090                    return PassThroughTransition.class.getName().equals(transition.getType()) || MappingTransition.class.getName().equals(transition.getType());
091            }
092            
093            /**
094             * This optimization shall be executed after elimination
095             * of unnecessary pass-through nodes and transitions.
096             */
097            @Override
098            public int getOrder() {
099                    return 10;
100            }
101    
102    }