#ifndef HMDCLOOKUPTB_H
#define HMDCLOOKUPTB_H
#include "TObject.h"
#include "hparset.h"
#include "hmdcgeomobj.h"
#include "hlocation.h"
#include "hmdcsizescells.h"
#include <stdlib.h>
class TH2C;
class TObjArray;
class HCategory;
class HMdcGeomPar;
class HMdcGetContainers;
class HMdcLayerGeomPar;
class HMdcSizesCells;
class HSpecGeomPar;
class HMdcClus;
class HMdcCluster;
class HMdcClustersArrs;
class HMdcList12GroupCells;
class HMdcClFnStack;
class HMdcClFnStacksArr;
class HMdcSecListCells;
class HMdcDriftTimeParSec;
class HMdcLayListCells;
class HStart2GeomPar;
class HMdcLookUpTbCell: public TObject {
  protected:
    UShort_t  nLines;          
    UShort_t  line;            
    UShort_t  yBinMin;         
    UShort_t  yBinMax;         
    UShort_t *xBinMin;         
    UShort_t *xBinMax;         
    Float_t   alphaMean;       
    Float_t   distCutFT;       
    Float_t   distCut1T;       
    Float_t   distCutVF;       
    
    Double_t  dDistMinCut;     
    Double_t  dDistMaxCut;     
    Double_t  dDistMinCut2VF;  
    Double_t  dDistMaxCut2VF;  
  public:
    HMdcLookUpTbCell(void);
    ~HMdcLookUpTbCell(void);
    void     clear(void) {line=0;}
    void     init(Int_t yBinMinT, Int_t yBinMaxT);
    Bool_t   addLine(UShort_t nc1, UShort_t nc2);
    UShort_t getNLines(void) const             {return line;}
    UShort_t getYBinMin(void) const            {return yBinMin;}
    UShort_t getYBinMax(void) const            {return yBinMax;}
    UShort_t getXBinMin(UInt_t yb) const       {return xBinMin[yb];}
    UShort_t getXBinMax(UInt_t yb) const       {return xBinMax[yb];}
    void     setAlphaMean(Double_t al)         {alphaMean = al;}
    Double_t getAlphaMean(void) const          {return alphaMean;}
    void     setDistCutFT(Double_t ct)         {distCutFT = ct;}
    void     setDistCut1T(Double_t ct)         {distCut1T = ct;}
    void     setDistCut1TVF(Double_t ct)       {distCutVF = ct;}
    void     setTdcTDistAndCuts1T(Double_t d);
    void     setTdcTDistAndCutsFT(Double_t d);
    Double_t getDDistMinCut(void) const        {return dDistMinCut;}
    Double_t getDDistMaxCut(void) const        {return dDistMaxCut;}
    Double_t getDDistMinCut2VF(void) const     {return dDistMinCut2VF;}
    Double_t getDDistMaxCut2VF(void) const     {return dDistMaxCut2VF;}
    
    ClassDef(HMdcLookUpTbCell,0)
};
class HMdcLookUpTbLayer: public TObject {
  protected:
    HMdcSizesCellsLayer* pSCellLay;
    HMdcLookUpTbCell*    pLTCellArr; 
    Int_t    nCells;           
    struct DistCalcLuTb {
      Double_t yt;             
      Double_t zt;             
      Double_t C1x;            
      Double_t C1y;            
      Double_t C1;             
      Double_t C2x;            
      Double_t C2y;            
      Double_t C2;             
      Double_t yVertex;        
      Double_t zVertex;        
      Double_t yTp[250];       
      Double_t zTp[250];       
    };
    DistCalcLuTb  layPart1;
    DistCalcLuTb *layPart2;
    
    DistCalcLuTb  *currLayPart;
    
    
    Int_t    lTargPnt;       
    Double_t yWirePos;       
    Double_t dDmin;          
    Double_t dDmax;          
    
