////////////////////////////////////////////////////////////////////////
//
// THcHelicity
//
// Helicity of the beam in delayed mode using quartets
//    +1 = plus,  -1 = minus,  0 = unknown
//
// Also supports in-time mode with delay = 0
// 
////////////////////////////////////////////////////////////////////////

#include "THcHelicity.h"

#include "THaApparatus.h"
#include "THaEvData.h"
#include "THcGlobals.h"
#include "THcParmList.h"
#include "THcHelicityScaler.h"
#include "TH1F.h"
#include "TMath.h"
#include <iostream>
#include <bitset>

using namespace std;

//_____________________________________________________________________________
THcHelicity::THcHelicity( const char* name, const char* description,
				    THaApparatus* app ):
  THaHelicityDet( name, description, app ), 
  fnQrt(-1), fHelDelay(8), fMAXBIT(30)
{
  //  for( Int_t i = 0; i < NHIST; ++i )
  //    fHisto[i] = 0;
  //  memset(fHbits, 0, sizeof(fHbits));
}

//_____________________________________________________________________________
THcHelicity::THcHelicity()
  : fnQrt(-1), fHelDelay(8), fMAXBIT(30)
{
  // Default constructor for ROOT I/O

  //  for( Int_t i = 0; i < NHIST; ++i )
  //    fHisto[i] = 0;
}

//_____________________________________________________________________________
THcHelicity::~THcHelicity() 
{
  DefineVariables( kDelete );

  // for( Int_t i = 0; i < NHIST; ++i ) {
  //   delete fHisto[i];
  // }
}

//_____________________________________________________________________________
THaAnalysisObject::EStatus THcHelicity::Init(const TDatime& date) {
  // Call `Setup` before everything else.
  Setup(GetName(), GetTitle());

  fFirstEvProcessed = kFALSE;
  fActualHelicity = kUnknown;
  fPredictedHelicity = kUnknown;
  fLastMPSTime = 0;
  fFoundMPS = kFALSE;

  // Call initializer for base class.
  // This also calls `ReadDatabase` and `DefineVariables`.
  EStatus status = THaDetector::Init(date);
  if (status) {
    fStatus = status;
    return fStatus;
  }

  fEvNumCheck = 0;
  fDisabled = kFALSE;

  fLastHelpCycle=-1;
  fQuadPattern[0] = fQuadPattern[1] = fQuadPattern[2] = fQuadPattern[3] = 0;
  fQuadPattern[4] = fQuadPattern[5] = fQuadPattern[6] = fQuadPattern[7] = 0;
  fHelperHistory=0;
  fHelperQuartetHistory=0;
  fScalerSeed=0;
  fNBits = 0;
  lastispos = 0;
  fLastReportedHelicity = kUnknown;
  fFixFirstCycle = kFALSE;
  fHaveQRT = kFALSE;
  fNQRTProblems = 0;
  fPeriodCheck = 0.0;
  fCycle = 0.0;

  fglHelicityScaler = 0;
  fHelicityHistory = 0;

  fStatus = kOK;
  return fStatus;
}

//_____________________________________________________________________________
void THcHelicity::Setup(const char* name, const char* description) {
  // Prefix for parameters in `param` file.
  string kwPrefix = string(GetApparatus()->GetName()) + "_" + name;
  std::transform(kwPrefix.begin(), kwPrefix.end(), kwPrefix.begin(), ::tolower);
  fKwPrefix = kwPrefix;
}

