#ifndef FUNCSTATE_H
#define FUNCSTATE_H

#include <cassert>
#include <deque>
using namespace std;

#include <typedefs.h>

/*!
\brief Function with state.

The structure of the state xi includes one extra dimension -
 the functions value, so passing this function around also
 passes the states value.
*/
template< typename X >
class funcstate
{
public:

  /** To count function evaluations. */
  uint counter;

  /** Dimension. */
  uint dim;
  
  /** Function arguments and function value, dim+1 in length. */
  X* xi;

  /** Bad state. */
  funcstate()
    : counter(0), dim(0), xi(0), mem(false) {}

  /** Default allocates memory for state. */
  funcstate(uintc dim_, boolc mem_=true);

  /** Evaluate the function and store in xi[dim]. */
  virtual X const operator()() = 0;
 
  /** Free memory if allocated. */
  virtual ~funcstate();

  /** Is the memory managed? */
  bool mem;

  /** Initialize xi[0..n-1]. */
  void set_position(X* xi_);
  /** dim+1 vector. */
  void set_positionvalue(X* xi_);
  /** Get the last calculated function value. */
  X const fnvalue()
    { return xi[dim]; }
};


/*!
\brief History of function states.
*/
template< typename X >
class funchistory
{
public:

  /** Previous positions with function value as the last element. */
  deque< X* > xik;

  /** The function. */
  funcstate<X> & fs;

  /** Initialize reference. */
  funchistory(funcstate<X> & fs_)
    : fs(fs_) {}
  /** Free memory if allocated. */
  ~funchistory();

  /** Access position states. */
  X* operator [] (uintc i)
    { assert(i<xik.size()); return xik[i]; }

  /** Save current position. */
  void push();

  /** Read then delete front of xik stack into the
      current position. */
  void pop();

  /** Copy the front of xik stack to the current position. */ 
  void restore();

  /** Removes the last position stack element. */
  void del_back();

};


// template wrappers to create inherited classes of funcstate.

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

template< typename X >
funcstate<X>::funcstate(uintc dim_, boolc mem_)
  : counter(0), dim(dim_), mem(mem_)
{
  if (mem==true)
  {
    assert(dim!=0);
    xi = new X[dim+1];
  }
}

template< typename X >
void funcstate<X>::set_position(X* xi_)
{
  for (uint i=0; i<dim; ++i)
    xi[i] = xi_[i];
}

template< typename X >
void funcstate<X>::set_positionvalue(X* xi_)
{
  for (uint i=0; i<=dim; ++i)
    xi[i] = xi_[i];
}

template< typename X >
funcstate<X>::~funcstate()
{
  if (mem)
    delete[] xi;
  xi=0;  
}

template< typename X >
void funchistory<X>::push()
{
  X* x= new X[fs.dim+1];
  for (uint i=0; i<=fs.dim; ++i)
    x[i] = fs.xi[i];

  xik.push_front(x);
}
  
template< typename X >
void funchistory<X>::pop()
{
  assert( xik.empty()==false);
  if (xik.empty())
    return;

  X * z = xik[0];
  fs.set_positionvalue( z );
  delete[] z;
  xik.pop_front();
}

template< typename X >
void funchistory<X>::restore()
{
  assert( xik.empty()==false);
  if (xik.empty())
    return;

  X * z = xik[0];
  fs.set_positionvalue( z );
}

template< typename X >
void funchistory<X>::del_back()
{
  if (xik.empty())
    return;

  X * z = xik.back();
  xik.pop_back();
  delete[] z; 
}

template< typename X >
funchistory<X>::~funchistory()
{
  for (uint i=0; i<xik.size(); ++i)
    delete[] xik[i];
  xik.clear();
}

#endif



