#ifndef HMDC34CLFINDER_H
#define HMDC34CLFINDER_H
#include "TObject.h"
#include "hlocation.h"
#include "hmdclistgroupcells.h"
#include "hmdclistcells.h"
#include "hmdcgeomobj.h"
#include "hparset.h"
#include "hgeomvector.h"
#include "hmdckickplane.h"
#include "TCutG.h"
class HMdcClus;
class HMdcSeg;
class TH2C;
class HMdcGetContainers;
class HSpecGeomPar;
class HMdcSizesCells;
class HMdcGeomPar;
class HCategory;
class HMdcClFnStack;
class HMdcClFnStacksArr;
class HMdcClustersArrs;
class HMdcCluster;
class HMdcDriftTimeParSec;
class HMdcSizesCellsLayer;
class HMdcClusMetaMatch;
class HMdcTrackParam;
class HMdcKickCor;
class HMdcProjPlot : public HMdcPlane {
  protected:
  public:
    Double_t  yMin,yMax;     
    Double_t  xMin,xMax;
    Double_t  xMinD,xMaxD;   
    Short_t   nBinX;         
    Double_t  stX;           
    Short_t   nBinY;         
    Double_t  stY;           
    Short_t*  xMinL;         
    Short_t*  xMaxL;         
    Short_t*  yMinL;         
    Double_t* xBinsPos;      
    Double_t* yBinsPos;      
    Float_t   xFirstBin;     
    Float_t   yFirstBin;     
    Int_t     size;                
    static UChar_t* weights;       
    static UChar_t* weights3;      
    static UChar_t* weights4;      
    static Int_t    wtArrSize;     
    static UChar_t  nBitsLuTb[64];
    TH2C*     rootPlot;
  public:
    HMdcProjPlot(UChar_t mSeg, Int_t inBinX, Int_t inBinY);
    ~HMdcProjPlot();
    void      setEdges(Double_t iyMin, Double_t ixMinD, Double_t ixMaxD,
                      Double_t iyMax, Double_t ixMin,  Double_t ixMax);
    void      print(void);
    Int_t     xbin(Int_t bin) const        {return bin%nBinX;}
    Int_t     ybin(Int_t bin) const        {return bin/nBinX;}
    Double_t  xBnPos(Int_t bin) const      {return xBinsPos[bin%nBinX];}
    Double_t  yBnPos(Int_t bin) const      {return yBinsPos[bin/nBinX];}
    Short_t   binX(Double_t x) const       {return Short_t((x-xMin)/stX);}
    Short_t   binY(Double_t y) const       {return Short_t((y-yMin)/stY);}
    void      calcCrossBin(const HGeomVector &r,const HGeomVector &dir,Short_t& xb,Short_t& yb) const;
    TH2C*     getPlot(Char_t* name, Char_t* title);
    UChar_t   binAmplitude(Int_t nb) const {return nBitsLuTb[weights3[nb]]+nBitsLuTb[weights4[nb]];}
    void      clearBin(Int_t nb)           {weights3[nb] = weights4[nb]=0;}
    inline UChar_t getBinAmplAndClear(Int_t nb);
  protected:
    HMdcProjPlot(void) {}
    ClassDef(HMdcProjPlot,0)
};
inline UChar_t HMdcProjPlot::getBinAmplAndClear(Int_t nb) {
  UChar_t amp  = nBitsLuTb[weights3[nb]];
  weights3[nb] = 0;
  amp         += nBitsLuTb[weights4[nb]];
  weights4[nb] = 0;
  return amp;
}
class HMdc34ClFinderLayer: public TObject {
  protected:
  public:
    UChar_t  module;             
    UChar_t  layer;              
    HMdcSizesCellsLayer *pSCLay;
    
    HMdcLayListCells* cells;     
    Int_t    nCells;             
    Short_t  nBinX;              
    Short_t* yBin;               
    Int_t    yFirst;             
    Int_t    nYLines;            
    Int_t    wOrType;            
    Short_t* xBin1;              
    Short_t* xBin2;              
    Double_t tgY;                
    Double_t tgZ;                
    Double_t y0[2];              
    Double_t z0[2];              
                                 
    Double_t yStep;              
    Double_t zStep;              
    Int_t    nPSegOnKick[2][2];  
                                 
