// Path: src/main/java/com/j2js/Log.java
// public class Log {
// 	
//     public static Log logger;
//     
//     public static Log getLogger() {
//         return logger;
//     }
//     
//     private int state = INFO;
//     
//     /**
//      * @return Returns the state.
//      */
//     public int getState() {
//         return state;
//     }
// 
//     /**
//      * @param state The state to set.
//      */
//     public void setState(int state) {
//         this.state = state;
//     }
// 
//     public static final int DEBUG = 3;
//     public static final int INFO = 2;
//     public static final int WARN = 1;
//     public static final int ERROR = 0;
//     
//     public void debug(CharSequence arg0, Throwable arg1) {
//         if (isDebugEnabled()) {
//             System.out.println("[DEBUG] " + arg0);
//             arg1.printStackTrace();
//         }
//     }
// 
//     public void debug(CharSequence arg0) {
//         if (isDebugEnabled()) {
//             System.out.println("[DEBUG] " + arg0);
//         }
//     }
// 
//     public void debug(Throwable arg0) {
//         if (isDebugEnabled()) {
//             arg0.printStackTrace();
//         }
//     }
// 
//     public void error(CharSequence arg0, Throwable arg1) {
//         if (isErrorEnabled()) {
//             System.out.println("[ERROR] " + arg0);
//             arg1.printStackTrace();
//         }
//     }
// 
//     public void error(CharSequence arg0) {
//         if (isErrorEnabled()) {
//             System.out.println("[ERROR] " + arg0);
//         }
//     }
// 
//     public void error(Throwable arg0) {
//         if (isErrorEnabled()) {
//             arg0.printStackTrace();
//         }
//     }
// 
//     public void info(CharSequence arg0, Throwable arg1) {
//         if (isInfoEnabled()) {
//             System.out.println("[INFO] " + arg0);
//             arg1.printStackTrace();
//         }
//     }
// 
//     public void info(CharSequence arg0) {
//         if (isInfoEnabled()) {
//             System.out.println("[INFO] " + arg0);
//         }
//     }
// 
//     public void info(Throwable arg0) {
//         if (isInfoEnabled()) {
//             arg0.printStackTrace();
//         }
//     }
// 
//     public boolean isDebugEnabled() {
//         return state >= DEBUG;
//     }
// 
//     public boolean isErrorEnabled() {
//         return state >= ERROR;
//     }
// 
//     public boolean isInfoEnabled() {
//         return state >= INFO;
//     }
// 
//     public boolean isWarnEnabled() {
//         return state >= WARN;
//     }
// 
//     public void warn(CharSequence arg0, Throwable arg1) {
//         if (isWarnEnabled()) {
//             System.out.println("[WARNING] " + arg0);
//             arg1.printStackTrace();
//         }
//     }
// 
//     public void warn(CharSequence arg0) {
//         if (isWarnEnabled()) {
//             System.out.println("[WARNING] " + arg0);
//         }
//     }
// 
//     public void warn(Throwable arg0) {
//         if (isWarnEnabled()) {
//             arg0.printStackTrace();
//         }
//     }
//     
// }


import java.util.*;
import com.j2js.Log;
package com.j2js.cfg;



/**
 * Class to build the dominator tree of a given control flow graph.
 * The algorithm is according Purdum-Moore, which isn't as fast as Lengauer-Tarjan, but a lot simpler.
 */
public class DominatorTree {
  
    private ControlFlowGraph graph;
    
    public DominatorTree(ControlFlowGraph theGraph) {
        graph = theGraph;
    }
    
    /**
     * Sets the pre-order index of a node.
     */
    private void visit(Node node, Collection<Node> visited) {
        // Establish preorder index.
        node.setPreOrderIndex(visited.size());
        visited.add(node);
        
        for (Node succ : node.succs()) {
            if (! visited.contains(succ)) {
                visit(succ, visited);
            }
        }

    }
    
