//
// Pibero Djawwotho <pibero@indiana.edu>
// Indiana University
// 24 April 2007
//

#ifndef Upsilon_hh
#define Upsilon_hh

#include <cstdio>
#include <cmath>
//class TH1;
class TNtuple;
using namespace std;

//class TH1;
#ifdef __ROOT__
//
// Compile for RCF environment
//
class TH1;
class TFile;
#include "TH1F.h"
#include "TFile.h"
#include "StThreeVectorF.hh"
//#include "TRefArray.h"

//#include "StDaqLib/TRG/trgStructures2007.h"
//typedef TrgDataType2007 TrgDataType;
#include "StDaqLib/TRG/trgStructures2008.h"
typedef TrgDataType2008 TrgDataType;
#else
//
// Compile for L2 machine
//
#include "/home/startrg/trg/trg_soft_dev/include/trgStructures.h"
#endif

#include "bemcTower.h"
#include "bemcPatch.h"


struct struct_BemcTower {
  float x;
  float y;
  float z;
  float E;
  float adc;
  float eta;
  float phi;
  int softid;
  int numberOfNeighbors;
  int neighbor[8];
};

struct struct_matched_track {
  float dedx;
  float nSigE;
  float nSigPi;
  float nSigP;
  float nSigK;
  float eta;
  float phi;
  float project_eta;
  float project_phi;
  int project_softid[3][3];
  StThreeVectorF p;
//  float dca;
  int charge;
  int nHitsFit;

};

struct struct_myevent {
	float VpdVertex;
	float ZdcVertex;
	float BbcVertex;
	float vz;
  vector<struct_BemcTower> all_tower_list;
  vector<struct_matched_track> matched_track_list;
};

struct BemcCluster {
  float x;
  float y;
  float z;
  float E;
};

struct Eventups {
  float runNumber;		// Run number
  float vpdVertex;		// VPD vertex
  float zdcVertex;		// ZDC vertex
  float bbcVertex;		// BBC vertex
  float id1;			// softId of L0 trigger tower
  float id2;			// softId of L2 trigger tower
  float eta1;			// eta of L0 trigger tower
  float eta2;			// eta of L2 trigger tower
  float phi1;			// phi of L0 trigger tower
  float phi2;			// phi of L2 trigger tower
  float mult1;			// Multiplicity of L0 trigger tower
  float mult2;			// Multiplicity of L2 trigger tower
  float etrig1;			// Energy of L0 trigger tower (GeV)
  float etrig2;			// Energy of L2 trigger tower (GeV)
  float ecluster1;		// Energy of L0 cluster (GeV)
  float ecluster2;		// Energy of L2 cluster (GeV)
  float invMass;		// Invariant mass (GeV)
  float cosTheta;		// cos(theta)
  float time;			// Event processing time
  float evSeen;			// Events seen (event number)
  float evAccept;		// Events accepted
  float numberOfHotTowers;	// Number of hot towers killed dynamically
  int numberOfL2Candidates;    //total upsilon candidates within the cuts, we do not quit for each event
};

class Upsilon {
public:
  Upsilon();
  ~Upsilon();

  void init(int runNumber, int* userInt, float* userFloat);
  bool run(TrgDataType* trgData, unsigned short* bemcData);
  void finish();

private:

  TH1* mCandidates;
  TNtuple* mUps;
  TFile *f;
  static const char* fVersion;
  static const float CPU_MHZ;
  static const char* fHeader;
  static const int fSizeOfHeader;

  enum { NUMBER_OF_TOWERS = 4800, NUMBER_OF_PATCHES = 300, BIT_SHIFT = 4, NUMBER_OF_TOWERS_PER_CLUSTER = 3 };

