/*
 *  Copyright (c) 2012 Malhar, Inc.
 *  All Rights Reserved.
 */
package com.malhartech.util;

/**
 *
 * @author Chetan Narsude <chetan@malhar-inc.com>
 */
import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.util.Collection;

/**
 * Provides a circular buffer<p>
 * <br>
 *
 */
public class CircularBuffer<T>
{
  private static final BufferUnderflowException underflow = new BufferUnderflowException();
  private static final BufferOverflowException overflow = new BufferOverflowException();
  private T[] buffer;
  private volatile int tail;
  private volatile int head;

  @SuppressWarnings("unchecked")
  /**
   *
   * Constructing a circular buffer of 'n' integers<p>
   * <br>
   *
   * @param n size of the buffer to be constructed
   * <br>
   */
  public CircularBuffer(int n)
  {
    buffer = (T[])new Object[n];
    tail = 0;
    head = 0;
  }

  /**
   *
   * Add object at the head<p>
   * <br>
   *
   * @param toAdd object to be added
   *
   */
  public void add(T toAdd)
  {
    if (head - tail == buffer.length) {
      throw overflow;
    }
    else {
      buffer[head++ % buffer.length] = toAdd;
    }
  }

  /**
   *
   * Get object from the tail<p>
   * <br>
   *
   * @return object removed from the buffer returned
   * <br>
   */
  public T get()
  {
    if (head > tail) {
      return buffer[tail++ % buffer.length];
    }

    throw underflow;
  }

  public T peek()
  {
    if (head > tail) {
      return buffer[tail % buffer.length];
    }

    return null;
  }

  /**
   *
   * Number of objects in the buffer<p>
   * <br>
   *
   * @return Number of objects in the buffer
   * <br>
   */
  public final int size()
  {
    return head - tail;
  }

  /**
   *
   * Total design capacity of the buffer<p>
   * <br>
   *
   * @return Total return capacity of the buffer
   * <br>
   */
  public int capacity()
  {
    return buffer.length;
  }

  /**
   *
   * Drain the buffer<p>
   * <br>
   *
   * @param container {@link java.util.Collection} class to which the buffer objects are added
   * @return Number of objects removed from the buffer
   * <br>
   */
  public int drainTo(Collection<? super T> container)
  {
    int size = size();

    while (tail < head) {
      container.add(buffer[tail++ % buffer.length]);
    }

    return size;
  }

  /**
   *
   * Printing status for debugging<p>
   * <br>
   *
   * @return String containing capacity, head, and tail
   * <br>
   */
  @Override
  public String toString()
  {
    return "CircularBuffer(capacity=" + buffer.length + ", head=" + head + ", tail=" + tail + ")";
  }
}

@@ -553,16 +553,47 @@
 buffer;%0A
+  private final int bufferlen;%0A
   privat
@@ -646,41 +646,38 @@
 ad;%0A
-%0A
   
-@SuppressWarnings(%22unchecked%22)
+private volatile int count;%0A
 %0A  /
@@ -813,32 +813,65 @@
    * %3Cbr%3E%0A   */%0A
+  @SuppressWarnings(%22unchecked%22)%0A
   public Circula
@@ -930,30 +930,21 @@
     
-tail = 0;%0A    head = 0
+bufferlen = n
 ;%0A  
@@ -1090,27 +1090,21 @@
     if (
-head - tail
+count
  == buff
@@ -1105,23 +1105,19 @@
 = buffer
-.
 len
-gth
 ) %7B%0A    
@@ -1144,21 +1144,9 @@
   %7D%0A
-    else %7B%0A  
+%0A
     
@@ -1167,23 +1167,19 @@
 %25 buffer
-.
 len
-gth
 %5D = toAd
@@ -1185,17 +1185,24 @@
 dd;%0A    
-%7D
+count++;
 %0A  %7D%0A%0A  
@@ -1352,38 +1352,51 @@
   %7B%0A    if (
-head %3E tail) %7B
+count %3E 0) %7B%0A      count--;
 %0A      retur
@@ -1411,39 +1411,35 @@
 %5Btail++ %25 buffer
-.
 len
-gth
 %5D;%0A    %7D%0A%0A    th
@@ -1492,19 +1492,17 @@
 if (
-head %3E tail
+count %3E 0
 ) %7B%0A
@@ -1534,23 +1534,19 @@
 %25 buffer
-.
 len
-gth
 %5D;%0A    %7D
@@ -1741,19 +1741,13 @@
 urn 
-head - tail
+count
 ;%0A  
@@ -1929,23 +1929,19 @@
 n buffer
-.
 len
-gth
 ;%0A  %7D%0A%0A 
@@ -2253,19 +2253,19 @@
 le (
-tail %3C head
+count-- %3E 0
 ) %7B%0A
@@ -2306,23 +2306,19 @@
 %25 buffer
-.
 len
-gth
 %5D);%0A    
@@ -2571,15 +2571,32 @@
 ffer
-.
 len
-gth
+ + %22, count=%22 + count
  + %22

use a counter to keep track of number of objects in the buffer.