  public:
    HMdcLookUpTbLayer(Int_t sec, Int_t mod, Int_t layer);
    ~HMdcLookUpTbLayer(void);
    HMdcLookUpTbCell& operator[](Int_t i) {return pLTCellArr[i];}
    Int_t           getSize(void);
    void            setMinDistLUTb(Int_t lPart,HGeomVector& t,Double_t* carr);
    void            setNTargPnts(Int_t n)           {lTargPnt = n;}
    Double_t*       getYTargetArr(void)             {return layPart1.yTp;}
    Double_t*       getZTargetArr(void)             {return layPart1.zTp;}
    Double_t*       getYTargetArrP2(void)           {return layPart2==NULL ? NULL : layPart2->yTp;}
    Double_t*       getZTargetArrP2(void)           {return layPart2==NULL ? NULL : layPart2->zTp;}
    void            setVertexPoint(Int_t vp);
    void            setCurrentCell(Int_t cell);
    inline Bool_t   drTmTest(Double_t xb,Double_t yb) const;
    inline Bool_t   drTmTest2(Double_t xb,Double_t yb,Double_t corr=0.) const;
    inline void     transToRotLay(Double_t xb,Double_t yb,Double_t &ybl,Double_t &zbl) const;
    DistCalcLuTb   *getLayerPart2Par(void)          {return layPart2;}
    ClassDef(HMdcLookUpTbLayer,0)
};
inline Bool_t HMdcLookUpTbLayer::drTmTest(Double_t xb,Double_t yb) const {
  
  
  
  Double_t y      = currLayPart->C1x*xb + currLayPart->C1y*yb + currLayPart->C1;
  Double_t z      = currLayPart->C2x*xb + currLayPart->C2y*yb + currLayPart->C2;
  Double_t dyDdz  = (y - currLayPart->yVertex)/(z - currLayPart->zVertex);
  Double_t ct     = 1.+dyDdz*dyDdz;
  Double_t dDist2 = y-dyDdz*z - yWirePos;
  dDist2 *= dDist2;
  return dDist2>dDmin*dDmin*ct && dDist2<dDmax*dDmax*ct;
}
inline Bool_t HMdcLookUpTbLayer::drTmTest2(Double_t xb,Double_t yb,Double_t corr) const {
  
  
  
  
  
  
  
  
  Double_t y      = currLayPart->C1x*xb + currLayPart->C1y*yb + currLayPart->C1;
  Double_t z      = currLayPart->C2x*xb + currLayPart->C2y*yb + currLayPart->C2;
  Double_t dyDdz  = (y - currLayPart->yVertex)/(z - currLayPart->zVertex);
  Double_t ct     = 1.+dyDdz*dyDdz;
  Double_t dDist2 = y-dyDdz*z - yWirePos;
  dDist2 *= dDist2;
  if(corr<=0.) return dDist2>dDmin*dDmin*ct && dDist2<dDmax*dDmax*ct;
  Double_t dDminCorr = dDmin>corr ? dDmin-corr : 0.;
  Double_t dDmaxCorr = dDmax+corr;
  
  return dDist2>dDminCorr*dDminCorr*ct && dDist2<dDmaxCorr*dDmaxCorr*ct;
}
inline void HMdcLookUpTbLayer::transToRotLay(Double_t xb,Double_t yb,Double_t &ybl,Double_t &zbl) const {
  
  
  ybl = layPart1.C1x*xb + layPart1.C1y*yb + layPart1.C1;
  zbl = layPart1.C2x*xb + layPart1.C2y*yb + layPart1.C2;
}
class HMdcLookUpTbMod : public TObject {
  protected:
    TObjArray* array;      
    Int_t      nLayers;    
  public:
    HMdcLookUpTbMod(Int_t sec, Int_t mod);
    ~HMdcLookUpTbMod(void);
    HMdcLookUpTbLayer& operator[](Int_t i) {return *static_cast<HMdcLookUpTbLayer*>((*array)[i]);}
    Int_t getSize(void);
    void  setNLayers(Int_t nl) {nLayers=nl;}
    Int_t getNLayers(void)     {return nLayers;}
  ClassDef(HMdcLookUpTbMod,0)
};
class HMdcLookUpTbSec : public TObject {
  protected:
    Int_t               sector;          
    Int_t               segment;         
    Int_t               nSegments;       
    Int_t               nModules;        
    Int_t               maxNModules;     
    Bool_t              isCoilOff;
                                         