//_____________________________________________________________________________
Int_t THcHelicity::ReadDatabase( const TDatime& date )
{

  cout << "In THcHelicity::ReadDatabase" << endl;
  // Read general HelicityDet database values (e.g. fSign)
  //  Int_t st = THaHelicityDet::ReadDatabase( date );
  //  if( st != kOK )
  //    return st;

  // Read readout parameters (ROC addresses etc.)
  Int_t st = THcHelicityReader::ReadDatabase( GetDBFileName(), GetPrefix(),
					date, fQWEAKDebug );
  if( st != kOK )
      return st;

  fSign = 1;			// Default helicity sign
  fRingSeed_reported_initial = 0; // Initial see that should predict reported
                                // helicity of first quartet.
  fFirstCycle = -1; // First Cycle that starts a quad (0 to 3)
  fFreq = 29.5596;
  fHelDelay=8;

  DBRequest list[]= {
    //	  {"_hsign", &fSign, kInt, 0, 1},
    {"helicity_delay", &fHelDelay, kInt, 0, 1},
    {"helicity_freq", &fFreq, kDouble, 0, 1},
    //    {"helicity_seed", &fRingSeed_reported_initial, kInt, 0, 1},
    //    {"helicity_cycle", &fFirstCycle, kInt, 0, 1},
    {0}
  };

  gHcParms->LoadParmValues(list, "");

  fMAXBIT=30;

  fTIPeriod = 250000000.0/fFreq;

  // maximum of event in the pattern, for now we are working with quartets
  //  Int_t localpattern[4]={1,-1,-1,1}; 
  // careful, the first value here should always +1
  //  for(int i=0;i<fQWEAKNPattern;i++)
  //    {
  //      fPatternSequence.push_back(localpattern[i]);
  //    }
  HWPIN=kTRUE;

  fQuartet[0]=fQuartet[1]=fQuartet[2]=fQuartet[3]=0;

  if (fFirstCycle>=0 && fRingSeed_reported_initial!=0) {
    // Set the seed for predicted reported and predicted actual
  } else {
    // Initialize mode to find quartets and then seed
  }

  cout << "Helicity decoder initialized with frequency of " << fFreq
       << " Hz and reporting delay of " << fHelDelay << " cycles." << endl;

  return kOK;
}

//_____________________________________________________________________________

void THcHelicity::MakePrefix()
{
 THaDetector::MakePrefix();
}
//_____________________________________________________________________________
Int_t THcHelicity::DefineVariables( EMode mode )
{
  // Initialize global variables

  cout << "Called THcHelicity::DefineVariables with mode == "
       << mode << endl;

  if( mode == kDefine && fIsSetup ) return kOK;
  fIsSetup = ( mode == kDefine );

  // Define standard variables from base class
  THaHelicityDet::DefineVariables( mode );

  const RVarDef var[] = {
    { "nqrt",     "position of cycle in quartet",          "fnQrt" },
    { "hel",      "actual helicity for event",             "fActualHelicity" },
    { "helrep",   "reported helicity for event",           "fReportedHelicity" },
    { "helpred",  "predicted reported helicity for event", "fPredictedHelicity" },
    { "mps", "In MPS blanking period", "fMPS"},
    { "pcheck", "Period check", "fPeriodCheck"},
    { "cycle", "Helicity Cycle", "fCycle"},
    { "qrt", "Last cycle of quartet", "fQrt"},
    { 0 }
  };
  cout << "Calling THcHelicity DefineVarsFromList" << endl;
  return DefineVarsFromList( var, mode );
}
//_____________________________________________________________________________

void THcHelicity::PrintEvent(Int_t evtnum)
{

  cout<<" ++++++ THcHelicity::Print ++++++\n";

  cout<<" +++++++++++++++++++++++++++++++++++++\n";

  return;
}

//_____________________________________________________________________________
Int_t THcHelicity::Begin( THaRunBase* )
{
  THcHelicityReader::Begin();

  //  fHisto[0] = new TH1F("hel.seed","hel.seed",32,-1.5,30.5);
  //  fHisto[1] = new TH1F("hel.error.code","hel.error.code",35,-1.5,33.5);
 
  return 0;
}