    Double_t maxDrDist;          
    Double_t y0w;                
    Double_t z0w;                
    Double_t xWirDir;            
    Double_t yWirDir;            
    Double_t zWirDir;            
    
    
    Double_t yCross;             
    
    
    UChar_t              layerPart;     
    Int_t                nextPartFCell; 
    HMdc34ClFinderLayer *layerNextPart;
  public:
    HMdc34ClFinderLayer(Int_t sec, Int_t mod, Int_t lay);
    HMdc34ClFinderLayer(HMdc34ClFinderLayer& prevPart);
    ~HMdc34ClFinderLayer();
    Bool_t createArrayBins(Short_t nBins);
    void   setCellsList(HMdcLayListCells& event) {cells = &event;}
    HMdc34ClFinderLayer* nextLayerPart(Int_t nPartFCell);
    HMdc34ClFinderLayer* getLayerPart(Int_t c);
    Bool_t calcWiresProj(HMdcSizesCellsLayer& fSCellsLay,HGeomVector& pKick,
                         HMdcProjPlot* prPlotSeg2,Int_t firstCell);
    ClassDef(HMdc34ClFinderLayer,0)
};
class HMdc34ClFinderMod : public TObject {
  protected:
    TObjArray* array;
  public:
    HMdc34ClFinderMod(Int_t sec, Int_t mod);
    ~HMdc34ClFinderMod();
    HMdc34ClFinderLayer& operator[](Int_t i) {
        return *static_cast<HMdc34ClFinderLayer*>((*array)[i]);
    }
    Int_t getNCells(void);
    void  setCellsList(HMdcModListCells& event);
        
    ClassDef(HMdc34ClFinderMod,0)
};
class HMdc34ClFinderSec : public TObject {
  protected:
    TObjArray*            array;            
    Int_t                 sector;
    HMdcClusMetaMatch    *pMetaMatch;       
    Int_t                 lMods[4];         
    UChar_t               mSeg[2];          
    HMdcKickPlane        *fkick;
    HGeomVector           target[2];        
    HMdcProjPlot         *prPlotSeg2;       
    HGeomVector           seg1;             
    HGeomVector           dirSeg1;          
    HGeomVector           segRegOnKick[4];  
    HGeomVector           segOnKick;        
    HGeomVector           errSegOnKick;     
    Double_t              al[4];
    Double_t              bl[4];
    Double_t              cl[4];
    Int_t                 nbX[4];
    Int_t                 minAmp[4];        
    Int_t                 maxAmp[4];        
    Bool_t                notEnoughWrs;     
    Int_t                 nearbyBins[8];    
    HMdcClFnStack        *stack;            
    HMdcClFnStacksArr    *stacksArr;        
    Short_t              *xMinClLines;
    Short_t              *xMaxClLines;
    Int_t                 nLMinCl;
    Int_t                 nLMaxCl;
    Bool_t                isClstrInited;    
    Int_t                 indexPar;         
    Int_t                 indexFCh;         
    Int_t                 indexLCh;         
    Int_t                *xCMin;            
    Int_t                *xCMax;            
    HMdc34ClFinderMod    *cFMod;            
    HMdc34ClFinderLayer  *cFLay;            
    Int_t                 nBinX;            
    Int_t                 module;           
    Int_t                 cell;             
    Int_t                 layInd;           
    Double_t              tdcTDist;         
    Int_t                 nBinYM2;          
    Int_t                 shUp;             
    Int_t                 shDown;           
    Int_t                 nYLinesL;         
    Short_t              *xBin1L;           
    Short_t              *xBin2L;           
    Int_t                 ny1;              
    Int_t                 ny2;              
    Short_t               nbL;              
    Short_t               nbF;              
    UInt_t                oneArrLay[6][4];
    UInt_t               *oneArr;
    UInt_t                bitsSetLay[6];    
    UInt_t                bitsSet;          
    Short_t               sUAr[12][420];    
    Short_t               sDAr[12][420];    
    Short_t               cNum[12][420];    
    HMdc34ClFinderLayer  *pLayPar[12][420]; 
    Int_t                 nPRg[12];         
    Short_t              *shUpArr;          
    Short_t              *shDnArr;          
    Short_t              *cellNum;          
    Int_t                *numPrRegs;        
    HMdc34ClFinderLayer **cFLayArr;         
    Int_t                 regInd;           
    Int_t                 shDownMax;        
    UChar_t              *weightsArr;       
    UChar_t               seg2MinAmpCut;    
    HMdcSecListCells     *pListCells;       
    HCategory            *fClusCat;
    HLocation             locClus;
    Bool_t                isGeant;
    
    Int_t                 typeClFinder;     
                                            
    Int_t                 realTypeClFinder; 
    