    Int_t               nBinX;           
    Double_t            xLow;            
    Double_t            xUp;             
    Double_t            xStep;           
    Int_t               nBinY;           
    Double_t            yLow;            
    Double_t            yUp;             
    Double_t            yStep;           
    Float_t             xFirstBin;       
    Float_t             yFirstBin;       
    Double_t           *xBinsPos;        
    Double_t           *yBinsPos;        
    Int_t               size;            
    static UChar_t     *hPlMod[4];       
    static Int_t        hPlModsSize;     
    Int_t               sizeBAr;         
    static Int_t        sizeBArSt;       
    static UChar_t     *plotBArSc;       
    UInt_t              maxBinBAr4Sc;    
    UInt_t              minBinBAr4Sc;    
    static UChar_t     *plotBArM[4];     
    UInt_t              maxBinBAr4M[4];  
    UInt_t              minBinBAr4M[4];  
    UInt_t*             xMin[4];         
    UInt_t*             xMax[4];         
    HMdcClFnStack      *stack;           
    HMdcClFnStacksArr  *stacksArr;       
    TObjArray          *array;           
    HCategory          *fClusCat;        
    HLocation           locClus;         
    Bool_t              isGeant;         
    Bool_t              trackListFlag;   
    Bool_t              noFiredCells;    
    Int_t               maxAmp[4];       
    
    HMdcSecListCells*   pListCells;      
    
    Int_t               minAmp[4];       
    Int_t               nMods;           
    Int_t               typeClFinder;    
                                         
                                         
    Int_t               neighbBins[8];
    HMdcPlane           prPlane;         
    Float_t             target[3];       
    Float_t             eTarg[3];        
    HGeomVector         targVc[3];       
                                         
                                         
    Bool_t              doVertexFn;      
    Double_t            dDistCutVF;      
    Int_t               levelVertF;      
    Int_t               levelVertFPP;    
    Int_t               lTargPnt;        
    Int_t               indFirstTPnt;
    Int_t               indLastTPnt;
    HGeomVector         targetPnts[250];
    Double_t            vertZErr;        
    Int_t              *vertexStat;      
    Int_t               vertexPoint;     
    
    Int_t               nClusters;       
    TH2C*               hist;            
    Int_t               plBining;
    
    HMdcClustersArrs*   pClustersArrs;   
    Int_t               nModSeg[2];
    Int_t               clusArrSize;     
    HMdcCluster*        clusArr;         
    Int_t               nClsArr;         
    static Short_t*     clusIndM1;       
    static Int_t        clIndArrSzM1;    
    HMdcCluster*        clusArrM1;       
    Int_t               nClsArrM1;       
    static Short_t*     clusIndM2;       
    static Int_t        clIndArrSzM2;    
    HMdcCluster*        clusArrM2;       
    Int_t               nClsArrM2;       
    
    Int_t               clusArrInd;      
                                         
    HMdcCluster*        cClusArr;        
    Int_t*              cNClusArr;       
    Int_t               cSeg;
    Int_t               cMod1;
    Int_t               cMod2;
    UChar_t*            cPlModF;
    UChar_t*            cPlModS;
    Int_t               cMod;
    UChar_t*            cPlMod;
    Short_t*            clusInd;
        
