// Path: measures/src/main/java/io/apisense/network/MeasurementError.java
// public class MeasurementError extends Exception {
//   public final String taskName;
// 
//   public MeasurementError(String taskName, String reason) {
//     super(reason);
//     this.taskName = taskName;
//   }
// 
//   public MeasurementError(String taskName, String reason, Throwable e) {
//     super(reason, e);
//     this.taskName = taskName;
//   }
// 
//   public MeasurementError(String taskName, Exception e) {
//     this(taskName, e.getMessage(), e);
//   }
// }


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import io.apisense.network.MeasurementError;
package io.apisense.network.udp;



/**
 * @author Hongyi Yao (hyyao@umich.edu) A helper structure for packing and unpacking network
 *         message
 */
final class UDPPacket {
  static final int PKT_ERROR = 1;
  static final int PKT_RESPONSE = 2;
  static final int PKT_DATA = 3;
  static final int PKT_REQUEST = 4;

  /**
   * Name of the task to referecence in case of a {@link MeasurementError}.
   */
  private final String taskName;

  /**
   * Type of the {@link UDPPacket},
   * may be {@link UDPPacket#PKT_ERROR}, {@link UDPPacket#PKT_RESPONSE},
   * {@link UDPPacket#PKT_DATA}, or {@link UDPPacket#PKT_REQUEST}
   */
  public final int type;

  /**
   * Number of burst to send.
   */
  public final int burstCount;
  /**
   * Number of packet received in a wrong order
   */
  public final int outOfOrderNum;
  /**
   * Data packet: local timestamp
   * Response packet: jitter
   */
  public final long timestamp;
  /**
   * Size of each UDP packet to send.
   */
  public final int packetSize;
  /**
   * Request sequence number.
   */
  public final int seq;
  /**
   * Time to wait between each packet.
   */
  public final int udpInterval;
  /**
   * Identification of the packet,
   * determine its order in the sequence.
   */
  public int packetNum;

  /**
   * Build from scratch an {@link UDPPacket} from the given configuration.
   *
   * @param taskName Name of the task to referecence in case of a {@link MeasurementError}
   * @param type     Type of packet to build.
   * @param config   Burst configuration to set in the packet.
   */
  public UDPPacket(String taskName, int type, UDPBurstConfig config) {
    this.taskName = taskName;
    this.type = type;
    this.burstCount = config.getUdpBurstCount();
    this.packetSize = config.getPacketSizeByte();
    this.udpInterval = (int) Math.ceil(config.getUdpInterval() / 1000); // convert µs to ms
    this.seq = 0;

    // Unrelevant properties
    outOfOrderNum = 0;
    timestamp = System.currentTimeMillis();

  }

  /**
   * Unpack received message and fill the structure
   *
   * @param taskName Name of the task to referecence in case of a {@link MeasurementError}
   * @param rawdata  Network message
   * @throws MeasurementError stream reader failed
   */
// Path: measures/src/main/java/io/apisense/network/MeasurementError.java
// public class MeasurementError extends Exception {
//   public final String taskName;
// 
//   public MeasurementError(String taskName, String reason) {
//     super(reason);
//     this.taskName = taskName;
//   }
// 
//   public MeasurementError(String taskName, String reason, Throwable e) {
//     super(reason, e);
//     this.taskName = taskName;
//   }
// 
//   public MeasurementError(String taskName, Exception e) {
//     this(taskName, e.getMessage(), e);
//   }
// }


// Path: measures/src/main/java/io/apisense/network/udp/UDPPacket.java
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import io.apisense.network.MeasurementError;

package io.apisense.network.udp;



/**
 * @author Hongyi Yao (hyyao@umich.edu) A helper structure for packing and unpacking network
 *         message
 */
final class UDPPacket {
  static final int PKT_ERROR = 1;
  static final int PKT_RESPONSE = 2;
  static final int PKT_DATA = 3;
  static final int PKT_REQUEST = 4;

  /**
   * Name of the task to referecence in case of a {@link MeasurementError}.
   */
  private final String taskName;

  /**
   * Type of the {@link UDPPacket},
   * may be {@link UDPPacket#PKT_ERROR}, {@link UDPPacket#PKT_RESPONSE},
   * {@link UDPPacket#PKT_DATA}, or {@link UDPPacket#PKT_REQUEST}
   */
  public final int type;

  /**
   * Number of burst to send.
   */
  public final int burstCount;
  /**
   * Number of packet received in a wrong order
   */
  public final int outOfOrderNum;
  /**
   * Data packet: local timestamp
   * Response packet: jitter
   */
  public final long timestamp;
  /**
   * Size of each UDP packet to send.
   */
  public final int packetSize;
  /**
   * Request sequence number.
   */
  public final int seq;
  /**
   * Time to wait between each packet.
   */
  public final int udpInterval;
  /**
   * Identification of the packet,
   * determine its order in the sequence.
   */
  public int packetNum;

  /**
   * Build from scratch an {@link UDPPacket} from the given configuration.
   *
   * @param taskName Name of the task to referecence in case of a {@link MeasurementError}
   * @param type     Type of packet to build.
   * @param config   Burst configuration to set in the packet.
   */
  public UDPPacket(String taskName, int type, UDPBurstConfig config) {
    this.taskName = taskName;
    this.type = type;
    this.burstCount = config.getUdpBurstCount();
    this.packetSize = config.getPacketSizeByte();
    this.udpInterval = (int) Math.ceil(config.getUdpInterval() / 1000); // convert µs to ms
    this.seq = 0;

    // Unrelevant properties
    outOfOrderNum = 0;
    timestamp = System.currentTimeMillis();

  }

  /**
   * Unpack received message and fill the structure
   *
   * @param taskName Name of the task to referecence in case of a {@link MeasurementError}
   * @param rawdata  Network message
   * @throws MeasurementError stream reader failed
   */
  public UDPPacket(String taskName, byte[] rawdata) throws MeasurementError {