#ifndef FixAhc_HH
#define FixAhc_HH

class RcdRecord;

class FixAhc {

public:
  FixAhc();
  FixAhc(unsigned p);

  bool fix(RcdRecord &r);

private:
  unsigned _printLevel;
};


#ifdef CALICE_DAQ_ICC

#include <iostream>

// records/inc/rcd
#include "RcdRecord.hh"

// records/inc/sub
#include "SubInserter.hh"
#include "SubAccessor.hh"
#include "SubRecordType.hh"

// records/inc/crc
#include "CrcLocationData.hh"

// records/inc/ahc
#include "AhcFeConfigurationDataV0.hh"
#include "AhcFeConfigurationData.hh"
#include "AhcVfeConfigurationData.hh"
#include "AhcVfeStartUpData.hh"


FixAhc::FixAhc() : _printLevel(0) {
}

FixAhc::FixAhc(unsigned p) : _printLevel(p) {
}

bool FixAhc::fix(RcdRecord &r) {

  if(r.recordType()==RcdHeader::configurationStart ||
     r.recordType()==RcdHeader::configurationStop  ||
     r.recordType()==RcdHeader::configurationEnd) {
   
    SubAccessor accessor(r);

    // AhcFeConfigurationData V0->V1 and to Vfe
    std::vector<const CrcLocationData<AhcFeConfigurationDataV0>*>
      v0(accessor.access< CrcLocationData<AhcFeConfigurationDataV0> >());
    
    std::vector<const CrcLocationData<AhcFeConfigurationData>*>
      v1(accessor.access< CrcLocationData<AhcFeConfigurationData> >());
    
    std::vector<const CrcLocationData<AhcVfeConfigurationData>*>
      vc(accessor.access< CrcLocationData<AhcVfeConfigurationData> >());
    
    std::vector<const CrcLocationData<AhcVfeStartUpData>*>
      vs(accessor.access< CrcLocationData<AhcVfeStartUpData> >());
    
    bool originalPrint(false);
    
    if(v0.size()>0 && v1.size()==0) {
      if(!originalPrint && _printLevel>2) {
	std::cout << "FixAhc::fix()  Original AhcFeConfigurationDataV0 subrecords"
		  << std::endl;
	for(unsigned i(0);i<v0.size();i++) v0[i]->print(std::cout," ") << std::endl;
	originalPrint=true;
      }
      
      SubInserter inserter(r);
      
      for(unsigned i(0);i<v0.size();i++) {
	inserter.insert< CrcLocationData<AhcFeConfigurationData> >(
								   CrcLocationData<AhcFeConfigurationData>(v0[i]->location(),AhcFeConfigurationData(*(v0[i]->data()))));
      }
      
      v1=accessor.access< CrcLocationData<AhcFeConfigurationData> >();
      //assert(v1.size()==v0.size());
      
      if(_printLevel>2) {
	std::cout << "FixAhc::fix() Final AhcFeConfigurationData subrecords"
		  << std::endl;
	for(unsigned i(0);i<v1.size();i++) v1[i]->print(std::cout);
      }
    }
    
    if(v0.size()>0 && vc.size()==0) {
      if(!originalPrint && _printLevel>2) {
	std::cout << "FixAhc::fix()  Original AhcFeConfigurationDataV0 subrecords"
		  << std::endl;
	for(unsigned i(0);i<v0.size();i++) v0[i]->print(std::cout);
	originalPrint=true;
      }
      
      SubInserter inserter(r);
      
      for(unsigned i(0);i<v0.size();i++) {
	inserter.insert< CrcLocationData<AhcVfeConfigurationData> >(
								    CrcLocationData<AhcVfeConfigurationData>(v0[i]->location(),AhcVfeConfigurationData(*(v0[i]->data()))));
      }
      
      vc=accessor.access< CrcLocationData<AhcVfeConfigurationData> >();
      assert(vc.size()==v0.size());
      
      if(_printLevel>2) {
	std::cout << "FixAhc::fix() Final AhcVfeConfigurationData subrecords"
		  << std::endl;
	for(unsigned i(0);i<vc.size();i++) vc[i]->print(std::cout);
      }
    }
    
    if(v0.size()>0 && vs.size()==0) {
      if(!originalPrint && _printLevel>2) {
	std::cout << "FixAhc::fix()  Original AhcFeConfigurationDataV0 subrecords"
		  << std::endl;
	for(unsigned i(0);i<v0.size();i++) v0[i]->print(std::cout);
	originalPrint=true;
      }
      
      SubInserter inserter(r);
      
      for(unsigned i(0);i<v0.size();i++) {
	inserter.insert< CrcLocationData<AhcVfeStartUpData> >(
							      CrcLocationData<AhcVfeStartUpData>(v0[i]->location(),AhcVfeStartUpData(*(v0[i]->data()))));
      }
      
      vs=accessor.access< CrcLocationData<AhcVfeStartUpData> >();
      assert(vs.size()==v0.size());
      
      if(_printLevel>2) {
	std::cout << "FixAhc::fix() Final AhcVfeStartUpData subrecords"
		  << std::endl;
	for(unsigned i(0);i<vs.size();i++) vs[i]->print(std::cout);
      }
    }
    
    // Now convert to CrcFeConfigurationData subrecords
    
    // Cannot access using normal accessor as template is specialised
    std::vector<const SubHeader*> v(accessor.access(subRecordType< CrcLocationData<AhcFeConfigurationData> >()));
    
    // Change subrecord type to be CRC value and set crate number to AHCAL value
    for(unsigned i(0);i<v.size();i++) {
      ((SubHeader*)v[i])->subRecordType(subRecordType< CrcLocationData<CrcFeConfigurationData> >());
      ((CrcLocationData<CrcFeConfigurationData>*)(v[i]->data()))->crateNumber(0xac);
    }
    
    return true;
  }

  return true;
}

#endif
#endif
