/*
   * Update the tree for a given trace
   */
  private void updateStats(Map<String, Long> eventsPerType) {

    final TmfStatisticsTree statsData = TmfStatisticsTreeManager.getStatTree(fViewer.getTreeID());
    if (statsData == null) {
      /* The stat tree has been disposed, abort mission. */
      return;
    }

    Map<String, Long> map = eventsPerType;
    String name = fJobTrace.getName();

    /**
     *
     *
     * <pre>
     * "Global", "partial", "total", etc., it's all very confusing...
     *
     * The base view shows the total count for the trace and for
     * each even types, organized in columns like this:
     *
     *                   |  Global  |  Time range |
     * trace name        |    A     |      B      |
     *    Event Type     |          |             |
     *       <event 1>   |    C     |      D      |
     *       <event 2>   |   ...    |     ...     |
     *         ...       |          |             |
     *
     * Here, we called the cells like this:
     *  A : GlobalTotal
     *  B : TimeRangeTotal
     *  C : GlobalTypeCount(s)
     *  D : TimeRangeTypeCount(s)
     * </pre>
     */

    /* Fill in an the event counts (either cells C or D) */
    for (Map.Entry<String, Long> entry : map.entrySet()) {
      statsData.setTypeCount(name, entry.getKey(), fIsGlobal, entry.getValue());
    }

    /*
     * Calculate the totals (cell A or B, depending if isGlobal). We will
     * use the results of the previous request instead of sending another
     * one.
     */
    long globalTotal = 0;
    for (long val : map.values()) {
      globalTotal += val;
    }
    /* Update both the tree model and the piechart model */
    statsData.setTotal(name, fIsGlobal, globalTotal);
    TmfPieChartStatisticsModel model = fViewer.getPieChartModel();
    if (model != null) {
      model.setPieChartTypeCount(fIsGlobal, fJobTrace, eventsPerType);
    }
    /* notify that the viewer needs to be refreshed */
    fViewer.modelComplete(fIsGlobal);
  }
  @Override
  protected IStatus run(IProgressMonitor monitor) {

    /* Wait until the analysis is ready to be queried */
    fStatsMod.waitForInitialization();
    ITmfStatistics stats = fStatsMod.getStatistics();
    if (stats == null) {
      /* It should have worked, but didn't */
      throw new IllegalStateException();
    }

    /*
     * TODO Eventually this could be exposed through the
     * TmfStateSystemAnalysisModule directly.
     */
    ITmfStateSystem ss = fStatsMod.getStateSystem(TmfStatisticsEventTypesModule.ID);
    if (ss == null) {
      /*
       * It should be instantiated after the
       * statsMod.waitForInitialization() above.
       */
      throw new IllegalStateException();
    }

    /*
     * Periodically update the statistics while they are being built (or, if
     * the back-end is already completely built, it will skip over the
     * while() immediately.
     */
    long start = 0;
    long end = 0;
    boolean finished = false;
    do {
      /* This model update is done every second */
      if (monitor.isCanceled()) {
        fViewer.removeFromJobs(fIsGlobal, fJobTrace);
        return Status.CANCEL_STATUS;
      }
      finished = ss.waitUntilBuilt(LIVE_UPDATE_DELAY);
      TmfTimeRange localtimeRange = fTimerange;
      /*
       * The generic statistics are stored in nanoseconds, so we must make
       * sure the time range is scaled correctly.
       */
      start = localtimeRange.getStartTime().normalize(0, TIME_SCALE).getValue();
      end = localtimeRange.getEndTime().normalize(0, TIME_SCALE).getValue();

      Map<String, Long> map = stats.getEventTypesInRange(start, end);
      updateStats(map);
    } while (!finished);

    /* Query one last time for the final values */
    Map<String, Long> map = stats.getEventTypesInRange(start, end);
    updateStats(map);
    fViewer.refreshPieCharts(fIsGlobal, !fIsGlobal);
    /*
     * Remove job from map so that new range selection updates can be
     * processed.
     */
    fViewer.removeFromJobs(fIsGlobal, fJobTrace);
    return Status.OK_STATUS;
  }