#ifndef PRINT_H
#define PRINT_H

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

#include <typedefs.h>

/*!
\brief General printing with iterators.

Global functions forward the printing to this class as they
 are the interface and this is the back end.

\par Example
\verbatim
#include <print.h>
...
  vector<double> v; ...
  cout << print(v,"\n") << endl;
\endverbatim

\par Example
\verbatim
#include <print.h>
...
  double a1[] = { 2.0, 4.0, 6.0, 8.0, 10.0 };
  cout << print(a1,a1+5) << endl;
\endverbatim
*/
template< typename Iter >
class printcontainer
{
public:

  /** The start iterator. */
  Iter ibeg;
  /** The end iterator. */
  Iter iend;

  /** The client can configure the space between elements. */
  string space;

  /** Pass in the container with its iterators. */
  printcontainer
  (
    Iter ibeg_,
    Iter iend_,
    stringc & space_=" "
  )
    : ibeg(ibeg_), iend(iend_), space(space_) {}

  /** The vector prints each sequential element and a space. */
  ostream & print(ostream & os) const;
};

/** Print a STL container. */
template< typename T >
printcontainer< typename T::const_iterator > 
  print( T const & data, stringc & space=" " )
  { return typename printcontainer< typename T::const_iterator >::printcontainer(data.begin(),data.end(),space); }

/** Print an iterated container. */
template< typename Iter >
printcontainer< Iter >
  print( Iter ibeg, Iter iend, stringc & space=" " )
  { return typename printcontainer< Iter >::printcontainer(ibeg,iend,space); }

/** The client can use print to generate a 
    printcontainer to do the printing. */
template< typename T >
ostream & operator << (ostream & os, printcontainer<T> const & x )
  { return x.print(os); }

template< typename Iter >
printcontainer< Iter > printvecfunc
( 
  Iter ibeg, 
  long unsigned int const N,
  stringc & space=" " 
)
{
  return print(ibeg,ibeg+N,space);
}

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


template< typename Iter >
ostream & printcontainer<Iter>::print(ostream & os) const
{
  Iter i=ibeg;
  if (i!=iend)
    os << *i++;
  for ( ; i!=iend; )
    os << space << *i++;

  return os;
}


#endif


