// Starts the simulation. It will end when no more packets are in the
  // medium
  public void runSimulator() {
    Event next;
    Packet p;

    while (true) {
      next = eventList.removeNext();

      if (next == null) {
        break;
      }

      if (traceLevel > 1) {
        System.out.println();
        System.out.println(
            "main(): event received.  t=" + next.getTime() + ", node=" + next.getEntity());
        if (next.getType() == FROMLAYER2) {
          p = next.getPacket();
          System.out.print("  src=" + p.getSource() + ", ");
          System.out.print("dest=" + p.getDest() + ", ");
          System.out.print("contents=[");
          for (int i = 0; i < NUMENTITIES - 1; i++) {
            System.out.print(p.getMincost(i) + ", ");
          }
          System.out.println(p.getMincost(NUMENTITIES - 1) + "]");
        } else if (next.getType() == LINKCHANGE) {
          System.out.println("  Link cost change.");
        }
      }

      time = next.getTime();

      if (next.getType() == FROMLAYER2) {
        p = next.getPacket();
        if ((next.getEntity() < 0) || (next.getEntity() >= NUMENTITIES)) {
          System.out.println("main(): Panic. Unknown event entity.");
        } else {
          entity[next.getEntity()].update(p);
        }
      } else if (next.getType() == LINKCHANGE) {
        if (time < 10001.0) {
          cost[0][1] = 20;
          cost[1][0] = 20;
          entity[0].linkCostChangeHandler(1, 20);
          entity[1].linkCostChangeHandler(0, 20);
        } else {
          cost[0][1] = 1;
          cost[1][0] = 1;
          entity[0].linkCostChangeHandler(1, 1);
          entity[1].linkCostChangeHandler(0, 1);
        }
      } else {
        System.out.println("main(): Panic.  Unknown event type.");
      }
    }

    System.out.println("Simulator terminated at t=" + time + ", no packets in medium.");
  }
  // Handle updates when a packet is received.
  // Students will need to call NetworkSimulator.toLayer2()
  // with new packets based upon what they
  // send to update.  Be careful to construct
  // the source and destination of the packet
  // correctly.  Read the warning in NetworkSimulator.java
  // for more details.
  public void update(Packet p) {
    /* When the update function is called with a packet, we update the destination node with the
     		routing information in the given packet.
     The packet methods used in this function are explained in the file Packet.java
     Initialize the new cost as INF, get the origin of the packet and set the "changed" FLAG to false.
     If the "changed" FLAG becomes true, we will know an update has been used and new packets are sent to
    		the neighbors of the updated node to continue the iteration.
    */
    int newCost = 999;
    int src = p.getSource();
    int[] nextDistanceVector = new int[NetworkSimulator.NUMENTITIES];
    boolean changeHandler = false;
    boolean linkchange = p.getLinkChange();
    System.out.println("heyy " + p.getLinkChange());
    /*
     * This is the crucial loop of the update function. i represents
     *   the newCost variable is initially set to be equal to the combination of
     *   the cost of getting from the node to source, plus getting from source to node i.
     *
     *  Later on, the new value for the distance table is the minimum of either the newcost or the
     *  already given value at the distanceTable.
     *
     * The new distance vector is saved as the nextDistanceVector, for updating purposes.
     */
    for (int i = 0; i < NetworkSimulator.NUMENTITIES; i++) {
      newCost = distanceVector[src] + p.getMincost(i);
      distanceTable[i][src] = newCost < distanceTable[i][src] ? newCost : distanceTable[i][src];
      nextDistanceVector[i] = Math.min(newCost, distanceVector[i]);

      // If any one of the values of the distance vector is updated, the FLAG becomes
      // 		true, which means a packet has to be sent to direct neighbors of this node.
      if (nextDistanceVector[i] != distanceVector[i]) changeHandler = true;
    }

    // The distanceVector is updated with the "next distance vector.
    distanceVector = nextDistanceVector;

    System.out.println(
        "LOG--------Entity " + thisNode + " says: Node " + thisNode + " is updated.");
    printDT();

    if (changeHandler || (linkchange && !IsMyLinkChanged)) {
      Packet packet;
      for (int j = 0; j < NetworkSimulator.NUMENTITIES; j++) {
        if (j != thisNode && NetworkSimulator.cost[thisNode][j] != 999) {
          packet = new Packet(thisNode, j, distanceVector);
          NetworkSimulator.toLayer2(packet);
          System.out.println(
              "LOG--------At Node " + thisNode + ", the distance vector has been updated.");
          System.out.println("LOG--------Packet sent from " + thisNode + " to " + j);
        }
      }
    }
    // Read the NetworkSimulator.java
    // for more details.
  }
  /**
   * ** Warning! This will allow an entity to send packets that they couldn't possibly send (e.g.
   * Entity 1 could send a packet from 0 to 3). This should be fixed later... ***
   */
  public static void toLayer2(Packet p) {
    Packet currentPacket;
    double arrivalTime;

    if ((p.getSource() < 0) || (p.getSource() >= NUMENTITIES)) {
      System.out.println("toLayer2(): WARNING: Illegal source id in " + "packet; ignoring.");
      return;
    }
    if ((p.getDest() < 0) || (p.getDest() >= NUMENTITIES)) {
      System.out.println("toLayer2(): WARNING: Illegal destination id " + "in packet; ignoring.");
      return;
    }
    if (p.getSource() == p.getDest()) {
      System.out.println(
          "toLayer2(): WARNING: Identical source and " + "destination in packet; ignoring.");
      return;
    }
    if (cost[p.getSource()][p.getDest()] == 999) {
      System.out.println(
          "toLayer2(): WARNING: Source and destination " + "not connected; ignoring.");
      return;
    }

    if (traceLevel > 2) {
      System.out.println("toLayer2(): source=" + p.getSource() + " dest=" + p.getDest());
      System.out.print("             costs:");
      for (int i = 0; i < NUMENTITIES; i++) {
        System.out.print(" " + p.getMincost(i));
      }
      System.out.println();
    }

    arrivalTime = eventList.getLastPacketTime(p.getSource(), p.getDest());
    if (arrivalTime == 0.0) {
      arrivalTime = time;
    }
    arrivalTime = arrivalTime + 1.0 + (rand.nextDouble() * 9.0);

    if (traceLevel > 2) {
      System.out.println("toLayer2(): Scheduling arrival of packet.");
    }

    currentPacket = new Packet(p);
    eventList.add(new Event(arrivalTime, FROMLAYER2, currentPacket.getDest(), currentPacket));
  }