    HMdcClustersArrs     *pClustersArrs;    
    Int_t                 clusArrSize;      
    HMdcCluster          *clusArr;          
    Int_t                 nClsArr;          
    HMdcCluster          *cluster;          
    HMdcDriftTimeParSec  *pDriftTimeParSec;
    Double_t              dDistCut;         
    Double_t              dDistYCorr;       
    Double_t              dDCutCorr[12];    
    Bool_t                useDriftTime;     
    
    Char_t                useDxDyCut;       
    TCutG                 cutDxDyArr[36];   
    struct DxDyBinsCut {
      Short_t xBMin;
      Short_t xBMax;
    };
    DxDyBinsCut*          cutXBins[36];     
    Short_t               nYLinesInCut[36];
    Short_t               yLineMin[36];
    Short_t               yLineMax[36];
    Double_t              x0;               
    Double_t              y0;               
    Short_t               xBin0;            
    Short_t               yBin0;            
    Int_t                 dXdYCutReg;       
    Int_t                 yMinDxDyCut;      
    Int_t                 yMaxDxDyCut;      
    Int_t                 yBinToDxDyInd;    
    
    
    Char_t                fakeSuppFlag;     
    Int_t                 wLev;             
    Int_t                 wBin;             
    Int_t                 wLay;             
    Int_t                 dWtCut;           
    
    HMdcKickCor          *pKickCor;
  protected:
    HMdc34ClFinderSec(void) : cFLayArr(NULL) {}
    ~HMdc34ClFinderSec();
    void     makeModS2Plot(Int_t mod);
    void     makeSeg2PlotAmpCut(void);
    Int_t    calcYbin(Int_t upDo,Int_t leRi,Int_t c);
    Int_t    scanPlotSeg2(void);
    Bool_t   calcClusterSeg2FixedLevel(Int_t nBin,UChar_t amp);
    Bool_t   calcClusterSeg2FloatLevel(Int_t nBin,UChar_t amp);
    Bool_t   fillClusterSeg2(void);
    Int_t    findClustersSeg2(void);
    void     initCluster(Int_t nBin,UChar_t amp);
    void     reinitCluster(Int_t nBin,UChar_t amp);
    void     addBinInCluster(Int_t nBin,UChar_t wt);
    Bool_t   increaseClusterNum(void);
    void     mergeClustSeg2(void);
    Int_t    fillClusCat(void);
    Bool_t   calcLayerProjVar(Int_t lay);
    Bool_t   setRegionVar(void);
    void     makeLayProjV1(void);
    void     makeLayProjV2(void);
    void     clearPrSeg2(void);
    Bool_t   testMaxAmp(void);
    void     calcYbinDrTm(Double_t dDCutYCellCorr);
    void     setArrays(Int_t lay);
    void     calcDriftDist(void);
    Double_t calcKickCor(void);
    void     removeGhosts(void);
    void     checkMetaMatch(void);
    void     setFirstLayerPart(Int_t c);
    void     setLayerPart(Int_t c);
    Bool_t   calcXBinsCut(Int_t nReg, TCutG& cutDxDy);
    Int_t    calcCrosses(TCutG &cutDxDy,Double_t yb,DxDyBinsCut& cutB);
    inline void fillBins(Int_t ny);
  public:
    HMdc34ClFinderMod& operator[](Int_t i) {
        return *static_cast<HMdc34ClFinderMod*>((*array)[i]);
    }
    void     clear(void);
    void     setMinBin(Int_t *mBin);
    Bool_t   notEnoughWires(void) const            {return notEnoughWrs;}
    Int_t    findClustersSeg2(HMdcClus* pClus,Int_t *mBin=0);
    Int_t    findClustersSeg2(HMdcTrackParam *tSeg1, HMdcClus* pClus,Int_t *mBin=0);
    TH2C*    getPlot(Char_t* name,Char_t* title,Int_t ver=0);
    HMdcProjPlot* getPlotSeg2(void)                {return prPlotSeg2;}
    Int_t    getNBinX(void)                        {return prPlotSeg2->nBinX;}
    Int_t    getNBinY(void)                        {return prPlotSeg2->nBinY;}
    void     setTargetF(const HGeomVector& vec)    {target[0]=vec;}
    void     setTargetL(const HGeomVector& vec)    {target[1]=vec;}
    const    HGeomVector& getTargetF(void)         {return target[0];}
    const    HGeomVector& getTargetL(void)         {return target[1];}
    void     setTypeClFinder(Int_t type)           {typeClFinder=type;}
    Int_t    getTypeClFinder(void)                 {return typeClFinder;} 
    void     setCellsList(HMdcSecListCells& event);
    
