#ifndef AhcSlowReadout_HH
#define AhcSlowReadout_HH

#include <iostream>
#include <fstream>

// dual/inc/utl
#include "UtlPack.hh"

// dual/inc/rcd
#include "RcdUserRW.hh"
#include "RcdHeader.hh"

// dual/inc/sub
#include "SubInserter.hh"
#include "SubAccessor.hh"
#include "DaqConfigurationStart.hh"
#include "BmlSlowRunData.hh"
#include "AhcSlowRunData.hh"
#include "AhcSlowConfigurationData.hh"
//#include "AhcSlowControlData.hh"
#include "AhcSlowReadoutData.hh"

// dual/inc/skt
#include "DuplexSocket.hh"


class AhcSlowReadout : public RcdUserRW {

public:
  //  AhcSlowReadout(std::string ipAddress="localhost",
  //AhcSlowReadout(std::string ipAddress="131.169.184.160", // tent at DESY
  AhcSlowReadout(std::string ipAddress="131.169.184.162", // beam at DESY
		  unsigned port=1201, unsigned tries=10) :
    RcdUserRW(), _socket(ipAddress.c_str(),port,tries),
    _runType(DaqRunType::daqTest) {

    std::cout << std::endl << "AhcSlowReadout::ctor()  SOCKET ESTABLISHED" << std::endl << std::endl;
  }

  virtual ~AhcSlowReadout() {
  }

  bool record(RcdRecord &r) {
    if(doPrint(r.recordType())) {
      std::cout << "AhcSlowReadout::record()" << std::endl;
      r.RcdHeader::print(std::cout," ") << std::endl;
    }
    
    // Check record type
    if(r.recordType()==RcdHeader::startUp) {

      std::string recv;
      sendAndRecv("reset",recv);
      
      // Nothing to read back
    }
    
    if(r.recordType()==RcdHeader::runStart ||
       r.recordType()==RcdHeader::runEnd) {

      SubInserter inserter(r);

      std::string recv;
      sendAndRecv("run",recv);
      // Don't store timestamp as sent again below

      // Get list of connected modules      
      sendAndRecv("readout mod_position",recv);
      assert(_slowRunData.parse(recv));
      if(doPrint(r.recordType(),1)) _slowRunData.print(std::cout," ") << std::endl;
      
      inserter.insert<AhcSlowRunData>(_slowRunData);

      // Get beam settings
#ifdef BML_SLOW_DATA

      // Only do this for beam runs as it is slow!
      if(r.recordType()==RcdHeader::runStart) {
	SubAccessor accessor(r);
	std::vector<const DaqRunStart*> v(accessor.extract<DaqRunStart>());
	assert(v.size()==1);
	_runType=v[0]->runType();
      }

      if(_runType.beamType()) {

#ifdef CERN_SETTINGS
	// First request values from database
	sendAndRecv("readout CERN getNewBeamData",recv);
	
	// Now get all the separate values
	BmlCernSlowRunData b;

	sendAndRecv("readout CERN 6POL",recv);
	assert(b.parse(recv,0));
	sendAndRecv("readout CERN ABSORBER",recv);
	assert(b.parse(recv,1));
	sendAndRecv("readout CERN BEND",recv);
	assert(b.parse(recv,2));
	sendAndRecv("readout CERN COLL",recv);
	assert(b.parse(recv,3));
	sendAndRecv("readout CERN H6",recv);
	assert(b.parse(recv,4));
	sendAndRecv("readout CERN QUAD",recv);
	assert(b.parse(recv,5));

	// These data have been disabled for 2007!?!
	//sendAndRecv("readout CERN RP",recv);
	//assert(b.parse(recv,6));

	sendAndRecv("readout CERN SCINT",recv);
	assert(b.parse(recv,7));
	sendAndRecv("readout CERN T4",recv);
	assert(b.parse(recv,8));
	sendAndRecv("readout CERN TARGET",recv);
	assert(b.parse(recv,9));
	sendAndRecv("readout CERN TRIM",recv);
	assert(b.parse(recv,10));
	
	inserter.insert<BmlCernSlowRunData>(b);
	if(doPrint(r.recordType(),1)) b.print(std::cout," ") << std::endl;
#endif

#ifdef FNAL_SETTINGS
	// First request new values from database
	//sendAndRecv("readout FNAL getNewBeamData",recv);
	
	// Now get the values
	sendAndRecv("readout FNAL data",recv);
	BmlFnalSlowReadoutData b;
	assert(b.parse(recv));
	inserter.insert<BmlFnalSlowReadoutData>(b);
	if(doPrint(r.recordType(),1)) b.print(std::cout," ") << std::endl;

	sendAndRecv("readout FNAL spilldata",recv);
	BmlFnalAcquisitionData c;
	assert(c.parse(recv));
	inserter.insert<BmlFnalAcquisitionData>(c);
	if(doPrint(r.recordType(),1)) c.print(std::cout," ") << std::endl;
#endif


      }
#endif

    }

    if(r.recordType()==RcdHeader::configurationStart) {
      std::string recv;
      
      SubAccessor accessor(r);
      std::vector<const AhcSlowConfigurationData*>
	v(accessor.access<AhcSlowConfigurationData>());
      assert(v.size()<=1);
      
      // Check for data to write down to PC
      if(v.size()==1 && v[0]->timeStamp()==0) {
	if(doPrint(r.recordType(),1)) v[0]->print(std::cout," ") << std::endl;
	
	int x(v[0]->xPosition());
	int y(v[0]->yPosition());
	
	std::ostringstream sout;
	sout << "position " << x << " " << y;

#ifdef AHC_SLOW_DISABLED
	std::cerr << "AhcSlwReadout stage move request DISABLED " << sout.str() << std::endl;
#else	
	sendAndRecv(sout.str(),recv);
	
      } else {
#endif
	sendAndRecv("control",recv);
      }

      SubInserter inserter(r);
      AhcSlowConfigurationData *d(inserter.insert<AhcSlowConfigurationData>(true));
      assert(d->parse(recv));
      if(doPrint(r.recordType(),1)) d->print(std::cout," ");
    }
    
    if(r.recordType()==RcdHeader::configurationEnd) {
      std::string recv;

      AhcSlowConfigurationData x;
      sendAndRecv("control",recv);
      assert(x.parse(recv));
      x.print(std::cout) << std::endl;

      SubInserter inserter(r);
      inserter.insert<AhcSlowConfigurationData>(x);
    }

#ifdef BML_SLOW_DATA
    if(r.recordType()==RcdHeader::acquisitionStart ||
       r.recordType()==RcdHeader::acquisitionEnd) {
      if(_runType.beamType()) {
	SubInserter inserter(r);
	std::string recv;

#ifdef FNAL_SETTINGS
	sendAndRecv("readout FNAL spilldata",recv);
	BmlFnalAcquisitionData c;
	assert(c.parse(recv));
	inserter.insert<BmlFnalAcquisitionData>(c);
	if(doPrint(r.recordType(),1)) c.print(std::cout," ") << std::endl;
#endif

      }
    }
#endif

    // Slow readout
    if(r.recordType()==RcdHeader::slowReadout) {
      SubInserter inserter(r);
      
      std::string recv;
      for(unsigned i(0);i<38;i++) {
	if(_slowRunData.module(i)>0 && _slowRunData.module(i)<39) {
	  std::ostringstream sout;
	  //sout << "readout mod " << _slowRunData.module(i);
	  sout << "readout mod " << i+1;
	  
	  sendAndRecv(sout.str(),recv);
	  AhcSlowReadoutData x;
	  assert(x.parse(recv));
	  if(doPrint(r.recordType(),2)) x.print(std::cout) << std::endl;
	  inserter.insert<AhcSlowReadoutData>(x);
	}
      }

#ifdef BML_SLOW_DATA
#ifdef FNAL_SETTINGS
      sendAndRecv("readout FNAL data",recv);
      BmlFnalSlowReadoutData b;
      assert(b.parse(recv));
      inserter.insert<BmlFnalSlowReadoutData>(b);
      if(doPrint(r.recordType(),1)) b.print(std::cout," ") << std::endl;
#endif
#endif

    }

    return true;
  }
  
