/**
   * Agenda eventos de envio e de chegada de pacote no roteador.
   *
   * @param tx Servidor de saída do pacote.
   */
  private void newTxPacketHeadsToRouter(Tx tx) {
    Pack nextTcpPack = tx.sendPacket(currentTime);
    tx.setTransmiting(true);
    double propagation = setPropagationDelay(tx);

    Event endOfTransmition = new Event(EventType.TxPacketHeadsToRouter);
    endOfTransmition.setTime(currentTime + transmissionTimeMs);
    endOfTransmition.setTxIndex(tx.getIndex());
    getEvents().add(endOfTransmition);

    Event routerReceivesTcp = new Event(EventType.TxPacketIntoRouter);
    routerReceivesTcp.setTime(currentTime + transmissionTimeMs + propagation);
    routerReceivesTcp.setPack(nextTcpPack);
    getEvents().add(routerReceivesTcp);

    Event timeout = new Event(EventType.Timeout);
    timeout.setTime(currentTime + tx.getRTO());
    timeout.setTxIndex(tx.getIndex());
    nextTcpPack.setTimeout(timeout);
    getEvents().add(timeout);

    if (tx.getNotDeliveredPacks().contains(nextTcpPack)) {
      int index = tx.getNotDeliveredPacks().indexOf(nextTcpPack);
      Pack p = tx.getNotDeliveredPacks().get(index);
      getEvents().remove(p.getTimeout());
      tx.getNotDeliveredPacks().remove(index);
    }

    tx.getNotDeliveredPacks().add(nextTcpPack);
  }
  /**
   * A fila de eventos precisa ser setada com eventos iniciais. Este método seta envios de pacotes
   * de congestionamento (tráfego de fundo) e também envios de pacotes vindo dos Txs.
   */
  private void setFirstEvents() {
    resetSimulation();

    // Prepara o tráfego de fundo.
    if (SimulationProperties.isWithCongestion()) {
      Event firstCongestionPack =
          new Event(
              EventType
                  .CongestionPacketIntoRouter); // Evento "Pacote de Tráfego de Fundo chegar ao
                                                // roteador"
      firstCongestionPack.setTime(random.generateExponential(1.0 / congestionPacketFrequency));
      getEvents().add(firstCongestionPack);
    }

    // Prepara os servidores para transmissão de Tx-Rx.
    for (Tx tx : getSystem().getTxs()) {
      double propagationDelay = setPropagationDelay(tx);
      // Fator aleatório além da propagação e da transmissão.
      // É zero por padrão, mas este intervalo muda nos cenários 2 e 3.
      double randTime = random.generateDouble() * SimulationProperties.getAssyncInterval();

      Event packSent = new Event(EventType.TxPacketHeadsToRouter); // Evento "Pacote sair do Tx"
      packSent.setTime(randTime + transmissionTime);
      packSent.setTxIndex(tx.getIndex());
      getEvents().add(packSent);

      Pack pack = tx.sendPacket(randTime);
      Event firstTcpPack =
          new Event(EventType.TxPacketIntoRouter); // Evento "Pacote TCP chegar ao roteador"
      firstTcpPack.setTime(randTime + transmissionTime + propagationDelay);
      firstTcpPack.setPack(pack);
      getEvents().add(firstTcpPack);

      Event possibleTimeout = new Event(EventType.Timeout); // Evento "Possível Timeout do pacote"
      possibleTimeout.setTime(randTime + tx.getRTO());
      possibleTimeout.setTxIndex(tx.getIndex());
      pack.setTimeout(possibleTimeout);
      getEvents().add(possibleTimeout);
    }
  }