#ifndef _ASAP_INDEX_ITERATOR_H_ 
#define _ASAP_INDEX_ITERATOR_H_ 

#include <vector>
#include <casa/Containers/Block.h>
#include <casa/Arrays/Vector.h>
#include <casa/Arrays/Matrix.h>

#include "Scantable.h"

using namespace std ;
using namespace casa ;

namespace asap {
class IndexIterator 
{
public:
  IndexIterator( vector< vector<uInt> > &idlist ) ;
  Vector<uInt> current() ;
  Bool pastEnd() ;
  void next() ;
private:
  vector< vector<uInt> > idxlist_m ;
  uInt nfield_m ;
  Block<uInt> prod_m ;
  Block<uInt> idx_m ;
  uInt niter_m ;
  uInt maxiter_m ;
  Vector<uInt> current_m ;
} ;

class ArrayIndexIterator
{
public:
  ArrayIndexIterator( Matrix<uInt> &arr, 
                      vector< vector<uInt> > idlist=vector< vector<uInt> >() ) ;
  virtual ~ArrayIndexIterator() ;
  Vector<uInt> current() ;
  Bool pastEnd() ;
  virtual void next() = 0 ;
  virtual Vector<uInt> getRows() = 0 ;
protected:
  IndexIterator *iter_m ;
  uInt nrow_m ;
  uInt ncol_m ;
  //Vector<uInt> storage_m ;
  Matrix<uInt> arr_m ;
  //IPosition pos_m ;
} ;

class ArrayIndexIteratorNormal : public ArrayIndexIterator
{
public:
  ArrayIndexIteratorNormal( Matrix<uInt> &arr, 
                            vector< vector<uInt> > idlist=vector< vector<uInt> >() ) ;
  void next() ;
  Vector<uInt> getRows() ;
private:
  Block<uInt> storage_m ;
  IPosition pos_m ;
} ;

class ArrayIndexIteratorAcc : public ArrayIndexIterator
{
public:
  ArrayIndexIteratorAcc( Matrix<uInt> &arr, 
                         vector< vector<uInt> > idlist=vector< vector<uInt> >() ) ;
  void next() ;
  Vector<uInt> getRows() ;
private:
  Int isChanged( Vector<uInt> &idx ) ;
  uInt *updateStorage( Int &icol, uInt *base, uInt &v ) ;

  Vector<uInt> prev_m ;
  Block<uInt> storage_m ;
  IPosition pos_m ;
  Block<uInt> len_m ;
} ;

class STIdxIter
{ 
public:
  STIdxIter() ;
  STIdxIter( const string &name,
                             const vector<string> &cols ) ;
  STIdxIter( const CountedPtr<Scantable> &s,
                          const vector<string> &cols ) ; 
  virtual ~STIdxIter() ;
  vector<uInt> currentSTL() { return tovector( iter_m->current() ) ; } ;
  Vector<uInt> current() { return iter_m->current() ; } ;
  Bool pastEnd() { return iter_m->pastEnd() ; } ;
  void next() { iter_m->next() ; } ;
  vector<uInt> getRowsSTL() { return tovector( iter_m->getRows() ) ; } ;
  Vector<uInt> getRows() { return iter_m->getRows() ; } ;
protected:
  ArrayIndexIterator *iter_m ;
  virtual void init( Table &t,
                     const vector<string> &cols ) = 0 ;
private:
  vector<uInt> tovector( Vector<uInt> v ) ;
} ;

class STIdxIterNormal : public STIdxIter
{
public:
  STIdxIterNormal() ;
  STIdxIterNormal( const string &name,
                                const vector<string> &cols ) ;
  STIdxIterNormal( const CountedPtr<Scantable> &s,
                                const vector<string> &cols ) ;
  ~STIdxIterNormal() ;
protected:
  void init( Table &t,
             const vector<string> &cols ) ;
} ;

class STIdxIterAcc : public STIdxIter
{
public:
  STIdxIterAcc() ;
  STIdxIterAcc( const string &name,
                             const vector<string> &cols ) ;
  STIdxIterAcc( const CountedPtr<Scantable> &s,
                             const vector<string> &cols ) ;
  ~STIdxIterAcc() ;
protected:
  void init( Table &t,
             const vector<string> &cols ) ;
} ;

} // namespace
#endif /* _ASAP_INDEX_ITERATOR_H_ */
