// Path: src/main/java/io/rainfall/statistics/StatisticsHolder.java
// public abstract class StatisticsHolder<E extends Enum<E>> {
// 
//   public abstract Enum<E>[] getResultsReported();
// 
//   public abstract Set<String> getStatisticsKeys();
// 
//   public abstract Statistics<E> getStatistics(String name);
// 
//   public abstract Set<StatisticsCollector> getStatisticsCollectors();
// 
//   public abstract Histogram fetchHistogram(final Enum<E> result);
// 
//   public abstract void reset();
// 
//   public abstract long getCurrentTps(Enum result);
// 
//   public abstract void record(String name, long responseTimeInNs, Enum result);
// 
//   public abstract void increaseAssertionsErrorsCount(String name);
// 
//   public abstract void pause();
// 
//   public abstract void resume();
// 
//   public long getTimeInNs() {
//     return System.nanoTime();
//   }
// 
//   public abstract long getStartTime();
// }
// 
// Path: src/main/java/io/rainfall/statistics/StatisticsPeekHolder.java
// public class StatisticsPeekHolder<E extends Enum<E>> {
//   public final static String ALL = "ALL";
//   private final Enum<E>[] resultsReported;
//   private final ConcurrentHashMap<String, LongAdder> assertionsErrors;
//   private final RainfallHistogramSink<E> histograms;
//   private final long startTime;
// 
//   private Map<String, StatisticsPeek<E>> statisticsPeeks = new ConcurrentHashMap<String, StatisticsPeek<E>>();
//   private Map<String, Exporter> extraCollectedStatistics = new ConcurrentHashMap<String, Exporter>();
//   private StatisticsPeek<E> totalStatisticsPeeks = null;
//   private long timestamp;
// 
//   public StatisticsPeekHolder(final Enum<E>[] resultsReported, final Map<String, Statistics<E>> statisticsMap,
//                               final Set<StatisticsCollector> statisticsCollectors,
//                               final ConcurrentHashMap<String, LongAdder> assertionsErrors, RainfallHistogramSink<E> histograms,
//                               long startTime) {
//     this.resultsReported = resultsReported;
//     this.assertionsErrors = assertionsErrors;
//     this.histograms = histograms;
//     this.startTime = startTime;
//     this.timestamp = System.currentTimeMillis();
//     for (String name : statisticsMap.keySet()) {
//       statisticsPeeks.put(name, statisticsMap.get(name).peek(timestamp));
//     }
//     this.totalStatisticsPeeks = new StatisticsPeek<E>(ALL, this.resultsReported, this.timestamp);
//     totalStatisticsPeeks.addAll(statisticsPeeks);
// 
//     for (StatisticsCollector statisticsCollector : statisticsCollectors) {
//       extraCollectedStatistics.put(statisticsCollector.getName(), statisticsCollector.peek());
//     }
//   }
// 
//   public StatisticsPeek<E> getStatisticsPeeks(String name) {
//     return statisticsPeeks.get(name);
//   }
// 
//   public Long getAssertionsErrorsCount(String name) {return assertionsErrors.get(name).longValue();}
// 
//   public Set<String> getStatisticsPeeksNames() {
//     return statisticsPeeks.keySet();
//   }
// 
//   public StatisticsPeek<E> getTotalStatisticsPeeks() {
//     return totalStatisticsPeeks;
//   }
// 
//   public long getTimestamp() {
//     return timestamp;
//   }
// 
//   public long getStartTime() {
//     return startTime;
//   }
// 
//   public Enum<E>[] getResultsReported() {
//     return resultsReported;
//   }
// 
//   public Map<String, Exporter> getExtraCollectedStatistics() {
//     return extraCollectedStatistics;
//   }
// 
//   public Long getTotalAssertionsErrorsCount() {
//     Long totalAssertionsErrorsCount = 0L;
//     for (LongAdder count : assertionsErrors.values()) {
//       totalAssertionsErrorsCount += count.longValue();
//     }
//     return totalAssertionsErrorsCount;
//   }
// 
//   public Histogram fetchHistogram(final Enum<E> result) {
//     return histograms.fetchHistogram(result);
//   }
// 
// }
// 
// Path: src/main/java/io/rainfall/utils/CompressionUtils.java
// public static String cleanFilename(String filename) {
//   Arrays.sort(illegalChars);
//   StringBuilder cleanName = new StringBuilder();
//   for (int i = 0; i < filename.length(); i++) {
//     int c = (int)filename.charAt(i);
//     if (Arrays.binarySearch(illegalChars, c) < 0) {
//       cleanName.append((char)c);
//     }
//   }
//   return cleanName.toString();
// }


