/*
 *    Fernflower - The Analytical Java Decompiler
 *    http://www.reversed-java.com
 *
 *    (C) 2008 - 2010, Stiver
 *
 *    This software is NEITHER public domain NOR free software 
 *    as per GNU License. See license.txt for more details.
 *
 *    This software is distributed WITHOUT ANY WARRANTY; without 
 *    even the implied warranty of MERCHANTABILITY or FITNESS FOR 
 *    A PARTICULAR PURPOSE. 
 */

package de.fernflower.modules.decompiler.sforms;

import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;

import de.fernflower.modules.decompiler.exps.Exprent;
import de.fernflower.modules.decompiler.sforms.FlattenStatementsHelper.FinallyPathWrapper;
import de.fernflower.util.VBStyleCollection;


public class DirectGraph {

	public VBStyleCollection<DirectNode, String> nodes = new VBStyleCollection<DirectNode, String>(); 
	
	public DirectNode first; 
	
	// exit, [source, destination]
	public HashMap<String, List<FinallyPathWrapper>> mapShortRangeFinallyPaths = new HashMap<String, List<FinallyPathWrapper>>(); 
	
	// exit, [source, destination]
	public HashMap<String, List<FinallyPathWrapper>> mapLongRangeFinallyPaths = new HashMap<String, List<FinallyPathWrapper>>(); 
	
	// negative if branches (recorded for handling of && and ||)
	public HashMap<String, String> mapNegIfBranch = new HashMap<String, String>(); 
	
	// nodes, that are exception exits of a finally block with monitor variable
	public HashMap<String, String> mapFinallyMonitorExceptionPathExits = new HashMap<String, String>(); 
	
	public void sortReversePostOrder() {
		LinkedList<DirectNode> res = new LinkedList<DirectNode>();
		addToReversePostOrderListIterative(first, res);
		
		nodes.clear();
		for(DirectNode node: res) {
			nodes.addWithKey(node, node.id);
		}
	}
	
	private void addToReversePostOrderListIterative(DirectNode root, List<DirectNode> lst) {
		
		LinkedList<DirectNode> stackNode = new LinkedList<DirectNode>();
		LinkedList<Integer> stackIndex = new LinkedList<Integer>();
		
		HashSet<DirectNode> setVisited = new HashSet<DirectNode>();
		
		stackNode.add(root);
		stackIndex.add(0);
		
		while(!stackNode.isEmpty()) {
			
			DirectNode node = stackNode.getLast();
			int index = stackIndex.removeLast();

			setVisited.add(node);
			
			for(;index<node.succs.size();index++) {
				DirectNode succ = node.succs.get(index);
				
				if(!setVisited.contains(succ)) {
					stackIndex.add(index+1);
					
					stackNode.add(succ);
					stackIndex.add(0);
					
					break;
				}
			}
			
			if(index == node.succs.size()) {
				lst.add(0, node);
				
				stackNode.removeLast();
			}
		}
		
	}
	
	
	public boolean iterateExprents(ExprentIterator iter) {

		LinkedList<DirectNode> stack = new LinkedList<DirectNode>();
		stack.add(first);
		
		HashSet<DirectNode> setVisited = new HashSet<DirectNode>(); 
		
		while(!stack.isEmpty()) {
			
			DirectNode node = stack.removeFirst();
			
			if(setVisited.contains(node)) {
				continue;
			}
			setVisited.add(node);

			for(int i=0;i<node.exprents.size();i++) {
				int res = iter.processExprent(node.exprents.get(i));
				
				if(res == 1) {
					return false;
				}
				
				if(res == 2) {
					node.exprents.remove(i);
					i--;
				}
			}
			
			stack.addAll(node.succs);
		}
		
		return true;
	}
	
	public interface ExprentIterator {
		// 0 - success, do nothing
		// 1 - cancel iteration
		// 2 - success, delete exprent
		public int processExprent(Exprent exprent);
	}
}