  void findSeedTowers(int* L0_HT, int* L2_HT, int& numberOfTowersL0, int& numberOfTowersL2);
  void calcCluster(int daqId, BemcCluster& cluster);
  float calcEnergy(int daqId) const;
  bool towerUnmasked(int daqId) const;
  float vpdVertex() const;
  float zdcVertex() const;
  float bbcVertex() const;
  void readBemcTower();
  void readBemcStatus();
  void readBemcKillTable();
  bool hotTower(int daqId);
  void findHotTowers();
  void moment(int n, int* data, float& mean, float& sigma);
  bool checkSoftId(int softId) const;
  bool checkDaqId(int daqId) const;
  bool checkPatch(int patch) const;
  bool checkCrate(int crate) const;
  bool checkCrateSeq(int crateSeq) const;
  bool checkCratePatch(int cratePatch) const;
  bool checkGain(float gain) const;
  bool checkXYZ(float x, float y, float z) const;
  bool checkEtaPhi(float eta, float phi) const;
  bool checkNumberOfNeighbors(int numberOfNeighbors) const;
  void fill_all_towers();


  FILE* fLog;
  char* fTuple;
  int fMaxEvents;
  TrgDataType* trgData;
  unsigned short* bemcData;
  BemcTower bemcTower[NUMBER_OF_TOWERS];
  int daqIdFromSoftId[NUMBER_OF_TOWERS+1];
  BemcPatch bemcPatch[NUMBER_OF_PATCHES];
  int pedestalShift;
  time_t fStartTime;
  time_t fStopTime;
  int fRunNumber;
  float fVpdVertex;
  float fZdcVertex;
  float fBbcVertex;
  int fEventsSeen;
  int fEventsAccepted;
  //int fnumberOfL2Candidates;//dd

public:
  // Dynamic masking of hot towers
  int fHits[NUMBER_OF_TOWERS];
  bool fHot[NUMBER_OF_TOWERS];
  int fNumberOfHotTowers;
  char fHotLog[8192];


  int fNumberOfL2Candidates;//dd
  vector<pair<int,int> > mL2Candidates;
  int mTest;//this is to test ddas

	struct_myevent  myevent;


private:
  // float parameters
  float fMinL0ClusterEnergy;
  float fMinL2ClusterEnergy;
  float fMinInvMass;
  float fMaxInvMass;
  float fMaxCosTheta;

  // int parameters
  int fL0SeedThreshold;
  int fL2SeedThreshold;
  int fHotThreshold;
  int fUseVertex;
  int fMaxHotTowers;
};

inline Upsilon::Upsilon()
{
  printf("Upsilon: ctor called\n");
  fStartTime = 0;
  fStopTime = 0;
  fLog = 0;
  fTuple = 0;
  fMaxEvents = 0;
  trgData = 0;
  bemcData = 0;
  fRunNumber = 0;
  fVpdVertex = 0;
  fZdcVertex = 0;
  fBbcVertex = 0;
  fEventsSeen = 0;
  fEventsAccepted = 0;
  //fnumberOfL2Candidates =0;//dd
}

inline Upsilon::~Upsilon()
{
  printf("Upsilon: dtor called\n");
}

inline float Upsilon::calcEnergy(int daqId) const
{
  return (bemcData[daqId] < bemcTower[daqId].pedestal) ?
    0 : (bemcData [daqId] - bemcTower[daqId].pedestal) * bemcTower[daqId].gain;
}

inline bool Upsilon::towerUnmasked(int daqId) const
{
  return (bemcTower[daqId].towerUnmasked &&
	  bemcTower[daqId].patchUnmaskedInHT &&
	  bemcTower[daqId].patchUnmaskedInSum);
}

inline bool Upsilon::checkSoftId(int softId) const
{
  return (1 <= softId && softId <= 4800);
}

inline bool Upsilon::checkDaqId(int daqId) const
{
  return (0 <= daqId && daqId < 4800);
}

inline bool Upsilon::checkPatch(int patch) const
{
  return (0 <= patch && patch < 300);
}

inline bool Upsilon::checkCrate(int crate) const
{
  return (1 <= crate && crate <= 30);
}

inline bool Upsilon::checkCrateSeq(int crateSeq) const
{
  return (0 <= crateSeq && crateSeq < 160);
}

inline bool Upsilon::checkCratePatch(int cratePatch) const
{
  return (0 <= cratePatch && cratePatch < 10);
}

inline bool Upsilon::checkGain(float gain) const
{
  return (0 <= gain && gain < 0.06); // GeV/ADC
}

