#ifndef CIRBUFFARR_H
#define CIRBUFFARR_H

;  // hack (compiler difficulties)
#include <cassert>
#include <iostream>
//;  // hack (compiler difficulties)
using namespace std;

typedef unsigned int uint;
typedef unsigned int const uintc;

/*!
\brief A Circular Buffer Array 

The client pushes the new state into the current position
 by using push or they can directly write to the memory
 area themselves and increment with ++ afterwards.

popping is done by the -- operator. There is no deletion
 only a change in the pointers.  The memory is 
 allocated upfront and released when the object dies.

The copy routines allow you to save a state in another
 memory location, and restore it. Hence this class can be used
 in another way.
*/
template< typename T >
class cirbuffarr
{
  /** state points to a matrix of T. */
  T * state;
  /** Index to the current state. */
  uint current;

  cirbuffarr() 
    { assert(false); }
public:

  /** The number of states the circular buffer has. */
  uintc nstates; 

  /** The number of elements of each state. */
  uintc W;

  /** Move the current pointer forward. */
  void operator ++ ()
    { ++current; current %= nstates; }
  /** Move the current pointer back. */
  void operator -- ()
    { current += (nstates-1); current %= nstates; }

  /** Hold n states, each with W T objects. */
  cirbuffarr(uintc nstates_, uintc W_);
  /** Free memory. */
  ~cirbuffarr();

  /** Access the states, 0 is the most recent. */
  inline T * operator [] (uintc k);
  /** Access the states, 0 is the most recent. */
  inline T const * operator [] (uintc k) const;

  /** Copy array x to the current state. */
  template< typename Z >
  void operator = ( Z const & x );

  /** Copy the i'th state to array x. */
  template< typename Z >
  void copyto( Z & x, uintc i=0 ) const;

  /** Push array x into the front. */
  template< typename Z >
  void push( Z const & x );

  /** Duplicate the current state. */
  void dup();

  /** Print the circular buffer from first to last states. */
  ostream & print(ostream & os) const;

};

template< typename T >
ostream & operator << (ostream & os, cirbuffarr<T> const & cir)
  { return cir.print(os); }


// ---------------------------------------------------------
// Implementation

template< typename T >
ostream & cirbuffarr<T>::print(ostream & os) const
{
  T const * s;
  uint i;
  uint k;
  for (i=0; i<nstates; ++i)
  {
    s = operator[](i); 
    os << i << ": ";
    for (k=0; k<W; ++k)
      os << s[k] << " ";
    os << endl;
  }

  return os;
}


template< typename T >
void cirbuffarr<T>::dup()
{
  T * prev = operator[](0); //accessState();
  push(prev);
}

template< typename T >
template< typename Z >
void cirbuffarr<T>::operator = ( Z const & x )
{
  T * c = operator[](0); //accessState(); 
  
  for (uint i=0; i<W; ++i)
    c[i] = x[i];
}

template< typename T >
template< typename Z >
void cirbuffarr<T>::push( Z const & x )
{
  operator ++();
  *this = x;
}

template< typename T >
template< typename Z >
void cirbuffarr<T>::copyto( Z & x, uintc i ) const
{
  T const * c = operator[](i);
  
  for (uint i=0; i<W; ++i)
    x[i] = c[i];
}

template< typename T >
T * cirbuffarr<T>::operator [] (uintc k)
{
  assert(k<nstates);
  assert(nstates!=0);
  return state + ((current+(nstates-k))%nstates)*W;
}

template< typename T >
T const * cirbuffarr<T>::operator [] (uintc k) const
{
  //assert(k<nstates);
  assert(nstates!=0);
  return state + ((current+(nstates-k))%nstates)*W;
}

template< typename T >
cirbuffarr<T>::cirbuffarr(uintc nstates_, uintc W_)
  : nstates(nstates_), W(W_)
{
  assert(nstates>0);
  current=0;
  state = new T[nstates*W];
}

template< typename T >
cirbuffarr<T>::~cirbuffarr()
{
  delete[] state;
  state = 0;
}


#endif


