////////////////////////////////////////////////////////////////////////
// Package: CandTrackCam
//
// marshall@hep.phy.cam.ac.uk
////////////////////////////////////////////////////////////////////////
#include <cassert>

// For measuring CPU time
extern "C" {
#include <unistd.h>    // sysconf
#include <sys/times.h> // times()
}

// Job Control includes
#include "MessageService/MsgService.h"
#include "MinosObjectMap/MomNavigator.h"
#include "JobControl/JobCModuleRegistry.h" // For JOBMODULE macro

// Algorithm includes
#include "Algorithm/AlgFactory.h"
#include "Algorithm/AlgHandle.h"
#include "Algorithm/AlgConfig.h"

// Candidate includes
#include "CandData/CandRecord.h"
#include "Candidate/CandContext.h"

#include "RecoBase/CandSliceHandle.h"
#include "RecoBase/CandSliceListHandle.h"
#include "RecoBase/CandTrack.h"
#include "RecoBase/CandTrackHandle.h"
#include "RecoBase/CandTrackListHandle.h"

#include "RawData/RawRecord.h"
#include "RawData/RawDaqSnarlHeader.h"

// This package includes
#include "CandTrackCam/TrackCamListModule.h"
#include "CandTrackCam/CandTrackCamListHandle.h"
#include "CandTrackCam/CandTrackCamList.h"

JOBMODULE(TrackCamListModule, "TrackCamListModule", "Track finder");
CVSID("$Id: TrackCamListModule.cxx,v 1.6 2008/07/03 21:57:33 gmieg Exp $");

////////////////////////////////////////////////////////////////////////
TrackCamListModule::TrackCamListModule()
{
  fAlgName="AlgTrackCamList";
  fAlgConfig="default";

  fListIn="CandSliceList";
}
////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////
TrackCamListModule::~TrackCamListModule()
{
}
////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////
void TrackCamListModule::BeginJob()
{
  MSG("TrackCamListModule", Msg::kDebug) << " Track Finder startup complete " << endl;
}
////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////
void TrackCamListModule::EndJob()
{
}
////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////
JobCResult TrackCamListModule::Reco(MomNavigator* mom)
{
  JobCResult result(JobCResult::kPassed);
  
  const char* alg_name = 0;
  const char* alg_config_name = 0;
  
  // Get CandRecord
  CandRecord *candrec = dynamic_cast<CandRecord *> (mom->GetFragment("CandRecord", "PrimaryCandidateRecord"));
  if(!candrec)
    {
      MSG("TrackCamListModule", Msg::kWarning) << " Failed to Find CandRecord " << endl;
      return result.SetFailed();
    }

  // Get RawRecord
  RawRecord *rr = dynamic_cast<RawRecord *>(mom->GetFragment("RawRecord"));
  if(rr==0){
    MSG("TrackCamListModule", Msg::kWarning) << " Failed to Find RawRecord " << endl;
    return result.SetFailed();
  }
  
  // Get RawHeader
  else {
    const RawDaqSnarlHeader* hdr = dynamic_cast<const RawDaqSnarlHeader*>(rr->GetRawHeader());
    if(hdr){
      MSG("TrackCamListModule", Msg::kDebug) << "TrackCamListModule:Reco Run:Snarl "<<hdr->GetRun()<<":"<< hdr->GetSnarl()<<endl; 
    }
  }


  // Get CandSliceListHandle
  CandSliceListHandle* slice_list = dynamic_cast<CandSliceListHandle*>(candrec->FindCandHandle("CandSliceListHandle",fListIn.Data()));
  if( !slice_list || (slice_list && slice_list->GetNDaughters()<1) )
    {
      // Require number of CandSlices to be non-zero.
      if(!slice_list) {
	MSG("TrackCamListModule", Msg::kWarning) << " Failed to Find " << fListIn.Data() << endl;}
      else if(slice_list && slice_list->GetNDaughters()<1) {
	MSG("TrackCamListModule", Msg::kDebug) << " No slices found. Empty " << fListIn.Data() << endl;}

      //return JobCResult::kPassed;
      return JobCResult::kAOK;     // Otherwise no further processing of record
    }


  AlgFactory &af = AlgFactory::GetInstance();
  alg_name=fAlgName.Data(); alg_config_name=fAlgConfig.Data();
  AlgHandle adlh = af.GetAlgHandle(alg_name,alg_config_name);
  
  CandContext cx(this, mom);
  cx.SetCandRecord(candrec);
  cx.SetDataIn(slice_list);

  clock_t dummyt;
  struct tms t1;
  struct tms t2;
  static double ticksPerSecond = sysconf(_SC_CLK_TCK);
  
  dummyt = times(&t1);
  CandTrackCamListHandle ctlh = CandTrackCamList::MakeCandidate(adlh, cx);
  dummyt = times(&t2);
  ctlh.SetCPUTime((Double_t)(t2.tms_utime+t2.tms_stime-t1.tms_utime-t1.tms_stime)/ticksPerSecond);

  MSG("TrackCamListModule", Msg::kVerbose) << "CandTrackCam CPUTime " << ctlh.GetCPUTime() << endl;

  ctlh.SetName(fListOut.Data());
  ctlh.SetTitle(TString("Created by TrackCamListModule"));
  candrec->SecureCandHandle(ctlh);
   
  return JobCResult::kPassed; // kNoDecision, kFailed, etc.
}
////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////
const char* TrackCamListModule::GetName() const
{
  const char* tmps = "TrackCamListModule";
  return tmps;
}
////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////
const Registry& TrackCamListModule::DefaultConfig() const
{
//======================================================================
// Supply the default configuration for the module
//======================================================================
  static Registry r; // Default configuration for module

  // Set name of config
  std::string name = this->GetName();
  name += ".config.default";
  r.SetName(name.c_str());

  // Set values in configuration
  r.UnLockValues();
  r.Set("NameListIn","CandSliceList");
  r.Set("NameListOut","CandTrackCamList");
  r.Set("TrackCamAlgorithm","AlgTrackCamList");
  r.Set("TrackListAlgConfig","default");
  r.LockValues();

  return r;
}
////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////
void TrackCamListModule::Config(const Registry& r)
{
//======================================================================
// Configure the module given the Registry r
//======================================================================
  const char* tmps;
  if (r.Get("NameListIn",tmps)) { fListIn = tmps; }
  if (r.Get("NameListOut",tmps)) { fListOut = tmps; }
  if (r.Get("TrackCamAlgorithm",tmps)) { fAlgName = tmps; }
  if (r.Get("TrackListAlgConfig",tmps)) { fAlgConfig = tmps; }
}
////////////////////////////////////////////////////////////////////////
