#ifndef __SmallArray_H
#define __SmallArray_H


#include <assert.h>

template< class DataT>
/*
CLASS
    SmallArray 

    This class allows you to declare a small array of max const size. 
    Not like the ordinary c array it provides boundry checking both on 
    inserting and on requiring information from it.

KEYWORDS
    array, container, iterator

AUTHORS
  Zipi Fligelman (zipo@math.tau.ac.il).

  Copyright: SAMBA group, Tel-Aviv Univ. Israel, 1999.

CHANGES LOG
<UL>
<LI>
</UL>

GOALS
  The goals of this class is to make available a dynamically allocated array
  that has constant (not more than unsigned short) length. This class is
  STL compliance and like the vector class allows push_back operation keeping
  in mind we want pass the boundries, and iteration options on the 
  array in a safe manner.

USAGE
  Since the class is a template class one might want to use a typedef operation
  to simplify the readability of the class. This is an example for reading
  the appropriate transformation (assumed to be less then 10) to a Small Array
  of refernce frames. All these arrays are kept in their own Small Array, 
  based on from which molecule to which molecule the transformations are 
  defined. The different molecules are given identifying numbers.

  EXAMPLE
  // in this example we assume the molecule number is given
  typedef SmallArray<ReferenceFrame> TransInfo;
  typedef SmallArray<TransInfo> TransInfoArray;

  ifstream ini_file(iniFileName);
  assert(iniFileName);
  char buffer[1024];
  int i=0;
  bool found = false;
  while (!ini_file.eof()) {
    ini_file.getline(buffer,100);
      if (!(*buffer=='#')) { 
         if (strncmp(buffer, "-->TRANSFORMATIONS_START",24) == 0) { 
            found = true;
             i=0;
      }
      else if (found && i <max_trans) {
        istrstream ist(buffer,100);
        ist >> r1 >> r2 >> r3 >> t1 >> t2 >> t3;
        ReferenceFrame tmp = 
                    ReferenceFrame(RigidTrans3(Vector3(r1,r2,r3), 
                                               Vector3(t1,t2,t3)));
        trans_array[mol_number].push_back(tmp);
        ++i;
      }
  }
  END
  
  For printing this array we only need to take two iterators and go through
  the motion of printing them.
  One might notice that I used the capabilities of the operator[] though 
  they are not necessary and one might have used (*it).begin() insteand.
  
  EXAMPLE
  for (TransInfoArray::const_iterator it = trans_array.begin();
       it != trans_array.end() ; ++it) {
       s << "Transformations from mol 0 to mol " << it-trans_array.begin()+1 
         << endl;
        for(TransInfo::iterator jt=trans_array[it-trans_array.begin()].begin();
            jt != trans_array[it].end(); ++jt)
            s << *jt << endl;
        s << "--------------------------------------------------\n";
  }
  END
*/
class SmallArray
{
public:
  // GROUP: STL compliance defintions
  typedef DataT value_type;
    //// STL compliant typedef.
  typedef DataT* iterator;
  //// STL compliant typedef.
  typedef const DataT* const_iterator;
  //// STL compliant typedef.
  typedef DataT& reference;
  //// STL compliant typedef.
  typedef const DataT& const_reference;

  // GROUP: Constructors/Destructor
  
  //// Constructor receives initial space to allocate. Default is 3.
  explicit SmallArray(unsigned short size);

  //// Copy constructor
  SmallArray(const SmallArray< DataT>& sa);

  //// Destructor. Deletes vector data.
  ~SmallArray();

  

  //// Adds an item at the end of the array add to the occ and return true.
  //// Return flase if no space left
  bool push_back(const DataT& elem);
  
  // GROUP: OPERATORS
  
  //// assignment operator
  SmallArray< DataT>& operator=(const SmallArray< DataT>& sa);

  //// Returns reference to indexed element of the array.
  // checking bounds
  reference operator[](unsigned short index);