//_____________________________________________________________________________
//void THcHelicity::FillHisto()
//{
//  fHisto[0]->Fill(fRing_NSeed);
//  fHisto[1]->Fill(fErrorCode);
//  return;
//}
//_____________________________________________________________________________
void THcHelicity::SetErrorCode(Int_t error)
{
 // used as a control for the helciity computation
  // 2^0: if the reported number of events in a  pattern is larger than fQWEAKNPattern
  // 2^1: if the offset between the ring reported value and TIR value is not fOffsetTIRvsRing
  // 2^2: if the reported time in the ring is 0
  // 2^3: if the predicted reported helicity doesn't match the reported helicity in the ring
  // 2^4: if the helicity cannot be computed using the SetHelicity routine
  // 2^5: if seed is being gathered

  if(fErrorCode==0)
    fErrorCode=(1<<error);
  // only one reported error at the time

  return;
}

//_____________________________________________________________________________
void THcHelicity::Clear( Option_t* opt ) 
{
  // Clear event-by-event data

  THaHelicityDet::Clear(opt);
  THcHelicityReader::Clear(opt);
  fEvtype = 0;

  fQrt=0;
  fErrorCode=0;

  return;
}
//_____________________________________________________________________________
void THcHelicity::SetHelicityScaler( THcHelicityScaler *f )
{
    fglHelicityScaler = f;
    fHelicityHistory = fglHelicityScaler->GetHelicityHistoryP();
}

