/*
 * Copyright 2000-2015 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intellij.util;

import gnu.trove.TIntArrayList;
import org.jetbrains.annotations.NotNull;

public class PausesStat {
  private static final int N_MAX = 200000;
  private final TIntArrayList pauses = new TIntArrayList();
  private final long epochStart;
  @NotNull private final String myName;
  private volatile boolean started;
  private int maxDuration;
  private Object maxDurationDescription;
  private int totalNumberRecorded;

  public PausesStat(@NotNull String name) {
    myName = name;
    epochStart = System.currentTimeMillis();
  }

  private int register() {
    int stamp = (int)(System.currentTimeMillis() - epochStart);
    pauses.add(stamp);
    return stamp;
  }

  public void started() {
    assert !started;
    if (pauses.size() > N_MAX) {
      // guard against OOME
      int toDelete = N_MAX / 2;
      assert toDelete % 2 == 0 : toDelete;
      pauses.remove(0, toDelete);
      maxDuration = 0;
    }
    register();
    started = true;
  }

  public void finished(@NotNull String description) {
    assert started;
    int startStamp = pauses.get(pauses.size() - 1);
    int finishStamp = register();
    int duration = finishStamp - startStamp;
    started = false;
    if (duration > maxDuration) {
      maxDuration = duration;
      maxDurationDescription = description;
    }
    totalNumberRecorded++;
  }

  public String statistics() {
    int total = 0;
    int number = pauses.size() / 2;
    int[] duration = new int[number];
    for (int i = 0; i < number*2; i+=2) {
      int start = pauses.get(i);
      int finish = pauses.get(i+1);
      int thisDuration = finish - start;
      total += thisDuration;
      duration[i / 2] = thisDuration;
    }

    return myName + " Statistics:" +
           "\nTotal number:     " + number + (totalNumberRecorded == number ? "" : " (Total number recorded: "+totalNumberRecorded+")") +
           "\nTotal time spent: " + total + "ms" +
           "\nAverage duration: " + (number == 0 ? 0 : total / number) + "ms" +
           "\nMedian  duration: " + ArrayUtil.averageAmongMedians(duration, 3) + "ms" +
           "\nMax  duration:    " + maxDuration + "ms (it was '"+maxDurationDescription+"')";
  }
}

@@ -1037,16 +1037,119 @@
 ecorded;
+%0A  private int indexToOverwrite; // used when pauses.size() == N_MAX and we have to overflow cyclically
 %0A%0A  publ
@@ -1350,101 +1350,8 @@
 t);%0A
-    pauses.add(stamp);%0A    return stamp;%0A  %7D%0A%0A  public void started() %7B%0A    assert !started;%0A
     
@@ -1367,18 +1367,21 @@
 s.size()
- %3E
+/2 ==
  N_MAX) 
@@ -1392,167 +1392,219 @@
     
-// guard against OOME%0A      int toDelete =
+pauses.set(indexToOverwrite, stamp);%0A      indexToOverwrite = (indexToOverwrite + 1) %25
  N_MAX
- / 2
 ;%0A    
-  assert toDelete %25 2 == 0 : toDelete;%0A      pauses.remove(0, toDelete);%0A      maxDuration = 0;%0A    %7D
+%7D%0A    else %7B%0A      pauses.add(stamp);%0A    %7D%0A    return stamp;%0A  %7D%0A%0A  public void started() %7B%0A    assert !started;
 %0A   
@@ -1760,16 +1760,64 @@
 s.size()
+/2 == N_MAX ? indexToOverwrite-1 : pauses.size()
  - 1);%0A 
@@ -2447,55 +2447,9 @@
 tics
-:%22 +%0A           %22%5CnTotal number:     %22 + number
+%22
  + (
@@ -2492,20 +2492,42 @@
  %22 (
-T
+%22+t
 otal
- n
+N
 umber
+Recorded+%22 events was
  rec
@@ -2535,36 +2535,112 @@
 rded
-: %22+
+ in 
 total
-NumberRecorded+%22)%22)
+, but only last %22+number+%22 are reported here)%22)+%22:%22+%0A           %22%5CnEvent number:     %22 + number
  +%0A 

handle overflow more gracefully