#ifndef _psi_src_bin_psimrcc_ccindex_h
#define _psi_src_bin_psimrcc_ccindex_h

/*! \file 
    \ingroup (PSIMRCC)
    \brief   This class is used to store n-tuples of MOs indices (p,q,r,..)
*/

/***************************************************************************
 *  PSIMRCC : Copyright (C) 2007 by Francesco Evangelista and Andrew Simmonett
 *  frank@ccc.uga.edu   andysim@ccc.uga.edu
 *  A multireference coupled cluster code
 ***************************************************************************/

/*********************************************************
  CCIndex Class
  1) Purpose
    This class is used to store n-tuples of MOs indices (p,q,r,..)
  2) Use
  3) Details
    The pairs are stored according to the irreps, for example

          A1           A2          B1       B2
    ----------------------------------------------
    |(0,0),(0,1)| (4,5),(7,9)  | .......|........|
    ----------------------------------------------
  4) Uses
    MOInfo class
    STL <vector>

*********************************************************/

#include <libutil/libutil.h>
#include <vector>

extern FILE *infile, *outfile;

namespace psi{ namespace psimrcc{

/**
	@author Francesco Evangelista <frank@ccc.uga.edu>
*/

class CCIndex{
  typedef vector<int*>         pIntVec;
  typedef std::vector<size_t>  Size_tVec;
  typedef std::vector<size_t*> pSize_tVec;
public:
  ///////////////////////////////////////////////////////////////////////////////
  // Class Constructor and Destructor
  ///////////////////////////////////////////////////////////////////////////////
  CCIndex(std::string str);
  ~CCIndex();

  ///////////////////////////////////////////////////////////////////////////////
  // Class Interface
  ///////////////////////////////////////////////////////////////////////////////
  // Print routines
  void        print();
  // Get the numeber of tuples and the numeber of indices per tuple
  double      get_memory()                                {return(memory);}
  int         get_ntuples()                               {return(ntuples);}
  int         get_nelements()                             {return(nelements);}
  std::string get_label()                                 {return(label);}

  // Get the tuples
  short**     get_tuples()                                {return(tuples);}
  short*      get_tuple(int i)                            {return(tuples[i]);}

  // Get the tuples irrep structure
  int         get_first(int i)                            {return(first[i]);}
  int         get_last(int i)                             {return(last[i]);}
  int         get_pairpi(int i)                           {return(pairpi[i]);}
  Size_tVec&  get_pairpi()                                {return(pairpi);}
  Size_tVec&  get_first()                                 {return(first);}
  Size_tVec&  get_last()                                  {return(last);}

  // Given a set of number retrieve the corresponding tuple index
  size_t      get_tuple_index(short p)                    {return(one_index_to_tuple[p]);}
  size_t      get_tuple_index(short p, short q)           {return(two_index_to_tuple[p][q]);}
  size_t      get_tuple_index(short p, short q, short r)  {return(three_index_to_tuple[p][q][r]);}

  // Given a set of number retrieve the corresponding tuple irrep
  int         get_tuple_irrep(short p)                    {return(one_index_to_irrep[p]);}
  int         get_tuple_irrep(short p, short q)           {return(two_index_to_irrep[p][q]);}
  int         get_tuple_irrep(short p, short q, short r)  {return(three_index_to_irrep[p][q][r]);}

  pIntVec&    get_indices_to_pitzer()                     {return(indices_to_pitzer);}

  size_t*     get_one_index_to_tuple()                    {return(one_index_to_tuple);};
  size_t**    get_two_index_to_tuple()                    {return(two_index_to_tuple);};
  size_t***   get_three_index_to_tuple()                  {return(three_index_to_tuple);};
  int*        get_one_index_to_irrep()                    {return(one_index_to_irrep);};
  int**       get_two_index_to_irrep()                    {return(two_index_to_irrep);};
  int***      get_three_index_to_irrep()                  {return(three_index_to_irrep);};

private:
  ///////////////////////////////////////////////////////////////////////////////
  // Class private functions
  ///////////////////////////////////////////////////////////////////////////////
  void        init();
  void        cleanup();
  void        make_zero_index();
  void        make_one_index();
  void        make_two_index();
  void        make_three_index();
  ///////////////////////////////////////////////////////////////////////////////
  // Class data
  ///////////////////////////////////////////////////////////////////////////////
  // Type                           // Name
  std::string                       label;                  // The label of this object
  int                               nelements;              // Number of elements
  Size_tVec                         dimension;              // Size of the elements space
  pIntVec                           mospi;                  // Size of each irrep of the elements space
  std::vector<std::vector<int> >    first_mos;              // Last mo of each irrep of the elements space
  pIntVec                           indices_to_pitzer;      // Mapping from the mos of this space to Pitzer
  bool                              greater_than_or_equal;  // >= tuples
  bool                              greater_than;           // >  tuples
  double                            memory;                 // Memory required to store all the data
  size_t                            ntuples;                // Number of tuples
  short**                           tuples;                 // The tuples ordered as matrix : tuples[number][element]
  Size_tVec                         first;                  // First pair of irrep
  Size_tVec                         last;                   // Last  pair of irrep
  Size_tVec                         pairpi;                 // Number of pairs for irrep
  size_t*                           one_index_to_tuple;     // 1->tuple mapping array
  size_t**                          two_index_to_tuple;     // 2->tuple mapping array
  size_t***                         three_index_to_tuple;   // 3->tuple mapping array
  int*                              one_index_to_irrep;     // 1->irrep mapping array
  int**                             two_index_to_irrep;     // 2->irrep mapping array
  int***                            three_index_to_irrep;   // 3->irrep mapping array
protected:
  static int                        nirreps;
};

}} /* End Namespaces */

#endif // _psi_src_bin_psimrcc_ccindex_h