    HMdcLookUpTbMod*    cFMod;           
    UChar_t*            cHPlModM;        
    HMdcCluster*        clus;            
    Bool_t              isClstrInited;   
    UInt_t*             cXMinM;          
    UInt_t*             cXMaxM;          
    UInt_t*             pXMinM;          
    UInt_t*             pXMaxM;          
    UChar_t*            cPlotBAr;        
    Int_t               nLMaxCl;         
    Int_t               nLMinCl;         
    UShort_t*           xMaxCl;          
    UShort_t*           xMinCl;          
    HMdcClus*           fClus;           
    Int_t               nFirstClust;     
    Bool_t              isSlotAv[2];     
    Int_t               layerOrder[6];   
    Int_t               module;          
    Int_t               layer;           
    Int_t               cell;            
    Float_t             tdcTime;         
    UChar_t             add;             
    HMdcLayListCells*   pLayLCells;
    HMdcLookUpTbLayer*  pLUTLayer;
    HMdcLookUpTbCell*   pLUTCell;
    HMdcSizesCellsSec*  pSCellSec;
    HMdcDriftTimeParSec* pDriftTimeParSec;
    Double_t            constUncert;     
    Double_t            dDCutCorr[4][6]; 
    Double_t            dDistCut;        
    Double_t           *yDDistCorr;      
    Bool_t              useDriftTime;    
    Char_t              fakeSuppFlag;    
    
  public:
    HMdcLookUpTbMod& operator[](Int_t i) {return *static_cast<HMdcLookUpTbMod*>((*array)[i]);}
    Int_t        getSize(void);
    Int_t        getNClusters(void) const            {return nClusters;}
    Int_t        getMaxClus(Int_t m=-1) const;
    Int_t        getNBinX(void) const                {return nBinX;}
    Double_t     getXlow(void) const                 {return xLow;}
    Double_t     getXup(void) const                  {return xUp;}
    Int_t        getNBinY(void) const                {return nBinY;}
    Double_t     getYlow(void) const                 {return yLow;}
    Double_t     getYup(void) const                  {return yUp;}
    void         clearwk(void);
    Int_t        findClusters(Int_t* imax);
    void         setParPlane(const HMdcPlane &plane) {prPlane.setPlanePar(plane);}
    void         setTargetF(const HGeomVector& vec)  {targVc[0]=vec;}
    void         setTargetL(const HGeomVector& vec)  {targVc[1]=vec;}
    HMdcPlane&   getPrPlane(void)                    {return prPlane;}
    const        HGeomVector& getTargetF(void)       {return targVc[0];}
    const        HGeomVector& getTargetL(void)       {return targVc[1];}
    TH2C*        fillTH2C(const Char_t* name,const Char_t* title,Int_t type=0,Int_t bining=2);
    void         setTypeClFinder(Int_t type)         {typeClFinder = type;}
    Int_t        getTypeClFinder(void)               {return typeClFinder;}
    Int_t        xBinNum(Double_t x)                 {return Int_t((x-xLow)/xStep);}
    Int_t        yBinNum(Double_t y)                 {return Int_t((y-yLow)/yStep);}
    Int_t        xBinNumInBounds(Double_t x);
    Int_t        yBinNumInBounds(Double_t y);
    Bool_t       calcXYBounds(Double_t& xL,Double_t& xU,Double_t& yL,Double_t& yU);
    void         setPrPlotSize(Double_t xL,Double_t xU,Double_t yL,Double_t yU);
    
    HMdcLookUpTbSec(Int_t sec, Int_t nSegs, Int_t inBinX, Int_t inBinY);
    void         setClusCat(HCategory* cat)          {fClusCat  = cat;}
    void         setStack(HMdcClFnStack* st)         {stack     = st;}
    void         setStacksArr(HMdcClFnStacksArr* sA) {stacksArr = sA;}
    void         setCoilFlag(Bool_t flg)             {isCoilOff = flg;}
    void         calcTarget(Double_t* targLenInc);
    Bool_t       calcLookUpTb(Bool_t quiet);
    void         fillTrackList(Bool_t fl)            {trackListFlag = fl;}
    void         calcTdcDrDist(void);
    void         findVertex(void);
    void         findSecVertex(void);
    void         setVertexStat(Int_t *vs)            {vertexStat = vs;}
    void         calcVertexFnTarg(Int_t nTrPnts,HGeomVector* trPnts);
    void         setVertexPoint(Int_t vp);
    void         setVertexZErr(Double_t vze)         {vertZErr = vze;}
    