inline bool Upsilon::checkXYZ(float x, float y, float z) const
{
  return (fabs(x) < 226 && fabs(y) < 226 && fabs(z) < 255); // cm
}

inline bool Upsilon::checkEtaPhi(float eta, float phi) const
{
  return (fabs(eta) < 1 && fabs(phi) < M_PI);
}

inline bool Upsilon::checkNumberOfNeighbors(int numberOfNeighbors) const
{
  return (numberOfNeighbors == 8 || numberOfNeighbors == 5);
}

//
// From Lijuan Ruan via Mark Heinz, 2007/04/10
//
inline float Upsilon::vpdVertex() const
{
  unsigned char* VPD = trgData->rawTriggerDet[0].VPD;
  unsigned char fastEast = 0;
  for (int i =  8; i < 16; ++i) if (fastEast < VPD[i]) fastEast = VPD[i];
  for (int i = 24; i < 32; ++i) if (fastEast < VPD[i]) fastEast = VPD[i];
  unsigned char fastWest = 0;
  for (int i = 40; i < 48; ++i) if (fastWest < VPD[i]) fastWest = VPD[i];
  for (int i = 56; i < 64; ++i) if (fastWest < VPD[i]) fastWest = VPD[i];
  float fastDiff = fastEast - fastWest;
  return (15.11 - fastDiff) / 1.136;
}

//
// From Frank Laue, 2007/04/12
//
inline float Upsilon::zdcVertex() const
{
  unsigned char* ZDC = trgData->rawTriggerDet[0].ZDC;
  float timeEast = ZDC[8];
  float timeWest = ZDC[9];
  float timeDiff = timeWest - timeEast;
  return (timeDiff + 4.75) / 0.332;
}

inline float Upsilon::bbcVertex() const
{
  unsigned char* BBC = trgData->rawTriggerDet[0].BBC;

  //
  // Taken from $STAR/StRoot/StEvent/StTriggerData2005.cxx
  //
  static const int q_map[2][24] = {
    { 8  , 5  , 4  , 40 , 37 , 36 , 7  , 6  ,
      3  , 2  , 1  , 39 , 38 , 35 , 34 , 33 ,
      72 , 71 , 70 , 69 , 68 , 67 , 66 , 65 },
    { 24 , 21 , 20 , 56 , 53 , 52 , 23 , 22 ,
      19 , 18 , 17 , 55 , 54 , 51 , 50 , 49 ,
      88 , 87 , 86 , 85 , 84 , 83 , 82 , 81 }
  };

  static const int t_map[2][24] = {
    { 16 , 13 , 12 , 48 , 45 , 44 , 15 , 14 ,
      11 , 10 , 9  , 47 , 46 , 43 , 42 , 41 ,
      80 , 79 , 78 , 77 , 76 , 75 , 74 , 73 },
    { 32 , 29 , 28 , 64 , 61 , 60 , 31 , 30 ,
      27 , 26 , 25 , 63 , 62 , 59 , 58 , 57 ,
      96 , 95 , 94 , 93 , 92 , 91 , 90 , 89 }
  };

  //
  // Taken from $STAR/StRoot/StEvent/StBbcTriggerDetector.cxx
  //
  enum { east = 0, west = 1 };

  unsigned short tdcEarliestEast = 0;
  unsigned short tdcEarliestWest = 0;

  for (int i = 0; i < 16; ++i) {
    unsigned char adc = BBC[q_map[east][i]-1];
    unsigned char tdc = BBC[t_map[east][i]-1];

    if (tdc < 245 && tdc > tdcEarliestEast && adc > 5) tdcEarliestEast = tdc;
  }

  for (int i = 24; i < 40; ++i) {
    unsigned char adc = BBC[q_map[west][i-24]-1];
    unsigned char tdc = BBC[t_map[west][i-24]-1];
    if (tdc < 245 && tdc > tdcEarliestWest && adc > 5) tdcEarliestWest = tdc;
  }

  return 2 * (tdcEarliestWest - tdcEarliestEast);
}

#endif
