#include "hades.h"
#include "hcategory.h"
#include "hevent.h"
#include "hruntimedb.h"
#include "hspectrometer.h"
#include "hstart2cal.h"
#include "hstart2detector.h"
#include "hstart2hit.h"
#include "hstart2hitf.h"
#include "hstart2hitfpar.h"
#include "hstartdef.h"
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
ClassImp(HStart2HitF)
HStart2HitF::HStart2HitF(void)
   : HReconstructor()
{
   
   fCatCal    = NULL;
   fCatHit    = NULL;
   fPar       = NULL;
   fSkipEvent = kFALSE;
}
HStart2HitF::HStart2HitF(const Text_t *name, const Text_t *title, Bool_t skip)
   : HReconstructor(name, title)
{
   
   fCatCal    = NULL;
   fCatHit    = NULL;
   fPar       = NULL;
   fSkipEvent = skip;
}
Bool_t HStart2HitF::init(void)
{
   
   
   
   HStart2Detector* det = static_cast<HStart2Detector*>(gHades->getSetup()->getDetector("Start"));
   if (NULL == det) {
       Error("init", "No Start Detector found.");
       return kFALSE;
   }
   fCatCal = gHades->getCurrentEvent()->getCategory(catStart2Cal);
   if (NULL == fCatCal) {
       Error("init", "HStart2Cal category not available!");
       return kFALSE;
   }
   fCatHit = det->buildCategory(catStart2Hit);
   if (NULL == fCatHit) {
       Error("init", "HStart2Hit category not available!");
       return kFALSE;
   }
   HRuntimeDb* rtdb = gHades->getRuntimeDb();
   fPar = static_cast<HStart2HitFPar*>(rtdb->getContainer("Start2HitFPar"));
   if (NULL == fPar) {
       Error("init", "Pointer to Start2HitFPar parameters is NULL");
       return kFALSE;
   }
   loc.set(1, 0);
   fActive = kTRUE;
   return kTRUE;
}
Int_t HStart2HitF::execute(void)
{
   
   HStart2Cal* pCal = NULL;
   HStart2Hit* pHit = NULL;
   Bool_t foundTime = kFALSE;
   Int_t  module    = -1;
   Int_t  strip     = -1;
   fSecondTime       = -10000;
   Int_t newstrip    = -1;
   Float_t firstTime = -10000;
   firstCluster .clear();
   secondCluster.clear();
   for (Int_t entry = 0; entry < fCatCal->getEntries(); ++entry) {
      if (NULL == (pCal = static_cast<HStart2Cal*>(fCatCal->getObject(entry)))) {
	  Error("execute", "Pointer to HStart2Cal object == NULL, returning");
	  return -1;
      }
      
      if (pCal->getModule() > 1) continue;
      
      
      
      for (Int_t i = 0; i < pCal->getMultiplicity() && i < pCal->getMaxMultiplicity(); ++i) {
         if (pCal->getTime(i + 1) > (fPar->getMeanTime(pCal->getModule(), pCal->getStrip()) - fPar->getWidth(pCal->getModule(), pCal->getStrip())) &&
	    pCal->getTime(i + 1) < (fPar->getMeanTime(pCal->getModule(), pCal->getStrip()) + fPar->getWidth(pCal->getModule(), pCal->getStrip())))
	 {
	     pCal->getAddress(module, strip);
	     
	     if (!foundTime) {
		 pHit = static_cast<HStart2Hit*>(fCatHit->getSlot(loc));
		 if (NULL != pHit) {
		     pHit = new(pHit) HStart2Hit;
		 } else {
		     Error("execute", "Can't get slot mod=%i, chan=%i", loc[0], loc[1]);
		     return -1;
		 }
	     }
	     
	     if (!foundTime || firstTime > pCal->getTime(i + 1)) {
		 pHit->setAddress(module, strip);
		 pHit->setTimeAndWidth(pCal->getTime(i + 1), pCal->getWidth(i + 1));
		 pHit->setFlag(kTRUE);
		 pHit->setMultiplicity(pCal->getMultiplicity());
		 firstTime = pHit->getTime();
		 newstrip = entry * 1000 + i+1;
	     }
	     foundTime = kTRUE;
	 }
      }
   }
   
   
   vector<Int_t> vtemp;
   Float_t maxdiff   = 2; 
   Float_t newStart2 = -100000;  
   Float_t timediff  =  100000;  
   Int_t   nextHit   = -1;
   if (foundTime) firstCluster.push_back(newstrip);
   for (Int_t entry = 0; entry < fCatCal->getEntries(); ++entry) {
       if(NULL == (pCal = static_cast<HStart2Cal*>(fCatCal->getObject(entry)))) {
	   Error("execute", "Pointer to HStart2Cal object == NULL, returning");
	   return -1;
       }
       
       if (pCal->getModule() > 1) continue;
       
       
       
       for (Int_t i = 0; i < pCal->getMultiplicity() && i < pCal->getMaxMultiplicity(); ++i) {
	   if (pCal->getTime(i + 1) > (fPar->getMeanTime(pCal->getModule(), pCal->getStrip()) - fPar->getWidth(pCal->getModule(), pCal->getStrip())) &&
	       pCal->getTime(i + 1) < (fPar->getMeanTime(pCal->getModule(), pCal->getStrip()) + fPar->getWidth(pCal->getModule(), pCal->getStrip()))) {
	       Float_t time = pCal->getTime(i + 1);
	       newstrip     = entry * 1000 + i+1;
	       Float_t diff = TMath::Abs(firstTime-time) ;
	       if(diff < maxdiff) { 
		   if(find(firstCluster.begin(), firstCluster.end(), newstrip) == firstCluster.end()) {
		       firstCluster.push_back(newstrip);
		   }
	       } else {  
		   vtemp.push_back(newstrip);
		   if(diff < timediff) {
		       timediff  = diff;
		       nextHit   = newstrip;
		       newStart2 = time;
		   }
	       } 
	   } 
       } 
   } 
   if (vtemp.size() > 0) { 
       fSecondTime = newStart2;
       secondCluster.push_back(nextHit);
       for (UInt_t i = 0; i < vtemp.size(); i++) {
	   if (find(secondCluster.begin(), secondCluster.end(), vtemp[i]) == secondCluster.end()) {
	       secondCluster.push_back(vtemp[i]);
	   }
       }
   }
   
   
   if (firstCluster.size() > 0) {
       pHit = static_cast<HStart2Hit*>(fCatHit->getObject(0));
       if (NULL == pHit) {
	   Error("execute()", "Pointer to HStart2Hit object == NULL");
       } else {
	   pHit->setIteration(1);
	   pHit->resetClusterStrip(2);
	   for(UInt_t i = 0; i < firstCluster.size(); i++) {
	       pHit->setClusterStrip(0, firstCluster[i]);
	   }
	   for (UInt_t i = 0; i < secondCluster.size(); i++) {
	       pHit->setClusterStrip(1, secondCluster[i]);
	   }
	   pHit->setSecondTime(fSecondTime);
	   if (secondCluster.size() > 0)  pHit->setMultiplicity(2);
	   else                           pHit->setMultiplicity(1);
       }
   }
   
   if (kFALSE == foundTime && kTRUE == fSkipEvent) {
       return kSkipEvent;
   }
   return 0;
}