public void setCongestionMonitor(CongestionMonitor cmi) {
   sni.cm = cmi;
 }
  /**
   * This method calculates the path from the origin to the destination road segment.
   *
   * @param smiod The SMIOD object.
   */
  public boolean calculatePath(
      StreetMobilityInfoOD smiod, RoadSegment origin, Location nextEnd, RoadSegment destination) {
    // TODO support loading from OD pairs
    // after calling constructor, objects for A* search must be created
    boolean found = false;

    // TODO the caller should determine direction
    if (DEBUG_OD) {
      System.out.println("Calculating path...");
      System.out.println("Origin:      " + origin.printStreetName(streets));
      System.out.println("Destination: " + destination.printStreetName(streets));
      System.out.println(
          "Distance: " + origin.getStartPoint().distance(destination.getStartPoint()));
    }

    if (nextEnd == null) {
      if (smiod.rsEnd.distance(origin.getEndPoint()) == 0) {
        nextEnd = origin.getEndPoint();
      } else {
        nextEnd = origin.getStartPoint();
      }
    }
    if (DEBUG_OD && DEBUG_VIS_OD && v != null) {
      v.colorSegment(origin, Color.RED);
    }

    boolean endStart;
    Location endPoint;
    if (destination.getStartPoint().distance(nextEnd)
        < destination.getEndPoint().distance(nextEnd)) {
      endPoint = destination.getStartPoint();
      endStart = true;
    } else {
      endPoint = destination.getEndPoint();
      endStart = false;
    }

    SegmentNode startNode =
        new SegmentNode(
            nextEnd, origin.getSelfIndex(), origin.getStartPoint().distance(nextEnd) == 0, true);
    SegmentNode endNode = new SegmentNode(endPoint, destination.getSelfIndex(), endStart, false);
    sni.dest = endNode;

    // try to find cached path
    if (hm != null) {
      LinkedList ll = (LinkedList) hm.get(nextEnd);
      if (ll != null) {
        ListIterator li = ll.listIterator();

        while (li.hasNext()) {
          LinkedList path = (LinkedList) li.next();
          if (!matches(startNode, endNode, path)) {
            continue;
          }
          smiod.path = (LinkedList) path.clone();
          smiod.path.removeFirst();
          if (DEBUG_OD) System.out.println("Found cached path!");
          return true;
          //                    break;
        }
      }
    }
    if (!found) {

      //      TODO support locations at arbitrary points on road
      smiod.destinationSN = endNode;
      smiod.destinationLocation = destination.getEndPoint();

      AStarSearch ass = new AStarSearch(hm, this); // TODO rename variable
      smiod.path = ass.findPath(startNode, endNode); // find the path
    }

    // no path found
    if (smiod.path.get(0) == null) {
      AStarSearch ass = new AStarSearch(hm, this); // TODO rename variable
      smiod.path = ass.findPath(startNode, endNode); // find the path
      if (v != null) {
        v.colorSegments(
            new RoadSegment[] {origin, destination}, new Color[] {Color.RED, Color.RED});
      }
      smiod.path.remove(0);
      System.out.println("No path found!");
      return false;
    }

    if (DEBUG_VIS_OD && v != null) {
      showPath(smiod.path.toArray(), Color.BLUE);
    }

    // check for strange double entry in list
    for (int i = 1; i < smiod.path.size(); i++) {
      if (((SegmentNode) smiod.path.get(smiod.path.size() - i)).segmentID
          == ((SegmentNode) smiod.path.get(smiod.path.size() - (i + 1))).segmentID) {
        if (DEBUG_OD) System.out.println("Removed redundant entry!");
        smiod.path.remove(smiod.path.size() - i);
      }
    }

    if (DEBUG_OD) printPath(smiod.path);
    if (hm != null) cachePath(smiod, startNode, endNode);

    return true; // path found!
  }