#ifndef HRUNGEKUTTA_H
#define HRUNGEKUTTA_H
#include "TString.h"
#include "TObject.h"
#include "TNamed.h"
#include "TMatrixD.h"
#include "hgeomvector.h"
#include "hgeomrotation.h"
#include "hgeomtransform.h"
#include "hmdctrackgfield.h"
class HMdcSizesCells;
class HRungeKutta {
 private:
   HMdcTrackGField* fieldMap;              
   Double_t fieldScalFact;                 
   Bool_t mdcInstalled[4][6];              
   Double_t mdcPos[4][6][3];               
   Double_t normVecMdc[4][6][3];           
   Double_t pointForVertexRec[6][3];       
   Double_t dzfacMdc[2][6];                
   Double_t p0Guess;                       
   
   Float_t  initialStepSize;               
   Float_t  stepSizeInc;                   
   Float_t  stepSizeDec;                   
   Float_t  maxStepSize;                   
   Float_t  minStepSize;                   
   Float_t  minPrecision;                  
   Float_t  maxPrecision;                  
   Int_t    maxNumSteps;                   
   Double_t maxDist;                       
   Float_t  pfit;                          
   Float_t  chi2;                          
   Float_t  trackLength;                   
   Float_t  dpar[5];                       
   Float_t  resolution[8];                 
   Float_t  sig[8];                        
   Double_t hit[4][3],fit[4][3];           
   Double_t fitdp[4][3],fitdh[4][3],fitdv[4][3],fit1h[4][3],fit1v[4][3]; 
   Int_t    mdcModules[4];                 
   Int_t    mdcLookup[4];                  
   Double_t dydpar[5][8];                  
   Double_t ydata[8];                      
   Double_t fitpar[5];                     
   Int_t    ndf;                           
   Int_t    nMaxMod;                       
   Int_t    sector;                        
   Double_t dirAtFirstMDC[3];              
   Double_t posNearLastMDC[3];             
   Double_t dirAtLastMDC[3];               
   Float_t  stepSizeAtLastMDC;             
   Float_t  trackLengthAtLastMDC;          
   Double_t trackPosOnMETA[3];             
   Int_t    jstep;                         
   Double_t zSeg1,rSeg1,thetaSeg1,phiSeg1; 
   Double_t zSeg2,rSeg2,thetaSeg2,phiSeg2; 
   Float_t  polbending;                    
   Double_t mTol;                          
public:
   HRungeKutta();
   virtual ~HRungeKutta() {}
   void clear();
   void setField(HMdcTrackGField*,Float_t);
   void setFieldFactor(Float_t fpol) {fieldScalFact = fpol;}
   void setMdcPosition(Int_t,Int_t,HGeomTransform&);
   Bool_t fit4Hits(Double_t*,Double_t*,Double_t*,Double_t*,Float_t*,Int_t,Double_t pGuess=999999999.);
   Bool_t fit3Hits(Double_t*,Double_t*,Double_t*,Double_t*,Float_t*,Int_t,Double_t pGuess=999999999.);
   void traceToVertex(HMdcSizesCells*);
   void traceToMETA(HGeomVector&,HGeomVector&,HGeomVector* point = NULL,HGeomVector* norm = NULL);
   Float_t getPfit() {return pfit;}
   Float_t getChi2() {return chi2/Float_t(ndf);}
   Int_t getNMaxMod() {return nMaxMod;}
   
   Float_t getXfit(Int_t iMdc) {
     return (mdcLookup[iMdc-1]!=-1) ? fit[(mdcLookup[iMdc-1])][0] : -999.;
   }
   Float_t getYfit(Int_t iMdc) {
     return (mdcLookup[iMdc-1]!=-1) ? fit[(mdcLookup[iMdc-1])][1] : -999.;
   }
   Float_t getZfit(Int_t iMdc) {
     return (mdcLookup[iMdc-1]!=-1) ? fit[(mdcLookup[iMdc-1])][2] : -999.;
   }
   
