/**
   * Test 0: Graph with no bifurcations. 100 nodes. G = 1 for all edges H = TargetsID - currentID
   * Expected: 1. Every node should be visited 2. ParentID = SonsID - 1
   */
  public void test_0() {
    final int nnodes = 100;
    Node[] ends = GraphTestUtil.buildNoBifurcations(builder(), nnodes);

    CountingWalker walker = new CountingWalker();

    final AStarIterator iterator = createIterator(ends[0], ends[ends.length - 1]);

    BasicGraphTraversal traversal = new BasicGraphTraversal(builder().getGraph(), walker, iterator);
    traversal.init();
    traversal.traverse();

    GraphVisitor visitor =
        new GraphVisitor() {
          public int visit(Graphable component) {
            assertTrue(component.isVisited());
            if (component.getID() == 0) assertNull(iterator.getParent((Node) component));
            else assertTrue(component.getID() == iterator.getParent((Node) component).getID() + 1);
            return 0;
          }
        };
    builder().getGraph().visitNodes(visitor);

    assertTrue(walker.getCount() == nnodes);
  }
  /**
   * Create a graph with no bifurcations and start a traversal from start node, then suspend, and
   * resume. <br>
   * <br>
   * Expected: After suspend: 1. Nodes from 0 to suspend node should be visted, others not.
   *
   * <p>After resume: 1. Next node visited should have id suspend node id + 1 2. Every node should
   * have a parent with id node id + 1
   */
  public void test_1() {
    int nnodes = 100;
    Node[] ends = GraphTestUtil.buildNoBifurcations(builder(), nnodes);
    final int suspend = 50;

    CountingWalker walker =
        new CountingWalker() {
          int m_mode = 0;

          public int visit(Graphable element, GraphTraversal traversal) {
            super.visit(element, traversal);
            if (m_mode == 0) {
              if (element.getID() == suspend) {
                m_mode++;
                return (GraphTraversal.SUSPEND);
              }
            } else if (m_mode == 1) {
              assertTrue(element.getID() == suspend + 1);
              m_mode++;
            }
            return (GraphTraversal.CONTINUE);
          }
        };

    final AStarIterator iterator = createIterator(ends[0], ends[ends.length - 1]);

    BasicGraphTraversal traversal = new BasicGraphTraversal(builder().getGraph(), walker, iterator);
    traversal.init();
    traversal.traverse();

    GraphVisitor visitor =
        new GraphVisitor() {
          public int visit(Graphable component) {
            if (component.getID() <= suspend) assertTrue(component.isVisited());
            else assertTrue(!component.isVisited());
            return 0;
          }
        };
    builder().getGraph().visitNodes(visitor);
    assertTrue(walker.getCount() == nnodes - suspend + 1);

    // resume
    traversal.traverse();

    visitor =
        new GraphVisitor() {
          public int visit(Graphable component) {
            assertTrue(component.isVisited());
            if (component.getID() == 0) assertNull(iterator.getParent((Node) component));
            else assertTrue(iterator.getParent((Node) component).getID() == component.getID() - 1);

            return 0;
          }
        };
    builder().getGraph().visitNodes(visitor);
    assertTrue(walker.getCount() == nnodes);
  }
  /**
   * Create a balanced binary tree and do a normal traversal starting at root. <br>
   * <br>
   * Expected: 1. #nodes_visited <= #nodes 2. The parent of each node should be the same as the
   * parent of the tree. 3. G = depth. H = infinity if the target is not in any subtree of this node
   * or depth difference between target node and current node otherwise.
   *
   * @throws WrongPathException
   */
  public void test_3() {
    int k = 4;
    Object[] obj = GraphTestUtil.buildPerfectBinaryTree(builder(), k);
    final Node root = (Node) obj[0];
    final HashMap map = (HashMap) obj[1];
    HashMap rmap = new HashMap();
    Map.Entry[] set = new Map.Entry[map.size()];
    map.entrySet().toArray(set);
    for (int i = 0; i < set.length; i++) {
      rmap.put(set[i].getValue(), set[i].getKey());
    }
    final HashMap hashmap = rmap;

    class Factory {
      public AStarIterator.AStarFunctions createFunctions(Node target) {
        return (new AStarIterator.AStarFunctions(target) {
          public double cost(AStarNode n1, AStarNode n2) {
            return 1;
          }

          public double h(Node n) {
            String dest = hashmap.get(this.getDest()).toString();
            String current = hashmap.get(n).toString();
            if (dest.startsWith(current)) {
              // n under dest
              dest = dest.replaceAll("\\D", "");
              current = current.replaceAll("\\D", "");
              return dest.length() - current.length();
            } else {
              return Double.POSITIVE_INFINITY;
            }
          }
        });
      }
    }
    Factory f = new Factory();

    AStarShortestPathFinder walker =
        new AStarShortestPathFinder(
            builder().getGraph(),
            root,
            ((Node) map.get("0.1.0.1")),
            f.createFunctions(((Node) map.get("0.1.0.1"))));

    walker.calculate();
    MyVisitor visitor = new MyVisitor();
    builder().getGraph().visitNodes(visitor);
    // #1
    assertTrue(visitor.count > 0);
    assertTrue(visitor.count < map.size() + 1);
    Path p = null;
    try {
      p = walker.getPath();
    } catch (Exception e) {
      e.printStackTrace();
    }
    p.getEdges();
    assertTrue(p.size() == 4);
    // #2
    for (int j = 0; j < p.size() - 1; j++) {
      Node n = (Node) p.get(j);
      Node parent = (Node) p.get(j + 1);
      String n_id = rmap.get(n).toString();
      String parent_id = rmap.get(parent).toString();
      assertTrue(n_id.startsWith(parent_id));
    }
  }