/* (non-Javadoc)
   * @see jist.swans.field.StreetMobility#setNextRoad(jist.swans.field.StreetMobilityInfo)
   */
  public void setNextRoad(StreetMobilityInfo smi) {

    StreetMobilityInfoOD smiod = (StreetMobilityInfoOD) smi;

    if (smiod.path.size() > 0 || smiod.config == Constants.MOBILITY_STREET_RANDOM) {
      // get next intersection
      smiod.nextIs = intersections.findIntersectingRoads(smiod.rsEnd);

      if (smiod.path.size() == 0
          || (RECALCULATE_ALWAYS
              && JistAPI.getTime() > 30 * Constants.SECOND
              && smiod.path.size() > 2
              && smiod.speedSum > 0)) // calculate new path
      {
        // indicate that node should be taken off map
        if (smiod.config == Constants.MOBILITY_STREET_FLOW && smiod.path.size() == 0) {
          smi.nextRS = null;
          return;
        }

        if (DEBUG_OD) System.out.println("Calculating new path...");
        // recalculate path based on congestion info
        if (smiod.path.size() > 2 && smiod.nextEnd != null) {
          LinkedList oldPath = (LinkedList) smiod.path.clone();
          SegmentNode nextOne = (SegmentNode) smiod.path.getFirst();
          RoadSegment origin = (RoadSegment) segments.get(nextOne.segmentID);
          SegmentNode dest = smiod.destinationSN;
          RoadSegment rs = (RoadSegment) segments.get(smiod.destinationSN.segmentID);

          calculatePath(smiod, smi.current, smi.rsEnd, rs);

          if (!smiod.path.getLast().equals(dest))
            throw new RuntimeException("Destination altered!");

          if (smiod.current.equals(
              (RoadSegment) segments.get(((SegmentNode) smiod.path.getFirst()).segmentID)))
            smiod.path.remove();
          if (smiod.path.getFirst().equals(nextOne)) ;
          else {
            if (DEBUG_VIS_OD && v != null) {
              v.drawCircle(
                  20, smiod.rsEnd /*(smiod.rsEnd.distance(smi.current.getEndPoint())==0
                                ? smi.current.getStartPoint() : smi.current.getEndPoint())*/);
              oldPath.addLast(new SegmentNode(smi.rsEnd, smi.current.getSelfIndex(), true, true));
              smiod.path.addLast(
                  new SegmentNode(smi.rsEnd, smi.current.getSelfIndex(), true, true));
              showPath(oldPath.toArray(), Color.RED);
              showPath(smiod.path.toArray(), Color.ORANGE);
              smiod.path.removeLast();
              System.out.println("Foo!");
            }
          }
          checkPath(smiod);
          if (smiod.current.equals(
              (RoadSegment) segments.get(((SegmentNode) smiod.path.getFirst()).segmentID)))
            smiod.path = oldPath;

        } else {
          // this section makes sure that a valid path is found:
          // 1) there must be a path from origin to destination on the map
          // 2) the path must be longer than 4 so that it's substantial
          boolean valid = false;
          while (!valid || smiod.path.size() < 4) {
            RoadSegment nextDest = null;
            int segmentSize = sni.segment.size();

            while (nextDest == null
                || nextDest.getSelfIndex() == smiod.current.getSelfIndex()
                || nextDest.getEndPoint().distance(smiod.current.getEndPoint())
                    > threshold) // get new destination
            {
              int i = rnd.nextInt(segmentSize);
              nextDest = (RoadSegment) sni.segment.get(i);
            }
            valid = calculatePath(smiod, smi.current, smi.rsEnd, nextDest);
          }
          checkPath(smiod);
        }
        if (DEBUG_OD) System.out.println("Current rsEnd: " + smi.rsEnd);
        if (DEBUG_OD)
          System.out.println("Current road: " + smi.current.printStreetName(sni.streets));
      }

      SegmentNode sn = (SegmentNode) smiod.path.get(0);
      RoadSegment rs = (RoadSegment) segments.get(sn.segmentID);
      updateNextRoadSegment(smiod, rs); // update next road
      smiod.path.remove(0); // already used the first entry

      while (smiod.path.size() > 0) {
        // weird intersection type that confuses A*
        // getting on a street for no distance...
        sn = (SegmentNode) smiod.path.get(0); // was zero
        rs = (RoadSegment) segments.get(sn.segmentID);
        if (smiod.rsEnd.distance(rs.getStartPoint()) == 0
            || smiod.rsEnd.distance(rs.getEndPoint()) == 0) {
          if (DEBUG_OD) System.out.println("rsEnd: " + smiod.rsEnd);
          if (DEBUG_OD) System.out.println("Current street: " + rs.printStreetName(sni.streets));

          if (DEBUG_OD) System.out.println("Fixing A* bug...");
          updateNextRoadSegment(smiod, rs);
          smiod.path.remove(0);

        } else {
          break;
        }
      }
    } else if (smiod.config == Constants.MOBILITY_STREET_FLOW) {
      smiod.nextRS = null;
      smiod.nextEnd = null;
    } else if (smiod.config == Constants.MOBILITY_STREET_CIRCUIT) {
      smiod.path = (LinkedList) routes[smiod.routeIndex].clone();
      SegmentNode sn = (SegmentNode) smiod.path.get(0);
      RoadSegment rs = (RoadSegment) segments.get(sn.segmentID);
      updateNextRoadSegment(smiod, rs); // update next road
      smiod.path.remove(0); // already used the first entry
    }
  }
 /**
  * Create new Java application harness.
  *
  * @param app main class of Java application
  * @throws NoSuchMethodException unable to find main method in application class
  */
 public AppJava(Class app) throws NoSuchMethodException {
   this.app = app;
   findMain(app);
   self = (AppInterface) JistAPI.proxy(this, AppInterface.class);
 }
 /**
  * Set application TCP entity.
  *
  * @param tcp tcp entity
  */
 public void setTcpEntity(TransInterface.TransTcpInterface tcp) {
   if (!JistAPI.isEntity(tcp)) throw new IllegalArgumentException("expected entity");
   this.tcp = tcp;
 }
 /** {@inheritDoc} */
 public void setCurrentThread(SimtimeThread thread) {
   if (!JistAPI.isEntity(thread)) throw new IllegalArgumentException("expected entity");
   this.thread = thread;
 }
 /**
  * Set application UDP entity.
  *
  * @param udp udp entity
  */
 public void setUdpEntity(TransInterface.TransUdpInterface udp) {
   if (!JistAPI.isEntity(udp)) throw new IllegalArgumentException("expected entity");
   this.udp = udp;
 }