content: package org.altbeacon.beacon.service;
  
  import org.altbeacon.beacon.Beacon;
  import org.altbeacon.beacon.logging.LogManager;
  
  import java.text.SimpleDateFormat;
  import java.util.ArrayList;
  import java.util.Date;
  
  /**
   * Stats module used for internal performance testing of the library
   * Created by dyoung on 10/16/14.
   */
  public class Stats {
      private static final Stats INSTANCE = new Stats();
      private static final String TAG = "Stats";
  
      /**
       * Synchronize all usage as this is not a thread safe class.
       */
      private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("HH:mm:ss.SSS");
  
      private ArrayList<Sample> mSamples;
      private long mSampleIntervalMillis;
      private boolean mEnableLogging;
      private boolean mEnableHistoricalLogging;
      private boolean mEnabled;
      private Sample mSample;
  
      public static Stats getInstance() {
          return INSTANCE;
      }
  
      private Stats() {
          mSampleIntervalMillis = 0l;
          clearSamples();
      }
      public ArrayList<Sample> getSamples() {
          rollSampleIfNeeded();
          return mSamples;
      }
      public void setEnabled(boolean enabled) {
          mEnabled = enabled;
      }
      public boolean isEnabled() {
          return mEnabled;
      }
      public void setLoggingEnabled(boolean enabled) {
          mEnableLogging = enabled;
      }
      public void setHistoricalLoggingEnabled(boolean enabled) {
          mEnableHistoricalLogging = enabled;
      }
      public void setSampleIntervalMillis(long interval) {
          mSampleIntervalMillis = interval;
      }
      public void log(Beacon beacon) {
          rollSampleIfNeeded();
          mSample.detectionCount++;
          if (mSample.firstDetectionTime == null) {
              mSample.firstDetectionTime = new Date();
          }
          if (mSample.lastDetectionTime != null) {
              long timeSinceLastDetection = new Date().getTime() - mSample.lastDetectionTime.getTime();
  
              if (timeSinceLastDetection > mSample.maxMillisBetweenDetections) {
                  mSample.maxMillisBetweenDetections = timeSinceLastDetection;
              }
          }
          mSample.lastDetectionTime = new Date();
      }
      public void clearSample() {
          mSample = null;
      }
  
      public void newSampleInterval() {
          Date boundaryTime = new Date();
          if (mSample != null) {
              boundaryTime = new Date(mSample.sampleStartTime.getTime()+mSampleIntervalMillis);
              mSample.sampleStopTime = boundaryTime;
              if (!mEnableHistoricalLogging && mEnableLogging) {
                  logSample(mSample, true);
              }
          }
          mSample = new Sample();
          mSample.sampleStartTime = boundaryTime;
          mSamples.add(mSample);
          if (mEnableHistoricalLogging) {
              logSamples();
          }
      }
  
      public void clearSamples() {
          mSamples = new ArrayList<Sample>();
          newSampleInterval();
      }
  
      private void logSample(Sample sample, boolean showHeader) {
          if (showHeader) {
              LogManager.d(TAG, "sample start time, sample stop time, first detection" +
                      " time, last detection time, max millis between detections, detection count");
          }
          LogManager.d(TAG, "%s, %s, %s, %s, %s, %s",
                  formattedDate(sample.sampleStartTime), formattedDate(sample.sampleStopTime),
                  formattedDate(sample.firstDetectionTime), formattedDate(sample.lastDetectionTime),
                  sample.maxMillisBetweenDetections, sample.detectionCount);
      }
  
      private String formattedDate(Date d) {
          String formattedDate = "";
          if (d != null) {
              synchronized (SIMPLE_DATE_FORMAT) {
                  formattedDate = SIMPLE_DATE_FORMAT.format(d);
              }
          }
          return formattedDate;
      }
  
      private void logSamples() {
          LogManager.d(TAG, "--- Stats for %s samples", mSamples.size());
          boolean firstPass = true;
          for (Sample sample : mSamples) {
              logSample(sample, firstPass);
              firstPass = false;
          }
      }
      private void rollSampleIfNeeded() {
          if (mSample == null || (mSampleIntervalMillis > 0 && (new Date().getTime() - mSample.sampleStartTime.getTime()) >=
                  mSampleIntervalMillis)) {
              newSampleInterval();
          }
      }
  
  
      public static class Sample {
          public long detectionCount  = 0l;
          public long maxMillisBetweenDetections;
          public Date firstDetectionTime;
          public Date lastDetectionTime;
          public Date sampleStartTime;
          public Date sampleStopTime;
      }
  }
  
  