  protected:
    HMdcLookUpTbSec(void) : vertexStat(NULL) {}
    ~HMdcLookUpTbSec(void);
    Bool_t       fillLookUpTb(Int_t m, Int_t l,HMdcTrapPlane& cellPr,
                                               HMdcLookUpTbCell& fCell);
    void         clearPrArrs(void);
    void         clearPrMod(Int_t mod);
    void         clearPrMod(void);
    void         clearPrModInSec(void);
    void         setDrTimeCutYCorr(Double_t corr);
    void         fillClusCat(Int_t mod, Int_t segp, Int_t tpClFndr);
    void         findClusInSeg(Int_t seg);
    void         findClusInSec(void);
    void         findClusInMod(Int_t mod);
    Int_t        getClusterSlot(Int_t seg, HMdcList12GroupCells& list);
    void         fillModWiresList(Int_t mod, HMdcList12GroupCells& list);
    Bool_t       fillModCluster(Int_t mod);
    Bool_t       fillSegCluster(void);
    Bool_t       fillSecCluster(void);
    void         makeModPlot(Int_t mod);
    void         makeSPlot(void);
    void         makeS1PlotAmpCut(void);
    void         makeLayProjV0(void);
    void         makeLayProjV1(void);
    void         makeLayProjV1b(void);
    void         makeLayProjV2(void);
    void         findClusInSeg1(void);
    void         mergeClusInMod(Int_t mod);
    void         mergeClusMod1to2(void);
    void         mergeClusInSeg(void);
    void         mergeClusInSec(void);
    void         testClusMod12toSeg(void);
    void         scanPlotInMod(Int_t mod);
    Bool_t       calcMixedClusterFixedLevel(Int_t nBin);
    Bool_t       calcMixedClusterFloatLevel(Int_t nBin);
    void         scanPlotInSeg1(Int_t seg, UChar_t* plotBAr);
    Bool_t       calcClusterInSecFixedLevel(Int_t nBin);
    Bool_t       calcClusterInSecFloatLevel(Int_t nBin);
    Bool_t       calcClusterInSegFixedLevel(Int_t nBin);
    Bool_t       calcClusterInSegFloatLevel(Int_t nBin);
    Bool_t       calcClusterInSeg1FixedLevel(Int_t nBin);
    Bool_t       calcClusterInSeg1FloatLevel(Int_t nBin);
    void         testSeg1ModClMatching(void);
    Bool_t       calcClusterInModFixedLevel(Int_t nBin);
    Bool_t       calcClusterInModFloatLevel(Int_t nBin);
    void         calcClParam(void);
    void         initCluster(Int_t nBin);
    void         reinitCluster(Int_t nBin);
    void         initCluster(Int_t nBin,UChar_t amp);
    void         reinitCluster(Int_t nBin,UChar_t amp);
    void         addBinInCluster(Int_t nBin,UChar_t wt);
    void         initClusterT2(Int_t nBin,UChar_t amp);
    void         reinitClusterT2(Int_t nBin,UChar_t amp);
    void         addBinInClusterT2(Int_t nBin,UChar_t wt);
    Bool_t       increaseClusterNum(void);
    Bool_t       setLayerVar(void);
    Bool_t       setNextCell(void);
    void         removeGhosts(void);
    void         testBinForVertexF(Int_t bx, Int_t by);
    void         testBinForVertex(Int_t bx, Int_t by);
    void         addToClusCounter(Int_t clusAmp);
    void         markFakesNBins(Int_t clusAmp,Int_t arrSize,Int_t *nUnWiresCut);
    void         markFakes(Int_t clusAmp,Int_t arrSize,Int_t *nRlWiresCut);
    void         markReals(Int_t clusAmp,Int_t arrSize,const Int_t *nUnWiresCut);
    