//_____________________________________________________________________________
Int_t THcHelicity::Decode( const THaEvData& evdata )
{

  // Decode Helicity data.
  // Return 1 if helicity was assigned, 0 if not, <0 if error.
  evnum = evdata.GetEvNum();

  Int_t err = ReadData( evdata ); // from THcHelicityReader class
  if( err ) {
    Error( Here("THcHelicity::Decode"), "Error decoding helicity data." );
    return err;
  }

  fReportedHelicity = (fIsHelp?(fIsHelm?kUnknown:kPlus):(fIsHelm?kMinus:kUnknown));
  fMPS = fIsMPS?1:0;
  fQrt = fIsQrt?1:0;		// Last of quartet

  if(fglHelicityScaler) {
    Int_t nhelev = fglHelicityScaler->GetNevents();
    Int_t ncycles = fglHelicityScaler->GetNcycles();
    if(nhelev >0) {
      for(Int_t i=0;i<nhelev;i++) {
	fScaleQuartet = (fHelicityHistory[i] & 2)!=0;
	Int_t ispos = fHelicityHistory[i]&1;
	if(fScaleQuartet) {
	  fScalerSeed = ((fScalerSeed<<1) | ispos) & 0x3FFFFFFF;
	  if(fNBits >= fMAXBIT) {
	    Int_t seedscan = fScalerSeed;
	    Int_t nbehind;
	    for(nbehind=0;nbehind<4;nbehind++) {
	      if(seedscan == fRingSeed_reported) {
		if(nbehind>1) {
		  cout << "Scaler seed behind " << nbehind
		       << " quartets" << endl;
		  cout << "Ev seed     " << bitset<32>(fRingSeed_reported) <<endl;
		  cout << "Scaler Seed " << bitset<32>(fScalerSeed) << endl;
		}
		break;
	      }
	      seedscan = RanBit30(seedscan);
	    }
	    if(nbehind>4) {
	      cout << "Scaler seed does not match" << endl;
	      cout << "Ev seed     " << bitset<32>(fRingSeed_reported) <<endl;
	      cout << "Scaler Seed " << bitset<32>(fScalerSeed) << endl;
	    }
	  }
	}
      }
    }
  }
  
  if(fHelDelay == 0) {		// If no delay actual=reported (but zero if in MPS)
    fActualHelicity = fIsMPS?kUnknown:fReportedHelicity;
    return 0;
  }

  if(fDisabled) {
    fActualHelicity = kUnknown;
    return 0;
  }

  fEvNumCheck++;
  Int_t evnum = evdata.GetEvNum();
  if(fEvNumCheck!=evnum) {
    cout << "THcHelicity: Missed " << evnum-fEvNumCheck << " events at event " << evnum << endl;
    cout << "             Disabling helicity decoding for rest of run." << endl;
    cout << "             Make sure \"RawDecode_master in cuts file accepts all physics events." <<endl;
    fDisabled = kTRUE;
    fActualHelicity = kUnknown;
    return 0;
  }

  fActualHelicity = -10.0;
  if(fFirstEvProcessed) {	// Normal processing
    //    cout << evnum << " " << fNCycle << " " << fIsMPS << " " << fFoundMPS << " " << fTITime << " "
    //	 << fLastMPSTime << " " << fNBits << endl;
    Int_t missed = 0;
    //    Double_t elapsed_time = (fTITime - fFirstEvTime)/250000000.0;
    if(fIsMPS) {
      fPeriodCheck = fmod(fTITime/fTIPeriod,1.0);
      fCycle = (fTITime/fTIPeriod);
      fActualHelicity = kUnknown;
      fPredictedHelicity = kUnknown;
      if(fFoundMPS) {
	missed = TMath::Nint(fTITime/fTIPeriod-fLastMPSTime/fTIPeriod);
	if(missed < 1) { // was <=1
	  fLastMPSTime = (fTITime+fLastMPSTime+missed*fTIPeriod)/2;
	  fIsNewCycle = kTRUE;
	  fActualHelicity = kUnknown;
	  fPredictedHelicity = kUnknown;
	} else {
	  fLastMPSTime = (fLastMPSTime + fTITime - missed*fTIPeriod)/2;
	}
	// If there is a skip, pass it off to next non MPS event
	// Need to also check here for missed MPS's
	//      cout << "Found MPS" << endl;
	// check for Nint((time-last)/period) > 1
      } else {
	fFoundMPS = kTRUE;
	fLastMPSTime = fTITime;
      }
    } else if (fFoundMPS) {	//
      if(fTITime - fLastMPSTime > fTIPeriod) { // We missed MPS periods
	missed = TMath::Nint(floor((fTITime-fLastMPSTime)/fTIPeriod));
	if(missed > 1) {
	  //	  cout << "Missed " << missed << " MPSes" << endl;
	  Int_t newNCycle = fNCycle + missed -1; // How many cycles really missed
	  Int_t quartets_missed = (newNCycle-fFirstCycle)/4 - (fNCycle-fFirstCycle)/4;
	  int quartetphase = (newNCycle-fFirstCycle)%4;
	  //	  cout << "  " << fNCycle << " " << newNCycle << " " << fFirstCycle << " " << quartets_missed << " " << quartetphase << endl;
	  //	  cout << "Cycles " << fNCycle << " " << newNCycle << " " << fFirstCycle 
	  //	       << " skipped " << quartets_missed << " quartets" << endl;
	  fNCycle = newNCycle;
	  // Need to reset fQuartet to reflect where we are based on the current
	  // reported helicity.  So we don't fail quartet testing.
	  // But only do this if we are calibrated.
	  if(fNBits >= fMAXBIT) {

	    for(Int_t i=0;i<quartets_missed;i++) { // Advance the seeds.
	      //	      cout << "Advancing seed A " << fNBits << endl;
	      fRingSeed_reported = RanBit30(fRingSeed_reported);
	      fRingSeed_actual = RanBit30(fRingSeed_actual);
	    }

	    fQuartetStartHelicity = (fRingSeed_actual&1)?kPlus:kMinus;
	    fQuartetStartPredictedHelicity = (fRingSeed_reported&1)?kPlus:kMinus;
	    fActualHelicity = (quartetphase==0||quartetphase==3)?
	      fQuartetStartHelicity:-fQuartetStartHelicity;
	    fPredictedHelicity = (quartetphase==0||quartetphase==3)?
	      fQuartetStartPredictedHelicity:-fQuartetStartPredictedHelicity;

	    if (((fNCycle - fFirstCycle)%2)==1) {
	      fQuartet[0] = fReportedHelicity;
	      fQuartet[1] = fQuartet[2] = -fQuartet[0];
	    } else {
	      fQuartet[0] = fQuartet[1] = -fReportedHelicity;
	      fQuartet[2] = -fQuartet[1];
	    }
	  } else {
	    fActualHelicity = kUnknown;
	    fQuartet[0] = fReportedHelicity;
	    fQuartet[1] = 0;
	  }
	}
	fLastMPSTime += missed*fTIPeriod;
	fIsNewCycle = kTRUE;
	fLastReportedHelicity = fReportedHelicity;
      } else {			// No missed periods.  Get helicities from rings
	if(fNBits>=fMAXBIT) {
	  int quartetphase = (fNCycle-fFirstCycle)%4;
	  fQuartetStartHelicity = (fRingSeed_actual&1)?kPlus:kMinus;
	  fQuartetStartPredictedHelicity = (fRingSeed_reported&1)?kPlus:kMinus;
	  fActualHelicity = (quartetphase==0||quartetphase==3)?
	    fQuartetStartHelicity:-fQuartetStartHelicity;
	  fPredictedHelicity = (quartetphase==0||quartetphase==3)?
	  fQuartetStartPredictedHelicity:-fQuartetStartPredictedHelicity;
	} else {
	  fActualHelicity = 0;
	}
      }
      if(fIsNewCycle) {
	//	cout << "Scaler Seed " << bitset<32>(fScalerSeed) << endl;
	//Int_t predictedScalerSeed = RanBit30(fScalerSeed);
	//	cout << "Predct Seed " << bitset<32>(predictedScalerSeed) << endl;
	//cout << "Event Seed  " << bitset<32>(fRingSeed_reported) << endl;
	  
	fQuartet[3]=fQuartet[2]; fQuartet[2]=fQuartet[1]; fQuartet[1]=fQuartet[0];
	fQuartet[0]=fReportedHelicity;
	fNCycle++;
	//	cout << "XX: " << fNCycle << " " <<  fReportedHelicity << " " << fIsQrt <<endl;

	if(fIsQrt) {		// 
	  fNLastQuartet = fNQuartet;
	  fNQuartet = (fNCycle-fFirstCycle)/4;
	  if(fHaveQRT) {	// Should already have phase set
	    if((fNCycle-fFirstCycle)%4 != 0) {// Test if first in a quartet
	      fNQRTProblems++;
	      if(fNQRTProblems > 10) {
		cout << "QRT Problem resetting" << endl;
		fHaveQRT = kFALSE;
		fFoundQuartet = kFALSE;
		fNQRTProblems = 0;
	      } else {
		cout << "Ignored " << fNQRTProblems << " problems" << endl;
	      }
	    } else {
	      fNQRTProblems = 0;
	    }
	  }
	  if(!fHaveQRT) {
	    fHaveQRT = kTRUE;
	    fFoundQuartet = kTRUE;
	    
	    fFirstCycle = fNCycle; //
	    fNQuartet = (fNCycle-fFirstCycle)/4;
	    fNLastQuartet = fNQuartet - 1; // Make sure LoadHelicity uses
	    fNBits = 0;
	    fNQRTProblems = 0;
	    cout << "Phase found from QRT signal" << endl;
	    cout << "fFirstcycle = " << fFirstCycle << endl;
	  }
	} else {
	  if(fHaveQRT) {	// Using qrt signal.
	    fNLastQuartet = fNQuartet;
	    fNQuartet = (fNCycle-fFirstCycle)/4;
	    if((fNCycle-fFirstCycle)%4 == 0) { // Shouldn't happen
	      fNQRTProblems++;
	      if(fNQRTProblems > 10) {
		cout << "Shouldn't happen, cycle=" << fNCycle << "/" << fFirstCycle << endl;
		fHaveQRT = kFALSE; // False until a new QRT seen
		fNBits = 0;		       // Reset
		fNLastQuartet = fNQuartet; // Make sure LoadHelicity does not use
	      } else {
		cout << "Ignored " << fNQRTProblems << " problems" << endl;
	      }
	    }
	  } else { 		// Presumable pre qrt signal data
	    if((fNCycle-fFirstCycle)%4 == 3) {// Test if last in a quartet
	      if((abs(fQuartet[0]+fQuartet[3]-fQuartet[1]-fQuartet[2])==4)) {
		if(!fFoundQuartet) {
		  //	      fFirstCycle = fNCycle - 3;
		  cout << "Quartet potentially found, starting at cycle " << fFirstCycle
		       << endl;
		  fNQuartet = (fNCycle-fFirstCycle)/4;
		  fNLastQuartet = fNQuartet - 1; // Make sure LoadHelicity uses
		  fFoundQuartet = kTRUE;
		}
	      } else {
		if(fNCycle - fFirstCycle > 4) { // Not at start of run.  Reset
		  cout << "Lost quartet sync at cycle " << fNCycle << endl;
		  cout << fQuartet[0] << " "  << fQuartet[1] << " "  << fQuartet[2] << " "
		       << fQuartet[3] << endl;
		  fFirstCycle += 4*((fNCycle-fFirstCycle)/4); // Update, but don't change phase
		}
		fFoundQuartet = kFALSE;
		fNBits = 0;
		cout << "Searching for first of a quartet at cycle " << " " << fFirstCycle
		     << endl;
		cout << fQuartet[0] << " "  << fQuartet[1] << " "  << fQuartet[2] << " "
		     << fQuartet[3] << endl;
		fFirstCycle++;
	      }
	    } else {
	      fNLastQuartet = fNQuartet;
	      fNQuartet = (fNCycle-fFirstCycle)/4;
	    }
	  }
	}
	// Load the actual helicity.  Calibrate if not calibrated.
	fActualHelicity = kUnknown;
	// Here if we know we missed some earlier in the quartet, we need
	// to make sure we get here and call LoadHelicity for the missing
	// Cycles, reducing the missed count for each extra loadhelicity
	// call that we make.
	LoadHelicity(fReportedHelicity, fNCycle, missed);
	fLastReportedHelicity = fReportedHelicity;
	fIsNewCycle = kFALSE;
	//	cout << fTITime/250000000.0 << " " << fNCycle << " " << fReportedHelicity << endl;
	//	cout << fNCycle << ": " << fReportedHelicity << " "
	//	     << fPredictedHelicity << " " << fActualHelicity << endl;
      }
      // Ignore until a MPS Is found

    } else {			// No MPS found yet
      fActualHelicity = kUnknown;
    }
  } else {
    cout << "Initializing" << endl;
    fLastReportedHelicity = fReportedHelicity;
    fActualHelicity = kUnknown;
    fPredictedHelicity = kUnknown;
    fFirstEvTime = fTITime;
    fLastEvTime = fTITime;
    fLastMPSTime = fTITime;  // Not necessarily during the MPS
    fNCycle = 0;
    fFirstEvProcessed = kTRUE;
    fFoundMPS = kFALSE;
    fFoundQuartet = kFALSE;
    fIsNewCycle = kFALSE;
    fNBits = 0;
  }

  // Some sanity checks
  if(fActualHelicity < -5) {
    cout << "Actual Helicity never got defined" << endl;
  }
  if(fNBits < fMAXBIT) {
    if(fActualHelicity == -1 || fActualHelicity == 1) {
      cout << "Helicity of " << fActualHelicity << " reported prematurely at cycle " << fNCycle << endl;
    }
  }
  fLastActualHelicity = fActualHelicity;
  return 0;
}
//_____________________________________________________________________________
Int_t THcHelicity::End( THaRunBase* )
{
  // End of run processing. Write histograms.
  THcHelicityReader::End();

  //  for( Int_t i = 0; i < NHIST; ++i )
  //    fHisto[i]->Write();

  return 0;
}

