#ifndef CONFIG_TABLE_HH
#define CONFIG_TABLE_HH

/****************************************************************************
 **
 ** An extension of the ItemList class to allow for lists of arbitrary length
 ** (fixed in constructor).  There are two constructors, depending on whether
 ** or not the elements of each list are named.  If they are, the config is
 ** assumed to have elements that look like:
 ** tablename rowname{
 **     name = value;
 **     name = value;
 **     ...
 ** }
 ** Alternatively, a prefix may be specified, in which case the config
 ** file is assumed to have elements of the sort:
 ** tablename rowname{
 **     prefix0 = value;
 **     prefix1 = value;
 **     ...
 ** }
 **
 ** Here the numbers in prefix* are in no particular order, but must be
 ** in the range (0,numcells-1).  A default value is given, so any elements
 ** which are not listed in the config file are initialized to the default.
 **
 **  WARNING!  Each row must have at least one element listed in config file.
 **
 ****************************************************************************/
#include "Item.h"
#include "ItemList.h"
#include <Attributes.h>
#include <StringAttribute.h>
#include <IntegerAttribute.h>
#include <FloatAttribute.h>
#include <BooleanAttribute.h>
#include <string>
#include "SmartSamplerExceptions.hh"
#include "ssdbg.hh"

//#include <vector>
#include "DynamicArray.h"

#define MAX_CELL_DIGITS 10 // Allow number of columns with this many digits.

// generate attribute and add to list for the various different types of cells we
// might be interested in.
void addCell(Attributes *att, char *name, char *longname, long *valaddr, long init){
  att->add( new IntegerAttribute(name,longname,valaddr,init));
}
void addCell(Attributes *att, char *name, char *longname, double *valaddr, double init){
  att->add( new FloatAttribute(name,longname,valaddr,init));
}
void addCell(Attributes *att, char *name, char *longname, char **valaddr, char *init){
  att->add( new StringAttribute(name,longname,valaddr,init));
}
void addCell(Attributes *att, char *name, char *longname, bool *valaddr, bool init){
  att->add( new BooleanAttribute(name,longname,(unsigned char *)valaddr,(unsigned char)init));
}

//
// Here we intantiate a class for handling one row of the table.
//
template <class cellType>
class ConfigTableRow: public Item {
public:

  ConfigTableRow(const char *name, char *prefix, int numCols, cellType defaultvalue)
    : row(numCols),Item( name ){
    int i;
    char nn[MAX_CELL_DIGITS];
    string colname;
    ssdbg(DBG_LOAD_TABLES)("ConfigTableRow constructor called with name=%s,prefix=%s,numCols=%d",name,prefix,numCols);
    for(i=0;i<numCols;i++){
      row.add(&defaultvalue);
      if(row.mem_error){
	throw LoadError("Memory error in DynamicArray called from ConfigTableRow");
      }
      sprintf(nn,"%d",i);
      colname = prefix;
      colname += nn;
      ssdbg(DBG_LOAD_TABLES)("ConfigTableRow adding cell %d with name %s",i,colname.c_str());
      addCell(&_attributes,(char *)colname.c_str(),(char *)colname.c_str(),getref(i),defaultvalue);
    }
  }

  ConfigTableRow(const char *name,std::vector<string> *colnames, int numCols, cellType defaultvalue)
    : row(numCols),Item( name ){
    int i;
    for(i=0;i!=colnames->size();i++){
      row.add(&defaultvalue);
      addCell(&_attributes,(char *)colnames->at(i).c_str(),(char *)colnames->at(i).c_str(),getref(i),defaultvalue);
    }
  }
  
  ~ConfigTableRow(){}

  cellType getval(int idx){
    cellType val;
    if(row.get(idx,&val)){
      ssdbg(DBG_LOAD_TABLES)("SmartSampler -- Error picking up value from configuration table!");
    }
    return(val);
  }

private:
  //  std::vector<cellType> row;
  DynamicArray<cellType> row;
  cellType *getref(int idx){
    cellType *ar = row.get_array();
    return(&ar[idx]);
  }
};


//
// Next, we put it all together into the whole table.
//
template <class cellType>
class ConfigTable : public ItemList {
public:
  ConfigTable(char *name, char *prefix, int numCols, cellType defaultvalue)
    : ItemList( name ),ft_prefix(prefix),ft_cols(numCols),ft_init(defaultvalue)
  {ft_colnames = new std::vector<string>;}
  ConfigTable(char *name, std::vector<string>*namelist, cellType defaultvalue)
    : ItemList( name ),ft_prefix(NULL),ft_cols(namelist->size()),ft_init(defaultvalue),ft_colnames(namelist)
  {}

  ~ConfigTable(){}

protected:
  Item *addItem(char const *name){
    ConfigTableRow<cellType> *newRow;
    ssdbg(DBG_LOAD_TABLES)("ConfigTable.addItem called for table %s, row name %s",identifier(),name);
    ssdbg(DBG_LOAD_TABLES)("Number of column names: %d",ft_colnames->size());
    if(ft_colnames->empty()){
      ssdbg(DBG_LOAD_TABLES)("ConfigTable.addItem constructing with prefix=%s,cols=%d,init=%s",ft_prefix,ft_cols,ft_init);
      newRow = new ConfigTableRow<cellType>(name,ft_prefix,ft_cols,ft_init);
    }else{
      newRow = new ConfigTableRow<cellType>(name,ft_colnames,ft_colnames->size(),ft_init);
    }
    _itemList.add( (Item * * )&newRow );
    return newRow;
  }
  std::vector<string> *ft_colnames;
  char *ft_prefix;
  int ft_cols;
  cellType ft_init;
};

#endif // CONFIG_TABLE_HH