import io.rainfall.statistics.StatisticsHolder;
import io.rainfall.statistics.StatisticsPeekHolder;
import org.HdrHistogram.Histogram;
import org.HdrHistogram.HistogramLogWriter;
import java.io.File;
import java.io.PrintStream;
import java.util.List;
import static io.rainfall.utils.CompressionUtils.cleanFilename;
  public void summarize(final StatisticsHolder<E> statisticsHolder) {
    // dump raw histograms as hlog files
    long startTime = statisticsHolder.getStartTime(); // ManagementFactory.getRuntimeMXBean().getStartTime();

    long endTime = System.currentTimeMillis();
    try {
      Enum<E>[] results = statisticsHolder.getResultsReported();
      for (Enum<E> result : results) {
        Histogram rawHistogram = statisticsHolder.fetchHistogram(result);
        rawHistogram.setStartTimeStamp(startTime);
        rawHistogram.setEndTimeStamp(endTime);

        File hlogFile = new File(this.basedir + File.separatorChar + buildHlogFilename(result.name()));
        hlogFile.getParentFile().mkdirs();
        HistogramLogWriter writer = new HistogramLogWriter(new PrintStream(hlogFile));
        writer.setBaseTime(startTime);

        writer.outputLogFormatVersion();
        writer.outputBaseTime(writer.getBaseTime());
        writer.outputLegend();
        writer.outputIntervalHistogram(rawHistogram);

        writer.close();
      }
    } catch (Exception e) {
      throw new RuntimeException("Can not report to hlog", e);
    }
  }

  private String buildHlogFilename(String result) {
// Path: src/main/java/io/rainfall/statistics/StatisticsHolder.java
// public abstract class StatisticsHolder<E extends Enum<E>> {
// 
//   public abstract Enum<E>[] getResultsReported();
// 
//   public abstract Set<String> getStatisticsKeys();
// 
//   public abstract Statistics<E> getStatistics(String name);
// 
//   public abstract Set<StatisticsCollector> getStatisticsCollectors();
// 
//   public abstract Histogram fetchHistogram(final Enum<E> result);
// 
//   public abstract void reset();
// 
//   public abstract long getCurrentTps(Enum result);
// 
//   public abstract void record(String name, long responseTimeInNs, Enum result);
// 
//   public abstract void increaseAssertionsErrorsCount(String name);
// 
//   public abstract void pause();
// 
//   public abstract void resume();
// 
//   public long getTimeInNs() {
//     return System.nanoTime();
//   }
// 
//   public abstract long getStartTime();
// }
// 
// Path: src/main/java/io/rainfall/statistics/StatisticsPeekHolder.java
// public class StatisticsPeekHolder<E extends Enum<E>> {
//   public final static String ALL = "ALL";
//   private final Enum<E>[] resultsReported;
//   private final ConcurrentHashMap<String, LongAdder> assertionsErrors;
//   private final RainfallHistogramSink<E> histograms;
//   private final long startTime;
// 
//   private Map<String, StatisticsPeek<E>> statisticsPeeks = new ConcurrentHashMap<String, StatisticsPeek<E>>();
//   private Map<String, Exporter> extraCollectedStatistics = new ConcurrentHashMap<String, Exporter>();
//   private StatisticsPeek<E> totalStatisticsPeeks = null;
//   private long timestamp;
// 
//   public StatisticsPeekHolder(final Enum<E>[] resultsReported, final Map<String, Statistics<E>> statisticsMap,
//                               final Set<StatisticsCollector> statisticsCollectors,
//                               final ConcurrentHashMap<String, LongAdder> assertionsErrors, RainfallHistogramSink<E> histograms,
//                               long startTime) {
//     this.resultsReported = resultsReported;
//     this.assertionsErrors = assertionsErrors;
//     this.histograms = histograms;
//     this.startTime = startTime;
//     this.timestamp = System.currentTimeMillis();
//     for (String name : statisticsMap.keySet()) {
//       statisticsPeeks.put(name, statisticsMap.get(name).peek(timestamp));
//     }
//     this.totalStatisticsPeeks = new StatisticsPeek<E>(ALL, this.resultsReported, this.timestamp);
//     totalStatisticsPeeks.addAll(statisticsPeeks);
// 
//     for (StatisticsCollector statisticsCollector : statisticsCollectors) {
//       extraCollectedStatistics.put(statisticsCollector.getName(), statisticsCollector.peek());
//     }
//   }
// 
//   public StatisticsPeek<E> getStatisticsPeeks(String name) {
//     return statisticsPeeks.get(name);
//   }
// 
//   public Long getAssertionsErrorsCount(String name) {return assertionsErrors.get(name).longValue();}
// 
//   public Set<String> getStatisticsPeeksNames() {
//     return statisticsPeeks.keySet();
//   }
// 
//   public StatisticsPeek<E> getTotalStatisticsPeeks() {
//     return totalStatisticsPeeks;
//   }
// 
//   public long getTimestamp() {
//     return timestamp;
//   }
// 
//   public long getStartTime() {
//     return startTime;
//   }
// 
//   public Enum<E>[] getResultsReported() {
//     return resultsReported;
//   }
// 
//   public Map<String, Exporter> getExtraCollectedStatistics() {
//     return extraCollectedStatistics;
//   }
// 
//   public Long getTotalAssertionsErrorsCount() {
//     Long totalAssertionsErrorsCount = 0L;
//     for (LongAdder count : assertionsErrors.values()) {
//       totalAssertionsErrorsCount += count.longValue();
//     }
//     return totalAssertionsErrorsCount;
//   }
// 
//   public Histogram fetchHistogram(final Enum<E> result) {
//     return histograms.fetchHistogram(result);
//   }
// 
// }
// 
// Path: src/main/java/io/rainfall/utils/CompressionUtils.java
// public static String cleanFilename(String filename) {
//   Arrays.sort(illegalChars);
//   StringBuilder cleanName = new StringBuilder();
//   for (int i = 0; i < filename.length(); i++) {
//     int c = (int)filename.charAt(i);
//     if (Arrays.binarySearch(illegalChars, c) < 0) {
//       cleanName.append((char)c);
//     }
//   }
//   return cleanName.toString();
// }


// Path: src/main/java/io/rainfall/reporting/HlogReporter.java
import io.rainfall.statistics.StatisticsHolder;
import io.rainfall.statistics.StatisticsPeekHolder;
import org.HdrHistogram.Histogram;
import org.HdrHistogram.HistogramLogWriter;
import java.io.File;
import java.io.PrintStream;
import java.util.List;
import static io.rainfall.utils.CompressionUtils.cleanFilename;

  public void summarize(final StatisticsHolder<E> statisticsHolder) {
    // dump raw histograms as hlog files
    long startTime = statisticsHolder.getStartTime(); // ManagementFactory.getRuntimeMXBean().getStartTime();

    long endTime = System.currentTimeMillis();
    try {
      Enum<E>[] results = statisticsHolder.getResultsReported();
      for (Enum<E> result : results) {
        Histogram rawHistogram = statisticsHolder.fetchHistogram(result);
        rawHistogram.setStartTimeStamp(startTime);
        rawHistogram.setEndTimeStamp(endTime);

        File hlogFile = new File(this.basedir + File.separatorChar + buildHlogFilename(result.name()));
        hlogFile.getParentFile().mkdirs();
        HistogramLogWriter writer = new HistogramLogWriter(new PrintStream(hlogFile));
        writer.setBaseTime(startTime);

        writer.outputLogFormatVersion();
        writer.outputBaseTime(writer.getBaseTime());
        writer.outputLegend();
        writer.outputIntervalHistogram(rawHistogram);

        writer.close();
      }
    } catch (Exception e) {
      throw new RuntimeException("Can not report to hlog", e);
    }
  }

  private String buildHlogFilename(String result) {
    return cleanFilename(result) + ".hlog";