   Float_t getXhit(Int_t iMdc) {
     return (mdcLookup[iMdc-1]!=-1) ? hit[(mdcLookup[iMdc-1])][0] : -999.;
   }
   Float_t getYhit(Int_t iMdc) {
     return (mdcLookup[iMdc-1]!=-1) ? hit[(mdcLookup[iMdc-1])][1] : -999.;
   }
   
   Float_t getXfithit(Int_t iMdc) {
     return (mdcLookup[iMdc-1]!=-1)
       ? (fit[(mdcLookup[iMdc-1])][0] - hit[(mdcLookup[iMdc-1])][0]) : -999.;
   }
   Float_t getYfithit(Int_t iMdc) {
     return (mdcLookup[iMdc-1]!=-1)
       ? (fit[(mdcLookup[iMdc-1])][1] - hit[(mdcLookup[iMdc-1])][1]) : -999.;
   }
   
   Float_t getXtrackFirstMDCFitPos()  { return fit[0][0]; }        
   Float_t getYtrackFirstMDCFitPos()  { return fit[0][1]; }        
   Float_t getZtrackFirstMDCFitPos()  { return fit[0][2]; }        
   Float_t getDXtrackFirstMDCFitPos() { return dirAtFirstMDC[0]; } 
   Float_t getDYtrackFirstMDCFitPos() { return dirAtFirstMDC[1]; } 
   Float_t getDZtrackFirstMDCFitPos() { return dirAtFirstMDC[2]; } 
   
   Float_t getXtrackLastMDCFitPos()  { return fit[nMaxMod-1][0]; } 
   Float_t getYtrackLastMDCFitPos()  { return fit[nMaxMod-1][1]; } 
   Float_t getZtrackLastMDCFitPos()  { return fit[nMaxMod-1][2]; } 
   Float_t getDXtrackLastMDCFitPos() { return dirAtLastMDC[0]; }   
   Float_t getDYtrackLastMDCFitPos() { return dirAtLastMDC[1]; }   
   Float_t getDZtrackLastMDCFitPos() { return dirAtLastMDC[2]; }   
   
   Float_t getXtrackOnMETA()  { return trackPosOnMETA[0];} 
   Float_t getYtrackOnMETA()  { return trackPosOnMETA[1];} 
   Float_t getZtrackOnMETA()  { return trackPosOnMETA[2];} 
   Float_t getTrackLength() { return trackLength; } 
   Float_t getZSeg1() { return zSeg1; }         
   Float_t getRSeg1() { return rSeg1; }         
   Float_t getThetaSeg1() { return thetaSeg1; } 
   Float_t getPhiSeg1() { return phiSeg1; }     
   Float_t getZSeg2() { return zSeg2; }         
   Float_t getRSeg2() { return rSeg2; }         
   Float_t getThetaSeg2() { return thetaSeg2; } 
   Float_t getPhiSeg2() { return phiSeg2; }     
   void     setMTol(Double_t tol) { mTol=tol; }
   Double_t getMTol()             { return mTol; }
 private:
   Bool_t   fitMdc();
   void     findMdcIntersectionPoint(Double_t*,Double_t*,Int_t,Double_t*);
   Bool_t   findIntersectionPoint(Double_t*,Double_t*,Double_t*,Double_t*,Double_t*);
   void     initMom();
   Float_t  distance(Double_t*,Double_t*);
   void     parSetNew0(Float_t,Float_t,Int_t);
   void     parSetNewVar(Float_t,Float_t);
   void     cosines(Float_t,Float_t,Double_t*);
   void     gentrkNew(Float_t,Double_t*,Double_t*,Double_t*,Int_t);
   Float_t  rkgtrk(Float_t,Float_t,Double_t*,Double_t*,Int_t kind=0);
   void     rkeqfw(Double_t*,Float_t,Double_t*,Float_t*);
   void     derive(Double_t*,Int_t);
   Bool_t   linSys();
   Bool_t   decompose(TMatrixD &lu,Double_t &sign,Double_t tol,Int_t &nrZeros);
   ClassDef(HRungeKutta,0)
};
#endif