#ifndef SubAccessor_HH
#define SubAccessor_HH

#include <vector>
#include <string>
#include <iostream>

#include "SubHeader.hh"
#include "SubRecordType.hh"

class RcdRecord;


class SubAccessor {

public:
  SubAccessor(const RcdRecord &r);

  std::vector<const SubHeader*> access(unsigned t=0xffffffff) const;

  template<class Payload> std::vector<const Payload*> access() const;

  template<class Payload> std::vector<const CrcLocationData<Payload>*> locationAccess(unsigned char c) const;

  std::ostream& print(std::ostream &o, std::string s="") const;

  // Obsolete
  template<class Payload> std::vector<const Payload*> extract() const;


private:
  const RcdRecord &_record;
};

template<class Payload> std::vector<const Payload*> SubAccessor::access() const {
  
  std::vector<const SubHeader*> v(access(subRecordType<Payload>()));
  
  std::vector<const Payload*> w(v.size());
  for(unsigned i(0);i<v.size();i++) {
    w[i]=(const Payload*)v[i]->data();
  }
  
  return w;
}

template<> std::vector<const CrcLocationData<EmcFeConfigurationData>*>
SubAccessor::access< CrcLocationData<EmcFeConfigurationData> >() const {

  std::vector<const CrcLocationData<CrcFeConfigurationData>*> 
    v(access< CrcLocationData<CrcFeConfigurationData> >());
  
  std::vector<const CrcLocationData<EmcFeConfigurationData>*> w;

  for(unsigned i(0);i<v.size();i++) {
    if(v[i]->crateNumber()==0xec) {
      w.push_back((const CrcLocationData<EmcFeConfigurationData>*)v[i]);
    }
  }

  return w;
}

template<> std::vector<const CrcLocationData<AhcFeConfigurationData>*>
SubAccessor::access< CrcLocationData<AhcFeConfigurationData> >() const {

  std::vector<const CrcLocationData<CrcFeConfigurationData>*> 
    v(access< CrcLocationData<CrcFeConfigurationData> >());
  
  std::vector<const CrcLocationData<AhcFeConfigurationData>*> w;

  for(unsigned i(0);i<v.size();i++) {
    if(v[i]->crateNumber()==0xac) {
      w.push_back((const CrcLocationData<AhcFeConfigurationData>*)v[i]);
    }
  }

  return w;
}

template<class Payload> std::vector<const CrcLocationData<Payload>*>
SubAccessor::locationAccess(unsigned char c) const {
  
  std::vector<const SubHeader*> v(access(subRecordType< CrcLocationData<Payload> >()));
  
  std::vector<const CrcLocationData<Payload>*> w;
  for(unsigned i(0);i<v.size();i++) {
    if(((CrcLocationData<Payload>*)(v[i]+1))->crateNumber()==c) {
      w.push_back((const CrcLocationData<Payload>*)(v[i]->data()));
    }
  }

  return w;
}

// Obsolete
template<class Payload> std::vector<const Payload*> SubAccessor::extract() const {
  return access<Payload>();
}


#ifdef CALICE_DAQ_ICC

#include "RcdRecord.hh"


SubAccessor::SubAccessor(const RcdRecord &r) : _record(r) {
}

std::vector<const SubHeader*> SubAccessor::access(unsigned t) const {
  std::vector<const SubHeader*> v;
  
  const SubHeader *h((const SubHeader*)_record.data());
  const SubHeader *g((const SubHeader*)_record.newData());
  
  for(;h!=0 && h<g;h=h->nextSubHeader()) {
    if(h->subRecordType()==t || t>0xffff) v.push_back(h);
  }
  
  return v;
}

std::ostream& SubAccessor::print(std::ostream &o, std::string s) const {
  std::vector<const SubHeader*> v(access());
  
  o << s << "SubAccessor::print()  Number of subrecords = "
    << v.size() << "  Number of bytes stored = "
    << _record.totalNumberOfBytes() << std::endl;

  for(unsigned i(0);i<v.size();i++) {
    v[i]->print(o,s+" ");
  }
  
  return o;
}

#endif
#endif
