private void checkExcepction(Collection<Vertex> v, Collection<Edge> e) {
    for (Edge edge : e) {
      // No edge from or to vertex labeled A if there is no vertex with
      // label A
      if (!v.contains(edge.getSource()) || !v.contains(edge.getDestination())) {
        throw new IllegalArgumentException();
      }

      // Edge weights should not be negative
      if (edge.getWeight() < 0) {
        throw new IllegalArgumentException();
      }

      // Collection of edges should not has the same directed edge more
      // than once
      // with a different weight
      for (Edge checkEdges : e) {
        if (checkEdges.getSource().equals(edge.getSource())
            && checkEdges.getDestination().equals(edge.getDestination())
            && checkEdges.getWeight() != edge.getWeight()) {
          throw new IllegalArgumentException();
        }
      }
    }
  }
 @Override
 public Vertex<V> opposite(Vertex<V> v, Edge<E, V> e) {
   Vertex<V> vt;
   if (e.getSource().equals(v)) vt = (Vertex<V>) e.getDestination();
   else if (e.getDestination().equals(v)) vt = (Vertex<V>) e.getSource();
   else vt = null;
   return vt;
 }
 @SuppressWarnings("unchecked")
 @Override
 public boolean areAdjacent(Vertex<V> v, Vertex<V> w) {
   boolean b = false;
   Edge<E, V> eg = (Edge<E, V>) edges.getHeader();
   while (eg != null && !b) {
     if ((eg.getDestination().equals(v) || eg.getSource().equals(v))
         && (eg.getDestination().equals(w) || eg.getSource().equals(w))) b = true;
     try {
       eg = (Edge<E, V>) edges.next((Pointer<E>) eg.getPosition()).element();
     } catch (Exception exc) {
       eg = null;
     }
   }
   return b;
 }
 /**
  * Test whether vertex b is adjacent to vertex a (i.e. a -> b) in a directed graph. Assumes that
  * we do not have negative cost edges in the graph.
  *
  * @param a one vertex
  * @param b another vertex
  * @return cost of edge if there is a directed edge from a to b in the graph, return -1 otherwise.
  * @throws IllegalArgumentException if a or b do not exist.
  */
 @Override
 public int edgeCost(Vertex a, Vertex b) {
   if (a == null || b == null || !totalVertices.contains(a) || !totalVertices.contains(b)) {
     throw new IllegalArgumentException();
   }
   for (Edge edge : adj.get(a)) {
     if (edge.getDestination().equals(b)) {
       return edge.getWeight();
     }
   }
   return -1;
 }
 @SuppressWarnings("unchecked")
 @Override
 public void reverseDirection() {
   Edge<E, V> h = (Edge<E, V>) edges.getHeader();
   while (h != null) {
     Vertex<V> temp = h.getSource();
     h.setSource(h.getDestination());
     h.setDestination(temp);
     try {
       h = (Edge<E, V>) edges.next((Pointer<E>) h.getPosition()).element();
     } catch (Exception exc) {
       h = null;
     }
   }
 }
 @SuppressWarnings("unchecked")
 public String printEdges(String type) {
   String s = "";
   Edge<E, V> eg = (Edge<E, V>) edges.getHeader();
   while (eg != null) {
     if (eg.getType().equals(type))
       s += eg.getSource().getInfo() + " -> " + eg.getDestination().getInfo() + "\n";
     try {
       eg = (Edge<E, V>) edges.next((Pointer<E>) eg.getPosition()).element();
     } catch (Exception exc) {
       eg = null;
     }
   }
   return s;
 }
  /**
   * Return a collection of vertices adjacent to a given vertex v. i.e., the set of all vertices w
   * where edges v -> w exist in the graph. Return an empty collection if there are no adjacent
   * vertices.
   *
   * @param v one of the vertices in the graph
   * @return an iterable collection of vertices adjacent to v in the graph
   * @throws IllegalArgumentException if v does not exist.
   */
  @Override
  public Collection<Vertex> adjacentVertices(Vertex v) {
    if (v == null || !totalVertices.contains(v)) {
      throw new IllegalArgumentException();
    }
    List<Vertex> destiVertex = new ArrayList<Vertex>();

    // Returns the edge to which the specified key is mapped, or null if
    // this map contains no mapping for the key.Then add the edge to the
    // ArrayList
    for (Edge e : adj.get(v)) {
      destiVertex.add(e.getDestination());
    }
    return destiVertex;
  }
  @SuppressWarnings("unchecked")
  @Override
  public Iterator<Vertex<V>> adjacentVertices(Vertex<V> v) {
    List<Vertex<V>> coll = new ArrayList<Vertex<V>>();
    Edge<E, V> head_edg = (Edge<E, V>) edges.getHeader();
    while (head_edg != null) {
      if (head_edg.getSource().equals(v)) coll.add((Vertex<V>) head_edg.getDestination());
      try {
        head_edg = (Edge<E, V>) edges.next((Pointer<E>) head_edg.getPosition()).element();
      } catch (Exception exc) {
        head_edg = null;
      }
    }

    return coll.iterator();
  }
  /**
   * Returns the shortest path from a to b in the graph, or null if there is no such path. Assumes
   * all edge weights are nonnegative. Uses Dijkstra's algorithm.
   *
   * @param a the starting vertex
   * @param b the destination vertex
   * @return a Path where the vertices indicate the path from a to b in order and contains a (first)
   *     and b (last) and the cost is the cost of the path. Returns null if b is not reachable from
   *     a.
   * @throws IllegalArgumentException if a or b does not exist.
   */
  public Path shortestPath(Vertex a, Vertex b) {

    List<Vertex> vertexList = new ArrayList<Vertex>();
    VertexComparator vcp = new VertexComparator();
    PriorityQueue<Vertex> vertexQueue =
        new PriorityQueue<Vertex>(10, vcp); // queue for unknow vertex

    // If the start and end vertex are equal
    // return a path containing one vertex and a cost of 0.
    if (a.equals(b)) {
      vertexList.add(a);
      return new Path(vertexList, 0);
    }

    // if the start and end vertex are not equal:

    // if there is no path starting from a, return null
    if (!adj.containsKey(a)) {
      return null;
    }

    // for (Vertex v : this.vertices() ) {
    //    System.out.println(v.known);
    // }

    // initialize before searching path
    for (Vertex v : adj.keySet()) {
      // variables in adj.keySet() are actually pointers pointing to different memory with those in
      // this.vertices()
      // what we need is actually to change those in memory pointed by this.vertices()
      // have no idea why this.vertices.get() method did not work
      // thus I have to implement as below
      Vertex vn = v; // actually this is a bad initialization
      for (Vertex vi : this.vertices()) {
        if (vi.equals(v)) {
          vn = vi;
        }
      }

      vn.known = false;
      // set all vertex distance to infinity
      vn.distance = Integer.MAX_VALUE;
      // vn.distance = 99999;
      vertexQueue.add(vn);
    }
    // System.exit(1);
    // Set source vertex distance to 0
    for (Vertex vn : this.vertices()) {
      if (vn.equals(a)) {
        vertexQueue.remove(vn);
        vn.distance = 0;
        vn.previous = vn;
        // update vn in vertexQueue
        vertexQueue.add(vn);
      }
    }
    // a.distance = 0;
    // a.previous = a;
    // vertexQueue.remove(a);
    // vertexList.add(a);

    Vertex end = b;
    for (Vertex vn : this.vertices()) {
      if (vn.equals(b)) {
        end = vn;
      }
    }
    // for (Vertex v : this.vertices() ) {
    //    System.out.println(v.distance);
    // }
    System.out.println("start searching...");
    // while ( (!vertexQueue.isEmpty()) && (end.known == false) ) { //while there are still unknow
    // vertex and vertex b is unknown
    while ((!vertexQueue
        .isEmpty())) { // while there are still unknow vertex and vertex b is unknown
      // System.out.println("elements in vertexQueue at beginning:");
      // for (Vertex v : vertexQueue ) {
      //    System.out.println(v.getLabel());
      //    System.out.println("distance: " + v.distance);
      // }
      Vertex nt = vertexQueue.poll(); // unknown node with smallest distance
      // System.out.println("marked " + nt + " as known.");
      // System.out.println("its current distance: " + nt.distance);
      nt.known = true;
      for (Edge e : adj.get(nt)) {
        // search for vertex with the same name as e.getDestination() in this.vertices()
        Vertex en = e.getDestination();
        for (Vertex vn : this.vertices()) {
          if (vn.equals(e.getDestination())) {
            en = vn;
          }
        }

        if (!en.known) {
          if ((nt.distance + e.getWeight()) < en.distance) {
            // update en in vertexQueue
            vertexQueue.remove(en);
            en.distance = nt.distance + e.getWeight();
            en.previous = nt;
            vertexQueue.add(en);
          }
        }
      }
    }
    System.out.println("finished computing shortest path.");
    // for (Vertex v : this.vertices() ) {
    //    System.out.println(v.distance);
    // }

    // traverse to get path from a to b
    Vertex tmp = end;
    while (!tmp.equals(a)) {
      vertexList.add(0, tmp); // may need a heap here?
      tmp = tmp.previous;
    }
    vertexList.add(0, a);
    return new Path(vertexList, end.distance);

    // TODO: after searching for all possible path, return null if there is no path from a to b

  }