/**
 * \file ExtTrkingAlg.h
 * \author Elena Vannuccini
 */
#ifndef exttrkingalg_h
#define exttrkingalg_h

// PAMELA classes
#include <TrkLevel1.h>
#include <TrkLevel2.h>

#include <ToFLevel2.h>

#include <CaloLevel1.h>
#include <CaloLevel2.h>

#include <ExtTrack.h>

// ROOT classes
#include <TClonesArray.h>



#include <stdlib.h>
#include <map>
#include <iostream>
#include <iomanip>


#define nCP 22;
#define nCV 2;
#define nCS 9;

 //         relative to pamela reference system (convenzione emiliano):
 //
 //        y ^
 //          |
 //          | 6 7 8 sisensor
 //          | 3 4 5   
 //          | 0 1 2 
 //          ------------> x 
 //
 //        relative to silicon sensor           
 //
 //        S ^
 //          |   |
 //        2 |   |  <- strip direction
 // sensor 1 |   | 
 //        0 |...|...
 //          ------------> L
 //            0 1 2 
 //            ladder
 //
 //

int GetCaloSensor(int view, int sis){
    if(sis<0||sis>8)return -1;
    if(view<0||view>1)return -1;
    if(!view)return (int)(sis/3); 
    else return sis%3; 
};
int GetCaloLadder(int view, int sis){ 
    if(sis<0||sis>8)return -1;
    if(view<0||view>1)return -1;
    if(!view)return sis%3;  
    else return (int)(sis/3); 
};
int GetCaloLadder(int strip){ 
    return (int)(strip/32);
};
int GetCaloSiSensor(int view, int l, int s){
    if(view<0||view>1)return -1;
    if(s<0||s>2)return -1;
    if(!view) return 3*s+l;
    else      return 3*l+s;
};

/**
 *
 * Extended CaloStrip class, to account for rototraslation parameters
 *
 */
class CaloStripRoto  {

 private:

  float fPitch; // = 1.;
  float shift[3]; //= {0.,0.,0.};//(L,S,Z)
  float alpha;//  = 0.;

  int   siSensor; // 0-8
  int sView;//0-1
  int sPlane;//0-21
  CaloStrip st;
  
  void Set(int view, int plane, float strip, int sisensor); ///< Set strip giving view [0-1], plane [0-22] and number [0-95]
  void SetSiSensor( int si=-1  ){ siSensor = si;};
  void SetView(int view){sView = view;};
  void SetPlane(int plane){sPlane = plane;};

 public:

/*   CaloStrip st; */


  float fXA; //< X position in cm of the strip
  float fYA; //< Y position in cm of the strip
  float fZA; //< Z position in cm of the strip

  float fXB; //< X position in cm of the strip
  float fYB; //< Y position in cm of the strip
  float fZB; //< Z position in cm of the strip
  
  //
  CaloStripRoto(int view, int plane, int sisensor, bool usemechanicalalignement = true); ///< Default Constructor.



  void ResetAligParams();
  void SetAligParams__fPitch( float f ){ fPitch = f; };
  void SetAligParams__shift( float *s ){ for(int i=0; i<3; i++)shift[i]=s[i]; };
  void SetAligParams__alpha( float a ){ alpha = a; };

  void SetStrip(float strip){Set(GetView(),GetPlane(),strip,GetSiSensor());}; ///< Set strip giving view [0-1], plane [0-22] and number [0-95]



/*   int GetSensor(int view, int sisensor); */
/*   int GetLadder(int view, int sisensor); */
/*   int GetSiSensor(int view, int ladder, int sensor); */
  //  CaloStrip GetCaloStrip(){return st;};
  bool SensorContains(float x, float y);
  
  int GetView(){return sView;};
  int GetPlane(){return sPlane;};
  int GetStrip(){return st.GetStrip();};
  int GetSensor();
  int GetLadder();
  int GetSiSensor(){ return siSensor; };
  
  float GetSpatialResolution(float def, float degx=0., float degy=0.,  float beta=1.);

  float GetDistanceTo(float xP, float yP, float& xM, float &yM);
  float GetDistanceTo(float xP, float yP){ float xM,yM; return GetDistanceTo(xP,yP,xM,yM); };

};


/**
 *
 * Extended hit class
 *
 */


class ExtHit{

 private:


 public:

 
  Float_t coordCm; //centimeters
  Float_t coordPU; //pitch units
  Float_t resCm; 
  Float_t signal;
  Int_t start; 
  Int_t mult;
  Int_t view;

  
  void Reset(){    
    coordCm = 1000.;
    coordPU = 1000.;
    resCm   = 1000.;
    signal  = 0.;
    start   = -1; 
    mult    = 0;
    view    = -1;
  };
  void Set(int s, int v){start=s; view=v;}   
  /* void Set(int s, int v){coordPU=s; view=v;}   */

  ExtHit(){Reset();};
  ExtHit(int s, int v){Reset(); Set(s,v); };
  ~ExtHit(){Reset();};

  ExtHit( const ExtHit& h ){
    coordCm = h.coordCm;
    coordPU = h.coordPU;
    resCm   = h.resCm;
    signal  = h.signal;
     start   = h.start; 
    mult    = h.mult;
    view    = h.view;
  }

