/**
   * Method orginally found in whatif.cpp
   *
   * @param packets returns timestampList - List of doubles
   */
  private Map<PacketInfo, Double> normalizeCore(List<PacketInfo> packets) {

    // Step 1: Identify Promotions
    List<RrcStateRange> promoDelays = new ArrayList<RrcStateRange>();
    for (RrcStateRange rrc : analysis.getRrcStateMachine().getRRcStateRanges()) {
      RRCState state = rrc.getState();
      if (state == RRCState.PROMO_FACH_DCH || state == RRCState.PROMO_IDLE_DCH)
        promoDelays.add(rrc);
    }
    Collections.sort(promoDelays);
    PacketTimestamp[] timeStampList = new PacketTimestamp[packets.size()];
    for (int i = 0; i < packets.size(); i++) {
      timeStampList[i] = new PacketTimestamp(packets.get(i));
    }

    // Step 2: Remove all promo delays
    int m = promoDelays.size();
    double timeStampShift = 0.0f;
    int j = 0;
    int j0 = -1; // "in-the-middle" position
    double middlePos = 0; // How to initialize??
    for (int i = 0; i < timeStampList.length; i++) {
      double timeStamp = timeStampList[i].timestamp;
      while (j < m && timeStamp >= promoDelays.get(j).getEndTime() - EPS) {
        if (j0 != -1) {
          assert (j0 == j && i > 0 && promoDelays.get(j).getEndTime() >= middlePos);
          timeStampShift += promoDelays.get(j).getEndTime() - middlePos;
          j0 = -1;
        } else {
          timeStampShift += promoDelays.get(j).getEndTime() - promoDelays.get(j).getBeginTime();
        }
        j++;
      }
      if (j < m
          && (promoDelays.get(j).getBeginTime() - EPS) < timeStamp
          && timeStamp < (promoDelays.get(j).getEndTime() + EPS)) {
        if (j0 == -1) {
          timeStampShift += timeStamp - promoDelays.get(j).getBeginTime();
          middlePos = timeStamp;
          j0 = j;
        } else {
          assert (j0 == j && i > 0);
          assert (timeStamp >= middlePos);
          timeStampShift += timeStamp - middlePos;
          middlePos = timeStamp;
        }
      }
      timeStampList[i].timestamp = timeStampList[i].timestamp - timeStampShift;
      assert (i == 0 || timeStampList[i].timestamp >= timeStampList[i - 1].timestamp);
    }
    Map<PacketInfo, Double> result = new LinkedHashMap<PacketInfo, Double>(timeStampList.length);
    for (int i = 0; i < timeStampList.length; ++i) {
      result.put(timeStampList[i].packet, timeStampList[i].timestamp);
    }
    return result;
  }
  /** Computes the total burst energy. */
  private void computeBurstEnergyRadioResource() {
    List<RrcStateRange> rrcCollection = analysis.getRrcStateMachine().getRRcStateRanges();
    int rrcCount = rrcCollection.size();
    if (rrcCount == 0) {
      return;
    }
    int p = 0;
    double time2 = -1;
    double totalEnergy = 0.0f;
    Iterator<Burst> iter = burstCollection.iterator();
    Burst currentBurst = iter.next();
    double time1 = rrcCollection.get(0).getBeginTime();
    while (true) {
      Burst nextBurst = iter.hasNext() ? iter.next() : null;
      time2 =
          nextBurst != null
              ? nextBurst.getBeginTime()
              : rrcCollection.get(rrcCount - 1).getEndTime();
      double e = 0.0f;
      double activeTime = 0.0f;
      while (p < rrcCount) {
        RrcStateRange rrCntrl = rrcCollection.get(p);
        if (rrCntrl.getEndTime() < time1) {
          p++;
        } else {
          if (time2 > rrCntrl.getEndTime()) {
            e +=
                profile.energy(
                    time1, rrCntrl.getEndTime(), rrCntrl.getState(), analysis.getPackets());
            if ((rrCntrl.getState() == RRCState.STATE_DCH
                    || rrCntrl.getState() == RRCState.TAIL_DCH)
                || (rrCntrl.getState() == RRCState.LTE_CONTINUOUS
                    || rrCntrl.getState() == RRCState.LTE_CR_TAIL)
                || (rrCntrl.getState() == RRCState.WIFI_ACTIVE
                    || rrCntrl.getState() == RRCState.WIFI_TAIL)) {
              activeTime += rrCntrl.getEndTime() - time1;
            }
            p++;
          }
          break;
        }
      }
      while (p < rrcCount) {
        RrcStateRange rrCntrl = rrcCollection.get(p);
        if (rrCntrl.getEndTime() < time2) {
          e +=
              profile.energy(
                  Math.max(rrCntrl.getBeginTime(), time1),
                  rrCntrl.getEndTime(),
                  rrCntrl.getState(),
                  analysis.getPackets());
          if ((rrCntrl.getState() == RRCState.STATE_DCH || rrCntrl.getState() == RRCState.TAIL_DCH)
              || (rrCntrl.getState() == RRCState.LTE_CONTINUOUS
                  || rrCntrl.getState() == RRCState.LTE_CR_TAIL)
              || (rrCntrl.getState() == RRCState.WIFI_ACTIVE
                  || rrCntrl.getState() == RRCState.WIFI_TAIL)) {
            activeTime += rrCntrl.getEndTime() - Math.max(rrCntrl.getBeginTime(), time1);
          }
          p++;
        } else {
          e +=
              profile.energy(
                  Math.max(rrCntrl.getBeginTime(), time1),
                  time2,
                  rrCntrl.getState(),
                  analysis.getPackets());
          if ((rrCntrl.getState() == RRCState.STATE_DCH || rrCntrl.getState() == RRCState.TAIL_DCH)
              || (rrCntrl.getState() == RRCState.LTE_CONTINUOUS
                  || rrCntrl.getState() == RRCState.LTE_CR_TAIL)
              || (rrCntrl.getState() == RRCState.WIFI_ACTIVE
                  || rrCntrl.getState() == RRCState.WIFI_TAIL)) {
            activeTime += time2 - Math.max(rrCntrl.getBeginTime(), time1);
          }
          break;
        }
      }
      currentBurst.setEnergy(e);
      totalEnergy += e;
      currentBurst.setActiveTime(activeTime);

      time1 = time2;
      if (nextBurst != null) {
        currentBurst = nextBurst;
      } else {
        break;
      }
    }
    this.totalEnergy = totalEnergy;
  }