  bool sendAndRecv(const std::string &s, std::string &r) {
    r.clear();

    //if(doPrint(r.recordType(),4))
    //  std::cout << " sendAndRecv()  std::string to send "
    //	<< s.size() << " bytes ==>" << s << "<==" << std::endl;

    std::string t("daqrequest "+s+'#');
    //if(doPrint(r.recordType(),5))
 std::cout << t << std::endl;

    if(!_socket.send(t.c_str(),t.size())) {
      std::cerr << "AhcSlowReadout::sendAndRecv()  Error writing to socket;"
		<< " number of bytes written < " << s.size() << std::endl;
      perror(0);
      return false;
    }
    
    bool terminated(false);
    //bool terminated(true);
    char x;
    std::string h;
    //std::cout <<"Before receving part! " << terminated << std::endl;
     
    for(unsigned i(0);!terminated;i++) {
      int n(-1);
      //if(doPrint(r.recordType(),6)) std::cout << " sendAndRecv()  Waiting for byte " << i;
      n=_socket.recv(&x,1);
      //if(doPrint(r.recordType(),6)) std::cout << "...got byte " << i << std::endl;
      
      if(n!=1) {
	std::cerr << "AhcSlowReadout::sendAndRecv()  Error reading from socket;"
		  << " number of bytes written = " << n << " < 1" << std::endl;
	perror(0);
	return false;
      }

      if(x=='#') terminated=true;
      else {
	if(i>10) r+=x;
	else     h+=x;
      }
    }

    //if(doPrint(r.recordType(),4))

      std::cout << " sendAndRecv()  std::string recv ed "
    	<< " header " << h.size()
    	<< " bytes ==>" << h << "<=="
    	<< ", message " << r.size()
    	<< " bytes ==>" << r << "<==" << std::endl;
    
    return true;
  }
    
private:
  DuplexSocket _socket;
  AhcSlowRunData _slowRunData;
  DaqRunType _runType;
};

#endif