    inline void  setCurrentArraySec(void);
    inline void  setCurrentArrayMod1(void);
    inline void  setCurrentArrayMod2(void);
  ClassDef(HMdcLookUpTbSec,0)
};
inline void HMdcLookUpTbSec::setCurrentArraySec(void) {
  cClusArr   = clusArr;
  cNClusArr  = &nClsArr;
  clusArrInd = 0;
}
inline void HMdcLookUpTbSec::setCurrentArrayMod1(void) {
  cClusArr   = clusArrM1;
  cNClusArr  = &nClsArrM1;
  clusArrInd = 1;
}
inline void HMdcLookUpTbSec::setCurrentArrayMod2(void) {
  cClusArr   = clusArrM2;
  cNClusArr  = &nClsArrM2;
  clusArrInd = 2;
}
class HMdcLookUpTb : public HParSet {
  protected:
    static HMdcLookUpTb* fMdcLookUpTb;
    TObjArray*           array;           
    Bool_t               isCoilOff;
    Int_t                typeClFinder;    
                                          
                                          
    HMdcGetContainers*   fGetCont;
    HMdcSizesCells*      fSizesCells;
    HMdcGeomPar*         fMdcGeomPar;
    HSpecGeomPar*        fSpecGeomPar;
    HMdcLayerGeomPar*    fLayerGeomPar;
    HStart2GeomPar*      fStartGeomPar;
    HCategory*           fMdcClusCat;     
    Double_t             targLenInc[2];
    Bool_t               quietMode;
    HMdcClFnStack*       stack;           
    HMdcClFnStacksArr*   stacksArr;       
    
    Bool_t               useDriftTime;    
    Double_t             constUncert;     
    Double_t             dDCutCorr[4][6]; 
    Double_t             dDistCut;        
    Double_t             dDistYCorr;      
 
    Int_t                numVFPoins;      
    Bool_t               use3PointMax;    
    HGeomVector          targetPnts[250];
    Double_t             vertZErr;        
    Int_t                vertexStat[250]; 
    Int_t                numStartDPoints; 
    
  public:
    static HMdcLookUpTb* getExObject(void)          {return fMdcLookUpTb;}
    static HMdcLookUpTb* getObject(void);
    static void          deleteCont(void);
    HMdcLookUpTbSec& operator[](Int_t i) {return *static_cast<HMdcLookUpTbSec*>((*array)[i]);}
    Int_t                getSize(void);
    Bool_t               init(HParIo* input,Int_t* set)           {return kTRUE;}
    virtual Bool_t       initContainer(void);
    void                 clear(void);
    void                 setTargLenInc(Double_t lf,Double_t rt);
    void                 setTypeClFinder(Int_t type)              {typeClFinder = type;}
    void                 setIsCoilOffFlag(Bool_t fl)              {isCoilOff = fl;}
    void                 setQuietMode(Bool_t md=kTRUE)            {quietMode = md;}
    void                 fillTrackList(Bool_t fl);
    void                 calcTdcDrDist(void);
    Int_t                findVertex(void);
    Int_t                getNVertexPnts(void) const               {return numVFPoins;}
    Int_t*               getVertexStat(void)                      {return vertexStat;}
    HGeomVector*         getVertexPnts(void)                      {return targetPnts;}
  protected:
    HMdcLookUpTb(const Char_t* name="MdcLookUpTb",
                 const Char_t* title="Cluster finder for MDC plane I&II",
                 const Char_t* context="");
    ~HMdcLookUpTb(void);
    virtual Bool_t       calcPrPlane(Int_t sec);
    virtual Bool_t       calcPlotSize(Int_t sec);
    Bool_t               calcTarget(Int_t sec);
    Bool_t               calcVertexFnTarg(void);
  ClassDef(HMdcLookUpTb,0)
};
#endif  /*!HMDCLOOKUPTB_H*/