package com.hammurapi.reasoning.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;

import com.hammurapi.flow.Flow;
import com.hammurapi.flow.Node;
import com.hammurapi.flow.Pin;
import com.hammurapi.flow.Transition;
import com.hammurapi.flow.runtime.impl.PassThroughTransition;

/**
 * Optimizes flow by finding equal conditions emanating from
 * the same pin and merging them.
 * @author Pavel Vlasov
 *
 */
public class ConditionSharingOptimizer implements RuleSetFlowOptimizer {

	// TODO - Copy connection keys during optimization.
	
	/*
	 * Algorithm:
	 * 1. Iterate over pins
	 * 2. For a pin iterate over all permutations of two outbound transitions.
	 * 3. If transitions are passthrough or mapping, and the nodes on the other ends are conditional, check two nodes for equality.
	 * 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.
	 * 5. Reconnect transitions, change pass-through to mapping or change mapping where required.  
	 */
	
	@Override
	public void optimize(Flow ruleSetFlow) {		
		boolean optimized;
		Z: do {
			optimized = false;
			TreeIterator<EObject> rcit = ruleSetFlow.eAllContents();
			N: while (rcit.hasNext()) {
				EObject next = rcit.next();
				if (next instanceof Pin) {					
					Pin pin = (Pin) next;
					Transition[] outputs = pin.getOutput().toArray(new Transition[pin.getOutput().size()]);
					/* For every two outbound transitions from the pin we check if the transitions
					 * are pass-through
					 */
					for (int idx1=0; idx1<outputs.length-1; ++idx1) {
						for (int idx2=idx1+1; idx2<outputs.length; ++idx2) {
							if (isPassThrhoughOrMapping(outputs[idx1]) && isPassThrhoughOrMapping(outputs[idx2])) {
								Pin pin1 = outputs[idx1].getToPin();
								Pin pin2 = outputs[idx2].getToPin();
								/*
								 * If target pins belong to condition nodes
								 */
								if (ConditionNode.class.equals(pin1.getNode().getType()) &&	ConditionNode.class.equals(pin2.getNode().getType())) {
									/* List of parameter mappings with which conditions are equal. Maps parameters of the second node to 
									 * parameters of the first node. */									
									List<Map<Integer, Integer>> paramMaps = new ArrayList<Map<Integer, Integer>>();
									if (equal(pin1.getNode(), pin2.getNode(), paramMaps)) {
										throw new UnsupportedOperationException();
									}
								}
							}
						}
					}
					
				}
			}						
		} while (optimized);		
	}

	private boolean sameName(String name, String name2) {
		return name==null ? name2==null : name.equals(name2);
	}

	/**
	 * Compares conditions.
	 * @param name
	 * @param node
	 * @return
	 */
	private boolean equal(Node node1, Node node2, List<Map<Integer,Integer>> paramMaps) {
		// TODO Auto-generated method stub
		return false;
	}

	private boolean isPassThrhoughOrMapping(Transition transition) {
		return PassThroughTransition.class.getName().equals(transition.getType()) || MappingTransition.class.getName().equals(transition.getType());
	}
	
	/**
	 * This optimization shall be executed after elimination
	 * of unnecessary pass-through nodes and transitions.
	 */
	@Override
	public int getOrder() {
		return 10;
	}

}