  //// Returns a const reference to indexed element of the array.
  // cheking bounds
  const_reference operator[](unsigned short index) const;

  //// Returns a pointer to the vector's head. 
  iterator begin();

  //// Returns a pointer to the vector's head. 
  const_iterator begin() const;

  //// Returns a pointer to the vector's end. The end is past the last element
  // of the vector.
  iterator end();

  //// Returns a pointer to the vector's end. The end is past the last element
  // of the vector.
  const_iterator end() const;
  
  //// This function return the current size of the array
  inline unsigned short size() const { return occ; }
  //// This function returns the maximum size of the array
  // the demand is that always size() <= max_size()
  inline unsigned short max_size() const { return sz; }
  //// This function returns the maximum size of the array
  // the demand is that always size() <= capacity()
  // we add this function to be compliant with the STL vector
  inline unsigned short capacity() const { return sz; }
  //// returns true if there are no elements in the array
  inline bool empty() { return (occ == 0) ; }
  //// returns true if there is no room left in the array
  inline bool full()  { return (occ == sz); }
protected:
  DataT *array;
  unsigned short sz;
  unsigned short occ;

private:
  static DataT* allocate(unsigned short space);
  static void copy(DataT* start, DataT* end, DataT* target);
  static void destroy(DataT* start, DataT* end);
};

template< class DataT>
DataT* SmallArray< DataT>::allocate(unsigned short space)
{
  return (DataT*)::operator new(space*sizeof(DataT));
}

template< class DataT>
void SmallArray< DataT>::copy(DataT* start, DataT* end, DataT* target)
{
  for (; start != end; ++start, ++target)
    *target = *start;
}

template< class DataT>
void SmallArray< DataT>::destroy(DataT* start, DataT* end)
{
  for (DataT* ptr=start; ptr!=end; ++ptr)
    ptr->~DataT();
  if (start)
      ::operator delete(start);
}


template< class DataT>
SmallArray< DataT>::SmallArray(unsigned short size) : sz(size), occ(0)
{
  array = allocate(sz);
}

template< class DataT>
SmallArray< DataT>::SmallArray(const SmallArray< DataT>& sa) 
{
  sz = sa.sz;
  occ = sa.occ;
  array = allocate(sz);
  copy(sa.array, sa.array+occ, array);
}

template< class DataT>
SmallArray< DataT>::~SmallArray()
{
  //// a question here shouldn't I destroy only occ 
  // don't seem like it but I might want to ask meir just in case
  destroy(array, array+occ);
}
  
template< class DataT>
SmallArray< DataT>& SmallArray< DataT>::operator=(const SmallArray< DataT>& a)
{
    if (&a != this) {
        destroy(array, array+occ);
        sz = a.sz;
        occ = a.occ;
        array = allocate(sz);
        copy(a.array, a.array+occ, array);
    }
    return *this;
}  

template< class DataT>
bool SmallArray< DataT>::push_back(const DataT& elem)
{
  if (occ>=sz)
    return false;
  array[occ] = elem;
  ++occ;
  return true;
}
   
//// An operator that given an index i returns the SmallArray[i]
// checking boundries
template< class DataT>
DataT& SmallArray< DataT>::operator[](unsigned short index)
{
  assert(index < occ);
  return array[index];
}

//// The same however deals with a const vector therefore returns a const 
// element
template< class DataT>
const DataT& SmallArray< DataT>::operator[](unsigned short index) const
{
  assert(index < occ);
  return array[index];
}


template< class DataT>
DataT* SmallArray< DataT>::begin()
{
  return array;
}

template< class DataT>
DataT* SmallArray< DataT>::end()
{
  return array+occ;
}

template< class DataT>
const DataT* SmallArray< DataT>::begin() const
{
  return array;
}

template< class DataT>
const DataT* SmallArray< DataT>::end() const
{ 
  return array+occ; 
}
  
#endif