//_____________________________________________________________________________
void THcHelicity::SetDebug( Int_t level )
{
  // Set debug level of this detector as well as the THcHelicityReader 
  // helper class.

  THaHelicityDet::SetDebug( level );
  fQWEAKDebug = level;
}

//_____________________________________________________________________________
void THcHelicity::LoadHelicity(Int_t reportedhelicity, Int_t cyclecount, Int_t missedcycles)
{
  //  static const char* const here = "THcHelicity::LoadHelicity";
  int quartetphase = (cyclecount-fFirstCycle)%4;
  fnQrt = quartetphase;

  //  if(!fFixFirstCycle) {
    if(fNQuartet - fNLastQuartet > 1) {	// If we missed a quartet
      if(fNBits< fMAXBIT) {	// and we haven't gotten the seed, start over
	cout << "fNBits = 0, missedcycles=" << missedcycles <<
	  "    " << fNLastQuartet << " " << fNQuartet << endl;
	fNBits = 0;
	return;
      }
    }
    //  }
  if(!fFoundQuartet) {		// Wait until we have found quad phase before starting
    return;			// to calibrate
  }
  // LoadHelicity is called first event of each cycle.
  // But only do it's thing if it is first cycle of quartet.
  // Need to instead have it do it's thing on the first event of a quartet.
  // But only for seed building.  Current logic is OK once seed is found.
  if(fNBits < fMAXBIT) {
    if(fNQuartet != fNLastQuartet) {
      // Sanity check fNQuartet == fNLastQuartet+1
      if(fNBits == 0) {
	cout << "Start calibrating at cycle " << cyclecount << endl;
	fRingSeed_reported = 0;
      }
      // Do phase stuff right here
      if((fReportedHelicity == kPlus && (quartetphase==0 || quartetphase == 3))
	 || (fReportedHelicity == kMinus && (quartetphase==1 || quartetphase == 2))) {
	fRingSeed_reported = ((fRingSeed_reported<<1) | 1) & 0x3FFFFFFF;
	//	cout << "                 " << fNQuartet << " 1" << endl;
      } else {
	fRingSeed_reported = (fRingSeed_reported<<1) & 0x3FFFFFFF;
	//	cout << "                 " << fNQuartet << " 0" << endl;
      }
      fNBits++;
      if(fReportedHelicity == kUnknown) {
	fNBits = 0;
	fRingSeed_reported = 0;
      } else if (fNBits==fMAXBIT) {
	cout <<   "Seed Found    " << bitset<32>(fRingSeed_reported) << " at cycle " << cyclecount << " with first cycle " << fFirstCycle << endl;
	if(fglHelicityScaler) {
	  cout << "Scaler Seed " << bitset<32>(fScalerSeed) << endl;
	}
	Int_t backseed = GetSeed30(fRingSeed_reported);
	cout << "Seed at cycle " << fFirstCycle << " should be " << hex << backseed << dec << endl;
	// Create the "actual seed"
	fRingSeed_actual = fRingSeed_reported;
	for(Int_t i=0;i<fHelDelay/4; i++) {
	  fRingSeed_actual = RanBit30(fRingSeed_actual);
	}
	fQuartetStartHelicity = (fRingSeed_actual&1)?kPlus:kMinus;
	fQuartetStartPredictedHelicity = (fRingSeed_reported&1)?kPlus:kMinus;
      }
      fActualHelicity = kUnknown;
    } // Need to change this to build seed even when not at start of quartet
  } else {
    if(quartetphase == 0) {
      // If quartetphase !=, the seeds will alread have been advanced
      // except that we won't have made the initial 
      //      cout << "Advancing seed B " << fNBits << endl;
      fRingSeed_reported = RanBit30(fRingSeed_reported); 
      fRingSeed_actual = RanBit30(fRingSeed_actual);

      fActualHelicity = (fRingSeed_actual&1)?kPlus:kMinus;
      fPredictedHelicity = (fRingSeed_reported&1)?kPlus:kMinus;
      //      if(fTITime/250000000.0 > 380.0) cout << fTITime/250000000.0 << " " << fNCycle << " " << hex <<
      //					fRingSeed_reported << " " << fRingSeed_actual << dec << endl;
      if(fReportedHelicity != fPredictedHelicity) {
	cout << "Helicity prediction failed " << fReportedHelicity << " "
	     << fPredictedHelicity << " " << fActualHelicity << endl;
	cout << bitset<32>(fRingSeed_reported) << " " << bitset<32>(fRingSeed_actual) << endl;
	fNBits = 0;		// Need to reaquire seed
	fActualHelicity = kUnknown;
	fPredictedHelicity = kUnknown;
      }
      fQuartetStartHelicity = fActualHelicity;
      fQuartetStartPredictedHelicity = fPredictedHelicity;
    }
    fActualHelicity = (quartetphase==0||quartetphase==3)?
      fQuartetStartHelicity:-fQuartetStartHelicity;
    fPredictedHelicity = (quartetphase==0||quartetphase==3)?
      fQuartetStartPredictedHelicity:-fQuartetStartPredictedHelicity;
  }
  return;
}
//_____________________________________________________________________________
Int_t  THcHelicity::RanBit30(Int_t ranseed)
{
  
  UInt_t bit7    = (ranseed & 0x00000040) != 0;
  UInt_t bit28   = (ranseed & 0x08000000) != 0;
  UInt_t bit29   = (ranseed & 0x10000000) != 0;
  UInt_t bit30   = (ranseed & 0x20000000) != 0;

  UInt_t newbit = (bit30 ^ bit29 ^ bit28 ^ bit7) & 0x1;

  
  if(ranseed<=0) {
    if(fQWEAKDebug>1)
      std::cerr<<"ranseed must be greater than zero!"<<"\n";

    newbit = 0;
  }
  ranseed =  ( (ranseed<<1) | newbit ) & 0x3FFFFFFF;
  //here ranseed is changed
  if(fQWEAKDebug>1)
    {
      cout<< "THcHelicity::RanBit30, newbit="<<newbit<<"\n";
    }

  return ranseed;

}
//_____________________________________________________________________________
Int_t  THcHelicity::GetSeed30(Int_t currentseed)
/* Back track the seed by 30 samples */
{
#if 1
  Int_t seed = currentseed;
  for(Int_t i=0;i<30;i++) {
    UInt_t bit1    = (seed & 0x00000001) != 0;
    UInt_t bit8    = (seed & 0x00000080) != 0;
    UInt_t bit29   = (seed & 0x10000000) != 0;
    UInt_t bit30   = (seed & 0x20000000) != 0;
    
    UInt_t newbit30 = (bit30 ^ bit29 ^ bit8 ^ bit1) & 0x1;
    seed = (seed >> 1) | (newbit30<<29);
  }
#else
  Int_t bits = currentseed;
  Int_t seed=0;
  for(Int_t i=0;i<30;i++) {
    Int_t val;
    // XOR at virtual position 0 and 29
    if(i==0) {
      val = ((bits & (1<<(i)))!=0) ^ ((bits & (1<<(i+29)))!=0);
    } else {
      val = ((bits & (1<<(i)))!=0) ^ ((seed & (1<<(i-1)))!=0);
    }
    if(i<=1) {
      val = ((bits & (1<<(1-i)))!=0) ^ val;
    } else {
      val = ((seed & (1<<(i-2)))!=0) ^ val;
    }
    if(i<=22) {
      val = ((bits & (1<<(i-22)))!=0) ^ val;
    } else {
      val = ((seed & (1<<(i-23)))!=0) ^ val;
    }
    seed |= (val<<i);
  }
#endif
  return seed;
}

ClassImp(THcHelicity)