    /**
     * Builds the dominator tree and store it in the respective nodes. 
     * It will remove all unreachable nodes on the way!
     */  
    public void build() {

        // Construct list of nodes in pre-order order.
        ArrayList<Node> preOrder = new ArrayList<Node>();
      
        visit(graph.getSource(), preOrder);

        // Remove unreachable nodes.
        for (Node node :  new ArrayList<Node>(graph.getNodes())) {
            if (!preOrder.contains(node)) {
// Path: src/main/java/com/j2js/Log.java
// public class Log {
// 	
//     public static Log logger;
//     
//     public static Log getLogger() {
//         return logger;
//     }
//     
//     private int state = INFO;
//     
//     /**
//      * @return Returns the state.
//      */
//     public int getState() {
//         return state;
//     }
// 
//     /**
//      * @param state The state to set.
//      */
//     public void setState(int state) {
//         this.state = state;
//     }
// 
//     public static final int DEBUG = 3;
//     public static final int INFO = 2;
//     public static final int WARN = 1;
//     public static final int ERROR = 0;
//     
//     public void debug(CharSequence arg0, Throwable arg1) {
//         if (isDebugEnabled()) {
//             System.out.println("[DEBUG] " + arg0);
//             arg1.printStackTrace();
//         }
//     }
// 
//     public void debug(CharSequence arg0) {
//         if (isDebugEnabled()) {
//             System.out.println("[DEBUG] " + arg0);
//         }
//     }
// 
//     public void debug(Throwable arg0) {
//         if (isDebugEnabled()) {
//             arg0.printStackTrace();
//         }
//     }
// 
//     public void error(CharSequence arg0, Throwable arg1) {
//         if (isErrorEnabled()) {
//             System.out.println("[ERROR] " + arg0);
//             arg1.printStackTrace();
//         }
//     }
// 
//     public void error(CharSequence arg0) {
//         if (isErrorEnabled()) {
//             System.out.println("[ERROR] " + arg0);
//         }
//     }
// 
//     public void error(Throwable arg0) {
//         if (isErrorEnabled()) {
//             arg0.printStackTrace();
//         }
//     }
// 
//     public void info(CharSequence arg0, Throwable arg1) {
//         if (isInfoEnabled()) {
//             System.out.println("[INFO] " + arg0);
//             arg1.printStackTrace();
//         }
//     }
// 
//     public void info(CharSequence arg0) {
//         if (isInfoEnabled()) {
//             System.out.println("[INFO] " + arg0);
//         }
//     }
// 
//     public void info(Throwable arg0) {
//         if (isInfoEnabled()) {
//             arg0.printStackTrace();
//         }
//     }
// 
//     public boolean isDebugEnabled() {
//         return state >= DEBUG;
//     }
// 
//     public boolean isErrorEnabled() {
//         return state >= ERROR;
//     }
// 
//     public boolean isInfoEnabled() {
//         return state >= INFO;
//     }
// 
//     public boolean isWarnEnabled() {
//         return state >= WARN;
//     }
// 
//     public void warn(CharSequence arg0, Throwable arg1) {
//         if (isWarnEnabled()) {
//             System.out.println("[WARNING] " + arg0);
//             arg1.printStackTrace();
//         }
//     }
// 
//     public void warn(CharSequence arg0) {
//         if (isWarnEnabled()) {
//             System.out.println("[WARNING] " + arg0);
//         }
//     }
// 
//     public void warn(Throwable arg0) {
//         if (isWarnEnabled()) {
//             arg0.printStackTrace();
//         }
//     }
//     
// }


// Path: src/main/java/com/j2js/cfg/DominatorTree.java
import java.util.*;
import com.j2js.Log;

package com.j2js.cfg;



/**
 * Class to build the dominator tree of a given control flow graph.
 * The algorithm is according Purdum-Moore, which isn't as fast as Lengauer-Tarjan, but a lot simpler.
 */
public class DominatorTree {
  
    private ControlFlowGraph graph;
    
    public DominatorTree(ControlFlowGraph theGraph) {
        graph = theGraph;
    }
    
    /**
     * Sets the pre-order index of a node.
     */
    private void visit(Node node, Collection<Node> visited) {
        // Establish preorder index.
        node.setPreOrderIndex(visited.size());
        visited.add(node);
        
        for (Node succ : node.succs()) {
            if (! visited.contains(succ)) {
                visit(succ, visited);
            }
        }

    }
    
    /**
     * Builds the dominator tree and store it in the respective nodes. 
     * It will remove all unreachable nodes on the way!
     */  
    public void build() {

        // Construct list of nodes in pre-order order.
        ArrayList<Node> preOrder = new ArrayList<Node>();
      
        visit(graph.getSource(), preOrder);

        // Remove unreachable nodes.
        for (Node node :  new ArrayList<Node>(graph.getNodes())) {
            if (!preOrder.contains(node)) {
                Log.getLogger().warn("Unreachable code detected and removed");