package javakurs.uebung09.aufgabe2;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javakurs.musterloesung.uebung08.DirectedGraph;
import javakurs.musterloesung.uebung08.DirectedGraphTest.EqualsPredicate;
import javakurs.musterloesung.uebung08.Edge;
import javakurs.musterloesung.uebung08.VertexPropertyMap;

/**
 * {@link DijkstraShortestPathTest} is a test class for
 * {@link DijkstraShortestPath}.
 *
 * @author Bernd Kiefer, DFKI
 * @author Joerg Steffen, DFKI
 * @version $Id: DijkstraShortestPathTest.java,v 1.1 2011/01/10 16:29:58 steffen Exp $
 */
public final class DijkstraShortestPathTest {

  /**
   * This would create a new instance of {@link DijkstraShortestPathTest}. Not
   * to be used.
   */
  private DijkstraShortestPathTest() {

    // private constructor to enforce noninstantiability
  }


  /**
   * Use this example to test the Dijkstra SSSP algorithm.
   *
   * @return the example graph or {@code null} if an error appeared
   */
  public static DirectedGraph<Integer> getExampleGraphDijkstra() {

    String graphString =
      "s --> w(2) z(4)\n"
        + "z --> w(5) y(9)\n"
        + "v --> w(1) s(6)\n"
        + "w --> x(6) q(3)\n"
        + "t --> u(1) v(9) s(8)\n"
        + "u --> t(5) v(7)\n"
        + "x --> z(8) u(7)\n"
        + "q --> x(2)\n"
        + "y --> x(5)\n";

    DirectedGraph<Integer> graph = null;
    try {
      graph = readGraph(new StringReader(graphString));
    } catch (IOException e) {
      e.printStackTrace();
    }
    return graph;
  }


  /**
   * Creates a graph from a readable specification including edge weights.
   *
   * @param in
   *          the reader from which to read the graph
   * @return the graph
   * @throws IOException
   *           if there is an error when reading the graph
   */
  public static DirectedGraph<Integer> readGraph(Reader in)
      throws IOException {

    BufferedReader bin = new BufferedReader(in);

    DirectedGraph<Integer> result = new DirectedGraph<Integer>();
    EqualsPredicate<String> eqPred = new EqualsPredicate<String>();

    VertexPropertyMap<String> names = new VertexPropertyMap<String>(result);
    result.register("names", names);

    Pattern nw = Pattern.compile("([^(]*)\\(([0-9]*)\\)");

    String nextLine = null;
    while ((nextLine = bin.readLine()) != null) {
      String[] fromTo = nextLine.split("\\s*-->\\s*");
      if (fromTo.length < 1) {
        continue;
      }

      List<Integer> nodes = names.findVertices(fromTo[0], eqPred);
      int from = -1;
      if (nodes.isEmpty()) {
        from = result.newVertex();
        names.put(from, fromTo[0]);
      }
      else {
        from = nodes.get(0);
      }

      if (fromTo.length == 2) {
        String[] token = fromTo[1].split("\\s+");

        for (String nameWeight : token) {
          Matcher nameAndWeight = nw.matcher(nameWeight);
          if (!nameAndWeight.matches()) {
            continue;
          }

          String name = nameAndWeight.group(1);
          int weight = Integer.parseInt(nameAndWeight.group(2));
          nodes = names.findVertices(name, eqPred);
          int to = -1;
          if (nodes.isEmpty()) {
            to = result.newVertex();
            names.put(to, name);
          }
          else {
            to = nodes.get(0);
          }

          result.newEdge(weight, from, to);
        }
      }
    }
    return result;
  }


  /**
   * This is the main method. It requires no arguments.
   *
   * @param args
   *          the arguments; not used here
   */
  public static void main(String[] args) {

    DirectedGraph<Integer> graph = getExampleGraphDijkstra();

    System.out.println(graph);

    List<Edge<Integer>> result =
      DijkstraShortestPath.shortestPath(
        graph, 0, graph.getNumberOfVertices() - 1);

    VertexPropertyMap<String> names =
      (VertexPropertyMap<String>)graph.getPropertyMap("names");

    System.out.print(names.get(0));
    for (Edge<Integer> edge : result) {
      System.out.print(
        "--" + edge.getEdgeInfo() + "-->" + names.get(edge.getEndVertex()));
    }
    System.out.println();
  }
}