  void Add(float cc, float pp, float ss){
    if(ss<0)cout << "void ExtHit(cc="<<cc<<",ss="<<ss<<") -- not valid argument";
    if(ss<0)return;
    mult++;
    float sumcc =  coordCm * signal;
    float sumpp =  coordPU * signal;
    signal+=ss;
    sumcc += ss * cc;
    sumpp += ss * pp;
    coordCm = sumcc/signal;
    coordPU = sumpp/signal;
  };

  void Dump(){
    cout << " View  "<<view<<endl;
    cout << " Coordinate (cm)   "<<coordCm<<endl;
    cout << " Coordinate (p.u.) "<<coordPU<<endl;
    cout << " Resolution (cm) "<<resCm<<endl;
    cout << " Multiplicity  "<<mult<<endl;
    cout << " Signal (MIP)  "<<signal<<endl;    
  };

  //  ClassDef(ExtHit,1);

};

/**
 *
 * Algorythm class
 *
 */



class ExtTrkingAlg : public TObject {

private:

  Int_t  _whichAlg;         ///< algorythm id

  TClonesArray *_trkArray; ///< array of tracks
  
  TrkLevel1*  _trk_l1; 
  TrkLevel2*  _trk_l2;
  
  CaloLevel1* _cal_l1;
  CaloLevel2* _cal_l2;
  vector<ExtHit> _cal_cl;///< calorimeter hits

  ToFLevel2*  _tof_l2;
  vector<ExtHit> _trk_cl;///< tracker hits

  ExtTrack* _extTrack;
  float*    _zMech;

  Int_t _sel_nClstrMAX;  ///< selection parameter: maximum number of cluster
  Int_t _sel_nPlaneXMIN; ///< selection parameter: minimum number of hit x-views
  Int_t _sel_nPlaneYMIN; ///< selection parameter: minimum number of hit y-views

  Int_t _alg_nClFixX;     ///< algorythm parameter: n.hits required on X view
  Int_t _alg_nClFixY;     ///< algorythm parameter:n.hits required on Y view
  Int_t _alg_nTrackMAX;   ///< algorythm parameter: maximum num. of track candidates
  Int_t _alg_nViewCal;    ///< algorythm parameter: n. calorimeter planes included 

  Int_t NEXTVIEWS;
  Int_t NEXTPLANES;

  float _caloCoord[2][22][96];
  float _caloZ[44];
  Trajectory* _caloTj;
  Trajectory* _tgf;


  vector<CaloStripRoto> _caloStripRoto; // rotatore di calorimetri! sapevatelo!

  Bool_t _debug;

public:

  void Clear(Option_t* option = "");    ///< Clear the event
  void Delete();                        ///< Delete all (deallocate arrays)

  ExtTrkingAlg(Int_t id=0);
  //  ExtTrkingAlg(){ ExtTrkingAlg(0); };  
  ~ExtTrkingAlg(){ Delete(); };

  //  ExtTrkingAlg(Int_t id);

  void SetTrkLevel1( TrkLevel1* trkl1 = NULL )   { _trk_l1  = trkl1;};
  void SetTrkLevel2( TrkLevel2* trkl2 = NULL )   { _trk_l2  = trkl2; };
  void SetToFLevel2( ToFLevel2* tofl2 = NULL )   { _tof_l2  = tofl2; };
  void SetCaloLevel1( CaloLevel1* call1 = NULL ) { _cal_l1  = call1; };
  void SetCaloLevel2( CaloLevel2* call2 = NULL ) { _cal_l2  = call2; };

  
  void FillClusterMap(multimap<int,int> &map,TrkLevel1* l1,Int_t vOffset = 0);
  void FillClusterMap(multimap<int,int> &map,CaloLevel1* l1,Int_t vOffset = 12);

  Bool_t CheckEvent();                        ///< pre-selection
  void ProcessEvent0(Bool_t force = false);    ///< apply tracking algorythm 0
  void ProcessEvent1(Bool_t force = false);    ///< apply tracking algorythm 1
  void ProcessEvent2(Bool_t force = false);    ///< apply tracking algorythm 1
  void ProcessEvent(Bool_t force = false);
  bool EvaluateClusterPosition_Tracker( int, int, int, int, float*, float*, float*);  
  bool EvaluateClusterPosition_Calorimeter( int icl, int& sensor, float *xmABar, float *ymABar, float *zmAB, float def=0.);


  TClonesArray *GetTrackArray(Bool_t reset = false);

  void SetSelectionParams(double* par);
  void SetAlgorythmParams(double* par);


  void SetDebug(Bool_t dbg = false){ _debug = dbg; };

  void Dump();

  TClonesArray** GetPointerToTrackArray(){ return &_trkArray; };

  vector<ExtHit> GetCaloClusters(){ return _cal_cl; };
  vector<ExtHit> GetTrkClusters(){ return _trk_cl; };

  CaloStripRoto GetCaloStripRoto(int index){ return _caloStripRoto[index]; };


};


#endif
