/*
 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
 *
 *  This file is licensed to You under the Common Public License (CPL);
 *  You may not use this file except in compliance with the License. You
 *  may obtain a copy of the License at
 *
 *      http://www.opensource.org/licenses/cpl1.0.php
 *
 *  See the COPYRIGHT.txt file distributed with this work for information
 *  regarding copyright ownership.
 */
package org.jikesrvm.compilers.opt.util;

import java.util.Enumeration;


/**
 * Depth First Spanning Tree
 * March 14, 1998
 * Builds topological sort of a graph consisting of SortedGraphNode.
 */
public final class TopSort extends Stack<SortedGraphNode> {

  /**
   * the "visited" marker to use
   */
  private int sortMarker;

  /**
   * the next "number" to give out
   */
  private int sortNumber;

  /**
   * the last node to get a number
   */
  private SortedGraphNode lastNumberedNode;

  /**
   * are we processing the graph in forward order?
   */
  private boolean forward;

  /**
   * Prevent instantiation
   */
  private TopSort() { }

  /**
   * @param graph the graph
   * @param forward should we treat edges as forward?
   *  This is the second version of the implementation
   *   (see CVS file for older one)
   */
  public static SortedGraphNode buildTopological(TopSortInterface graph, boolean forward) {

    SortedGraphNode start = graph.startNode(forward);
    TopSort sorter = new TopSort();
    sorter.sortMarker = SortedGraphNode.getNewSortMarker(start);
    sorter.forward = forward;
    sorter.DFS(start, graph.numberOfNodes());
    return sorter.lastNumberedNode;
  }

  /**
   * Depth-first numbering in a non-recursive manner
   * @param node the root node
   * @param numNodes the number of nodes in this graph
   */
  private void DFS(SortedGraphNode node, int numNodes) {

    // push node on to the emulated activation stack
    push(node);
    @SuppressWarnings("unchecked") // the java generic array problem
        Enumeration<? extends SortedGraphNode>[] nodeEnum = new Enumeration[numNodes];

    recurse:
    while (!empty()) {

      node = peek();

      // check if we were already processing this node, if so we would have
      // saved the state of the enumeration in the loop below
      Enumeration<? extends SortedGraphNode> _enum = nodeEnum[node.getNumber()];
      if (_enum == null) {
        // mark node as visited
        node.setSortMarker(sortMarker);
        if (forward) {
          _enum = node.getOutNodes();
        } else {
          _enum = node.getInNodes();
        }
      }

      while (_enum.hasMoreElements()) {
        SortedGraphNode target = _enum.nextElement();

        // have we visited target?
        if (target.getSortMarker() != sortMarker) {
          // simulate a recursive call
          // but first save the enumeration state for resumption later
          nodeEnum[node.getNumber()] = _enum;
          push(target);
          continue recurse;
        }
      }

      // give node the next smallest number
      node.setSortNumber(sortNumber--, forward);
      // link it to the previous smallest node, even if that node is null
      node.setSortedNext(lastNumberedNode, forward);
      // update the smallest node
      lastNumberedNode = node;

      // "Pop" from the emulated activiation stack
      pop();
    }
  }
}