    HMdc34ClFinderSec(Int_t sec, Int_t inBinX, Int_t inBinY);
    HGeomVector* getTargetArr(void)                {return target;}
    UChar_t *getMSeg(void)                         {return mSeg;}
    void     setClusCut(HCategory* pClCat)         {fClusCat    = pClCat;}
    void     setKickPlane(HMdcKickPlane* pkick)    {fkick       = pkick;}
    void     setXMinClLines(Short_t* xMin)         {xMinClLines = xMin;}
    void     setXMaxClLines(Short_t* xMax)         {xMaxClLines = xMax;}
    void     setClFnStack(HMdcClFnStack* pst)      {stack       = pst;}
    void     setClFnStArr(HMdcClFnStacksArr* psa)  {stacksArr   = psa;}
    Int_t    mdcFlag(Int_t m)                      {return lMods[m];}
    void     doMetaMatch(HMdcClusMetaMatch* pMM)   {pMetaMatch  = pMM;}
    Bool_t   setDxDyCut(TCutG* cutR);
    void     setFakeSupprFlag(Char_t fl)           {fakeSuppFlag = fl;}
    void     resetCounter(void)                    {} 
     void    setKickCorr(HMdcKickCor *p)           {pKickCor     = p;}
           
    ClassDef(HMdc34ClFinderSec,0)
};
class HMdc34ClFinder : public HParSet {
  protected:
    static HMdc34ClFinder* fMdc34ClFinder;
    TObjArray*             array;           
    HMdcGetContainers*     fGetCont;
    HSpecGeomPar*          fSpecGeomPar;
    HMdcSizesCells*        fSizesCells;
    HMdcKickPlane          kickPlane;
    HMdcGeomPar*           fMdcGeomPar;
    HCategory*             fMdcClusCat;
    Short_t*               xMinClLines;
    Short_t*               xMaxClLines;
    HMdcClFnStack*         stack;           
    HMdcClFnStacksArr*     stacksArr;       
    static Bool_t          quietMode;
    HMdcClusMetaMatch*     pMetaMatch;      
    
    TCutG                  cutDxDyArr[36];  
    Bool_t                 useDxDyCut;      
    
    Bool_t                 useKickCor;      
    HMdcKickCor           *pKickCor;
    
  public:
    static HMdc34ClFinder* getExObject(void);
    static HMdc34ClFinder* getObject(void);
    static void            deleteCont(void);
    static void            setQuietMode(Bool_t quiet) {quietMode=quiet;}
    static Bool_t          getQuietMode()             {return quietMode;}
    HMdc34ClFinderSec& operator[](Int_t i) {
      return *static_cast<HMdc34ClFinderSec*>((*array)[i]);
    }
    Bool_t init(HParIo* input,Int_t* set)             {return kTRUE;}
    Bool_t initContainer(HMdcEvntListCells& event);
    void   setCellsList(HMdcEvntListCells& event);
    void   clear(void);
    void   doMetaMatch(HMdcClusMetaMatch* pMM)        {pMetaMatch = pMM;}
    static Int_t calcDxDyCutRegion(const HGeomVector& pnt);
    void   printClFinderParam(void);
    
  protected:
    HMdc34ClFinder(const Char_t* name    = "Mdc34ClFinder",
                   const Char_t* title   = "Cluster finder for outer MDCs",
                   const Char_t* context = "");
    ~HMdc34ClFinder();
    Bool_t   calcTarget(Int_t sec);
    Bool_t   calcProjPlaneSeg2(Int_t sec);
    Bool_t   calcSizePlotSeg2(Int_t sec);
    Bool_t   calcWiresProj(Int_t sec);
    void     calcCrossLines(HGeomVector& p1l1, HGeomVector& p2l1,
                            HGeomVector& p1l2, HGeomVector& p2l2,HGeomVector& cross);
    Double_t xLine(HGeomVector& p1, HGeomVector& p2, Double_t yi);
    ClassDef(HMdc34ClFinder,0)
};
inline void HMdc34ClFinderSec::fillBins(Int_t ny) {
  
  Int_t   nb    = nbL-nbF+1;
  Int_t   nbR   = nb&3; 
  UInt_t* wt4    = (UInt_t*)(weightsArr+nbF + ny*nBinX); 
  UInt_t* wt4Max = wt4 + (nb>>2); 
  for(; wt4<wt4Max; wt4++) (*wt4) |= bitsSet;
 (*wt4) |= oneArr[nbR];
}
#endif  /*!HMDC34CLFINDER_H*/