package jimDij;

import java.util.*;

/***
 * Dijekstra finds the minimum paths through a graph.
 * This is a demo for both the intro programming and the
 * algorithms classes.
 *
 * @author  Jim Mahoney (mahoney@marlboro.edu)
 * @version 0.1 Nov 25 2002
 ***/

public class Dijkstra {

    private static Graph theGraph;
    private static final String dataFile   = "g5.obj";
    private static final String startPlace = "Tokushima";

    /***
     * What program would be complete without a main() method?
     ***/
    public static void main(String[] args){
        
        println("");
        print(" Reading data from '" + dataFile + "' ... ");
        theGraph = ReadData.initData(dataFile, startPlace);
        println(" done.");

        println("");
        print(" Building search tree ... ");
        doDijekstraSearch(true);                // true => verbose
        println(" done.");

        println("");
        println(" Here's the final data structure : ");
        theGraph.displayAsText();

        println("");
        println(" And here are the paths: ");
        theGraph.displayAllPaths();
    }

    // ------- The core of the algorithm -----------------------

    /*****
     * Finds the shortest paths from the starting 
     * node to every other node.  The answer is stored within then
     * Nodes, in the parent and pathDistance instance variables.
     *
     * The data structure should be set up before this is called.
     *
     * @param verbose    "true" means  print out the details of the search
     *****/
    public static void doDijekstraSearch(boolean verbose){
        int count=0;
        final int ITERATION_LIMIT = 1000;
        if (verbose){ println(""); }

        // When the algorithm starts, all the nodes are colored white
        // (which means we haven't looked at any of them), and 
        // all the total distance guess (pathDistance) in the nodes
        // are set to very large numbers - except
        // for the starting node, which is set to pathDistance zero.

        // Loop over all white nodes.
        while (true){

            // Count is only for safety, to catch infinite loops.
            count++;
            if (verbose) { println("-- loop "+count+" --"); }
            if (count>ITERATION_LIMIT){
                println(" +++ OOPS - HIT ITERATION LIMIT +++");
                return;
            }

            // (1) Get the next Node that we haven't done (a white one).
            Node currentNode = theGraph.getSmallestWhiteNode();
            if (currentNode==null){
                return;                 // We're finished if we can't
            }                           // find a white one.

            if (verbose) {
                println("");
                println("New white: ");
                currentNode.displayAsText();
            }
            
            // (2) Mark the current node as being finished (i.e. black).
            currentNode.setColor(Node.BLACK);

            // (3) Loop over all the edges that lead out from this Node.
            Iterator e = currentNode.edgeIterator();
            while (e.hasNext()){
                Edge edge = (Edge)e.next();
                Node neighbor = edge.getToNode();

                // Examine only neighbors which are not black.
                if (neighbor.isBlack()){
                    continue;
                }
                if (verbose){
                    print(" Looking at ");
                    neighbor.displayAsText();
                }

                // (4) Find the total distance to the neighbors
                //     using a path through the current node.
                int throughHere = currentNode.getPathDistance() 
                    + edge.getDistance();
                if (verbose) {println(" throughHere = "+throughHere);}

                //     If that's shorter than our best guess
                //     so far to that node, then
                //     remember the current node as its parent
                //     and the distance through this node as our
                //     best guess so far.
                if (neighbor.getPathDistance() > throughHere) {
                    neighbor.setPathDistance(throughHere);
                    neighbor.setParent(currentNode);
                }

                if (verbose){
                    print(" Leaving ");
                    neighbor.displayAsText();
                }
            }
            if (verbose){ println(""); }
        }
    }

    // -----  a few utility routines ----------------------------

    /***
     * Shorthand for System.out.println(String s).
     * Prints out its argument followed by a new line.
     * @param String s   what to print
     **/
    public static void println(String s){
        System.out.println(s);
    }

    /***
     * Shorthand for System.out.print(String s)
     * @param String s what to print
     **/
    public static void print(String s){
        System.out.print(s);
    }


}


syntax highlighted by Code2HTML, v. 0.9.1