/**
   * Keep track, collect and update the stats of all the <tt>MediaStreamStats</tt> this
   * <tt>HammerStats</tt> handles.
   *
   * <p>Also write the results in the stats files.
   */
  public void run() {
    PrintWriter writer = null;
    StringBuilder allBldr = new StringBuilder();
    String delim;
    String delim_ = "";
    synchronized (this) {
      threadStop = false;
    }

    logger.info("Running the main loop");
    System.out.println("Inside HammerStats run method.\n");

    while (!threadStop) {
      synchronized (this) {
        if (overallStatsLogging || allStatsLogging || summaryStatsLogging) {
          if (allStatsLogging || summaryStatsLogging) {
            if (writer == null) {
              try {
                writer = new PrintWriter(allStatsFile, "UTF-8");
                writer.print("[\n");
              } catch (FileNotFoundException e) {
                logger.fatal("HammerStats stopping due to FileNotFound", e);
                stop();
              } catch (UnsupportedEncodingException e) {
                logger.fatal("HammerStats stopping due to " + "UnsupportedEncoding", e);
              }
            }

            // Clear the StringBuilder
            allBldr.setLength(0);

            writer.print(delim_ + '\n');
            delim_ = ",";
            writer.print("{\n");
            writer.print("  \"timestamp\":" + System.currentTimeMillis() + ",\n");
          }

          delim = "";
          logger.info("Updating the MediaStreamStats");
          for (FakeUserStats stats : fakeUserStatsList) {
            // We update the stats before using/reading them.
            stats.updateStats();
          }

          for (FakeUserStats stats : fakeUserStatsList) {
            if (allStatsLogging) {
              allBldr.append(delim + stats.getStatsJSON(2) + '\n');
              delim = ",";
            }

            if (summaryStatsLogging || overallStatsLogging) {
              logger.info(
                  "Adding stats values from the"
                      + " MediaStreamStats to their"
                      + " HammerSummaryStats objects");
              audioSummaryStats.add(stats.getMediaStreamStats(MediaType.AUDIO));
              videoSummaryStats.add(stats.getMediaStreamStats(MediaType.VIDEO));
            }
          }

          if (allStatsLogging) {
            logger.info("Writing all stats to file");
            writer.print("  \"users\":\n");
            writer.print("  [\n");
            writer.print(allBldr.toString());
            writer.print("  ]");
            if (summaryStatsLogging) writer.print(',');
            writer.print('\n');
          }
          if (summaryStatsLogging) {
            logger.info("Writing summary stats to file");
            writer.print("  \"summary\":\n");
            writer.print("  {\n");

            writer.print("    \"max\":\n");
            writer.print("    {\n");
            writer.print("        \"audio\":");
            writer.print(audioSummaryStats.getMaxJSON() + ",\n");
            writer.print("        \"video\":");
            writer.print(videoSummaryStats.getMaxJSON() + '\n');
            writer.print("    },\n");

            writer.print("    \"mean\":\n");
            writer.print("    {\n");
            writer.print("       \"audio\":");
            writer.print(audioSummaryStats.getMeanJSON() + ",\n");
            writer.print("        \"video\":");
            writer.print(videoSummaryStats.getMeanJSON() + '\n');
            writer.print("    },\n");

            writer.print("    \"min\":\n");
            writer.print("    {\n");
            writer.print("        \"audio\":");
            writer.print(audioSummaryStats.getMinJSON() + ",\n");
            writer.print("        \"video\":");
            writer.print(videoSummaryStats.getMinJSON() + '\n');
            writer.print("    },\n");

            writer.print("    \"standard_deviation\":\n");
            writer.print("    {\n");
            writer.print("        \"audio\":");
            writer.print(audioSummaryStats.getStandardDeviationJSON() + ",\n");
            writer.print("        \"video\":");
            writer.print(videoSummaryStats.getStandardDeviationJSON() + '\n');
            writer.print("    }\n");

            writer.print("  }\n");
          }
          if (allStatsLogging || summaryStatsLogging) {
            writer.append("}");
            writer.flush();
          }
        }

        if (summaryStatsLogging || overallStatsLogging) {
          logger.info(
              "Clearing the HammerSummaryStats by creating new"
                  + " SummaryStats objects for each watched stats");
          audioSummaryStats.clear();
          videoSummaryStats.clear();
        }
      }

      try {
        Thread.sleep(timeBetweenUpdate * 1000);
      } catch (InterruptedException e) {
        logger.fatal("Error during sleep in main loop : " + e);
        stop();
      }
    }
    logger.info("Exiting the main loop");

    if (writer != null) {
      writer.print("]\n");
      writer.close();
    }

    if (overallStatsLogging) writeOverallStats();
  }
  /**
   * Create and return the String that contains the overall stats (in JSON).
   *
   * @return the String that contains the overall stats.
   */
  protected String getOverallStatsJSON() {
    StringBuilder bldr = new StringBuilder();
    bldr.append("{\n");

    bldr.append("  \"max\":\n");
    bldr.append("  {\n");
    bldr.append("      \"audio\":");
    bldr.append(audioSummaryStats.getAggregateMaxJSON() + ",\n");
    bldr.append("      \"video\":");
    bldr.append(videoSummaryStats.getAggregateMaxJSON() + '\n');
    bldr.append("  },\n");

    bldr.append("  \"mean\":\n");
    bldr.append("  {\n");
    bldr.append("     \"audio\":");
    bldr.append(audioSummaryStats.getAggregateMeanJSON() + ",\n");
    bldr.append("      \"video\":");
    bldr.append(videoSummaryStats.getAggregateMeanJSON() + '\n');
    bldr.append("  },\n");

    bldr.append("  \"min\":\n");
    bldr.append("  {\n");
    bldr.append("      \"audio\":");
    bldr.append(audioSummaryStats.getAggregateMinJSON() + ",\n");
    bldr.append("      \"video\":");
    bldr.append(videoSummaryStats.getAggregateMinJSON() + '\n');
    bldr.append("  },\n");

    bldr.append("  \"standard_deviation\":\n");
    bldr.append("  {\n");
    bldr.append("      \"audio\":");
    bldr.append(audioSummaryStats.getAggregateStandardDeviationJSON() + ",\n");
    bldr.append("      \"video\":");
    bldr.append(videoSummaryStats.getAggregateStandardDeviationJSON() + '\n');
    bldr.append("  },\n");

    bldr.append("  \"sum\":\n");
    bldr.append("  {\n");
    bldr.append("      \"audio\":");
    bldr.append(audioSummaryStats.getAggregateSumJSON() + ",\n");
    bldr.append("      \"video\":");
    bldr.append(videoSummaryStats.getAggregateSumJSON() + '\n');
    bldr.append("  }\n");

    bldr.append("}\n");
    return bldr.toString();
  }