/**
 * \file TrkLevel2.cpp
 * \author Elena Vannuccini
 */
#include <TrkLevel2.h>
#include <iostream>
#include <math.h>
using namespace std;
//......................................
// F77 routines
//......................................
extern "C" {    
    void dotrack_(int*, double*, double*, double*, double*, int*);
    void dotrack2_(int*, double*, double*, double*, double*,double*, double*, double*,int*);
     void mini2_(int*,int*,int*); 
     void guess_();
}

//--------------------------------------
//
//
//--------------------------------------
TrkTrack::TrkTrack(){
//    cout << "TrkTrack::TrkTrack()" << endl;
    seqno = -1; 
    image = -1; 
    chi2  = 0;
    nstep = 0;
    for(int it1=0;it1<5;it1++){
	al[it1] = 0;
	for(int it2=0;it2<5;it2++)coval[it1][it2] = 0;
    };
    for(int ip=0;ip<6;ip++){
	xgood[ip]  = 0;
	ygood[ip]  = 0;
	xm[ip]     = 0;
	ym[ip]     = 0;
	zm[ip]     = 0;
	resx[ip]   = 0;
	resy[ip]   = 0;
	tailx[ip]   = 0;
	taily[ip]   = 0;
	xv[ip]     = 0;
	yv[ip]     = 0;
	zv[ip]     = 0;
	axv[ip]    = 0;
	ayv[ip]    = 0;
	dedx_x[ip] = 0;
	dedx_y[ip] = 0;
    };
//    clx = 0;
//    cly = 0;
//    clx = new TRefArray(6,0); //forse causa memory leak???
//    cly = new TRefArray(6,0); //forse causa memory leak???
//    clx = TRefArray(6,0);
//    cly = TRefArray(6,0);

    TrkParams::SetTrackingMode();
    TrkParams::SetPrecisionFactor();
    TrkParams::SetStepMin();
    TrkParams::SetPFA();

};
//--------------------------------------
//
//
//--------------------------------------
TrkTrack::TrkTrack(const TrkTrack& t){
    seqno = t.seqno; 
    image = t.image; 
    chi2  = t.chi2;
    nstep = t.nstep;
    for(int it1=0;it1<5;it1++){
	al[it1] = t.al[it1];
	for(int it2=0;it2<5;it2++)coval[it1][it2] = t.coval[it1][it2];
    };
    for(int ip=0;ip<6;ip++){
	xgood[ip]  = t.xgood[ip];
	ygood[ip]  = t.ygood[ip];
	xm[ip]     = t.xm[ip];
	ym[ip]     = t.ym[ip];
	zm[ip]     = t.zm[ip];
	resx[ip]   = t.resx[ip];
	resy[ip]   = t.resy[ip];
	tailx[ip]  = t.tailx[ip];
	taily[ip]  = t.taily[ip];
	xv[ip]     = t.xv[ip];
	yv[ip]     = t.yv[ip];
	zv[ip]     = t.zv[ip];
	axv[ip]    = t.axv[ip];
	ayv[ip]    = t.ayv[ip];
	dedx_x[ip] = t.dedx_x[ip];
	dedx_y[ip] = t.dedx_y[ip];
    };
//    clx = 0;
//    cly = 0;
//    if(t.clx)clx = new TRefArray(*(t.clx));
//    if(t.cly)cly = new TRefArray(*(t.cly));
//    clx = TRefArray(t.clx);
//    cly = TRefArray(t.cly);

    TrkParams::SetTrackingMode();
    TrkParams::SetPrecisionFactor(); 
    TrkParams::SetStepMin();   
    TrkParams::SetPFA();

};
//--------------------------------------
//
//
//--------------------------------------
void TrkTrack::Copy(TrkTrack& t){

    t.seqno = seqno; 
    t.image = image; 
    t.chi2  = chi2;
    t.nstep = nstep;
    for(int it1=0;it1<5;it1++){
	t.al[it1] = al[it1];
	for(int it2=0;it2<5;it2++)t.coval[it1][it2] = coval[it1][it2];
    };
    for(int ip=0;ip<6;ip++){
	t.xgood[ip]  = xgood[ip];
	t.ygood[ip]  = ygood[ip];
	t.xm[ip]     = xm[ip];
	t.ym[ip]     = ym[ip];
	t.zm[ip]     = zm[ip];
	t.resx[ip]   = resx[ip];
	t.resy[ip]   = resy[ip];
	t.tailx[ip]  = tailx[ip];
	t.taily[ip]  = taily[ip];
	t.xv[ip]     = xv[ip];
	t.yv[ip]     = yv[ip];
	t.zv[ip]     = zv[ip];
	t.axv[ip]    = axv[ip];
	t.ayv[ip]    = ayv[ip];
	t.dedx_x[ip] = dedx_x[ip];
	t.dedx_y[ip] = dedx_y[ip];
	    
    };

//    t.clx = TRefArray(clx);
//    t.cly = TRefArray(cly);
    
};
//--------------------------------------
//
//
//--------------------------------------
/**
 * Evaluates the trajectory in the apparatus associated to the track. 
 * It integrates the equations of motion in the magnetic field. The magnetic field should be previously loaded ( by calling  TrkLevel2::LoadField() ), otherwise an error message is returned.  
 * @param t pointer to an object of the class Trajectory, 
 * which z coordinates should be previously initialized by calling the proper constructor ( Trajectory::Trajectory(int n, float* zin) ).
 * @return error flag.
 */
int TrkTrack::DoTrack(Trajectory* t){

    double *dxout = new double[t->npoint];
    double *dyout = new double[t->npoint];
    double *dzin = new double[t->npoint];
    double dal[5];

    int ifail = 0;

    for (int i=0; i<5; i++)         dal[i]  = (double)al[i];
    for (int i=0; i<t->npoint; i++) dzin[i] = (double)t->z[i];

    TrkParams::Load(1);
    if( !TrkParams::IsLoaded(1) ){
	cout << "int TrkTrack::DoTrack(Trajectory* t) --- ERROR --- m.field not loaded"<<endl;
	return 0;
    }
    dotrack_(&(t->npoint),dzin,dxout,dyout,dal,&ifail);
    
    for (int i=0; i<t->npoint; i++){
	t->x[i] = (float)*dxout++;
	t->y[i] = (float)*dyout++;
    }

//    delete [] dxout;
//    delete [] dyout;
//    delete [] dzin;

    return ifail;
};
//--------------------------------------
//
//
//--------------------------------------
/**
 * Evaluates the trajectory in the apparatus associated to the track. 
 * It integrates the equations of motion in the magnetic field. The magnetic field should be previously loaded ( by calling  TrkLevel2::LoadField() ), otherwise an error message is returned.  
 * @param t pointer to an object of the class Trajectory, 
 * which z coordinates should be previously initialized by calling the proper constructor ( Trajectory::Trajectory(int n, float* zin) ).
 * @return error flag.
 */
int TrkTrack::DoTrack2(Trajectory* t){

    double *dxout   = new double[t->npoint];
    double *dyout   = new double[t->npoint];
    double *dthxout = new double[t->npoint];
    double *dthyout = new double[t->npoint];
    double *dtlout  = new double[t->npoint];
    double *dzin    = new double[t->npoint];
    double dal[5];

    int ifail = 0;

    for (int i=0; i<5; i++)         dal[i]  = (double)al[i];
    for (int i=0; i<t->npoint; i++) dzin[i] = (double)t->z[i];

    TrkParams::Load(1);
    if( !TrkParams::IsLoaded(1) ){
	cout << "int TrkTrack::DoTrack2(Trajectory* t) --- ERROR --- m.field not loaded"<<endl;
	return 0;
    }
    dotrack2_(&(t->npoint),dzin,dxout,dyout,dthxout,dthyout,dtlout,dal,&ifail);
    
    for (int i=0; i<t->npoint; i++){
	t->x[i]   = (float)*dxout++;
	t->y[i]   = (float)*dyout++;
	t->thx[i] = (float)*dthxout++;
	t->thy[i] = (float)*dthyout++;
	t->tl[i]  = (float)*dtlout++;
    }

//    delete [] dxout;
//    delete [] dyout;
//    delete [] dzin;

    return ifail;
};
//--------------------------------------
//
//
//--------------------------------------
//float TrkTrack::BdL(){
//};
//--------------------------------------
//
//
//--------------------------------------
Float_t TrkTrack::GetRigidity(){ 
	Float_t rig=0;
	if(chi2>0)rig=1./al[4];
	if(rig<0) rig=-rig;
	return rig;
};
//
Float_t TrkTrack::GetDeflection(){
	Float_t def=0;
	if(chi2>0)def=al[4];
	return def;
};
//
/**
 * Method to retrieve the dE/dx measured on a tracker view.
 * @param ip plane (0-5)
 * @param iv view (0=x 1=y)
 */
Float_t TrkTrack::GetDEDX(int ip, int iv){
    if(iv==0 && ip>=0 && ip<6)return fabs(dedx_x[ip]);
    else if(iv==1 && ip>=0 && ip<6)return fabs(dedx_y[ip]);
    else {
	cout << "TrkTrack::GetDEDX(int ip, int iv) -- wrong input parameters "<<ip<<iv<<endl;
	return 0.;
    }
}
/**
 * Method to evaluate the dE/dx measured on a tracker plane. 
 * The two measurements on x- and y-view are averaged.
 * @param ip plane (0-5)
 */
Float_t TrkTrack::GetDEDX(int ip){
    if( (Int_t)XGood(ip)+(Int_t)YGood(ip) == 0 ) return 0; 
    return (GetDEDX(ip,0)+GetDEDX(ip,1))/((Int_t)XGood(ip)+(Int_t)YGood(ip));
};

/**
 * Method to evaluate the dE/dx averaged over all planes. 
 */
Float_t TrkTrack::GetDEDX(){
    Float_t dedx=0; 
    for(Int_t ip=0; ip<6; ip++)dedx+=GetDEDX(ip,0)*XGood(ip)+GetDEDX(ip,1)*YGood(ip); 
    dedx = dedx/(GetNX()+GetNY());
    return dedx;
};
/**
 * Returns 1 if the cluster on a tracker view includes bad strips.
 * @param ip plane (0-5)
 * @param iv view (0=x 1=y)
 */
Bool_t TrkTrack::IsBad(int ip,int iv){
    if(iv==0 && ip>=0 && ip<6)return (xgood[ip]<0) ;
    else if(iv==1 && ip>=0 && ip<6)return (ygood[ip]<0) ;
    else {
	cout << "TrkTrack::IsBad(int ip, int iv) -- wrong input parameters "<<ip<<iv<<endl;
	return 0.;
    }
};
/**
 * Returns 1 if the signal on a tracker view is saturated.
 * @param ip plane (0-5)
 * @param iv view (0=x 1=y)
 */
Bool_t TrkTrack::IsSaturated(int ip,int iv){
    if(iv==0 && ip>=0 && ip<6)return (dedx_x[ip]<0) ;
    else if(iv==1 && ip>=0 && ip<6)return (dedx_y[ip]<0) ;
    else {
	cout << "TrkTrack::IsSaturated(int ip, int iv) -- wrong input parameters "<<ip<<iv<<endl;
	return 0.;
    }
};
/**
 * Returns 1 if either the x or the y signal on a tracker plane is saturated.
 * @param ip plane (0-5)
 */
Bool_t TrkTrack::IsSaturated(int ip){
    return (IsSaturated(ip,0)||IsSaturated(ip,1));
};
/**
 * Returns 1 if there is at least a saturated signal along the track.
 */
Bool_t TrkTrack::IsSaturated(){
    for(int ip=0; ip<6; ip++)for(int iv=0; iv<2; iv++)if(IsSaturated(ip,iv))return true;
    return false;
}
/**
 * Returns the track "lever-arm" on the x view, defined as the distance (in planes) between 
 * the upper and lower x measurements (the maximum value of lever-arm is 6). 
 */
Int_t TrkTrack::GetLeverArmX(){
    int first_plane = -1;
    int last_plane  = -1;
    for(Int_t ip=0; ip<6; ip++){
	if( XGood(ip) && first_plane == -1 )first_plane = ip;
	if( XGood(ip) && first_plane != -1 )last_plane = ip;
    }
    if( first_plane == -1 || last_plane == -1){
	cout<< "Int_t TrkTrack::GetLeverArmX() -- XGood(ip) always false ??? "<<endl; 
	return 0;
    }
    return (last_plane-first_plane+1);
}
/**
 * Returns the track "lever-arm" on the y view, defined as the distance (in planes) between 
 * the upper and lower y measurements (the maximum value of lever-arm is 6). 
 */
Int_t TrkTrack::GetLeverArmY(){
    int first_plane = -1;
    int last_plane  = -1;
    for(Int_t ip=0; ip<6; ip++){
	if( YGood(ip) && first_plane == -1 )first_plane = ip;
	if( YGood(ip) && first_plane != -1 )last_plane = ip;
    }
    if( first_plane == -1 || last_plane == -1){
	cout<< "Int_t TrkTrack::GetLeverArmY() -- YGood(ip) always false ??? "<<endl; 
	return 0;
    }
    return (last_plane-first_plane+1);
}
//--------------------------------------
//
//
//--------------------------------------
void TrkTrack::Dump(){
    cout << endl << "========== Track " ;
    cout << endl << "seq.  n. : "<< seqno;
    cout << endl << "image n. : "<< image;
    cout << endl << "al       : "; for(int i=0; i<5; i++)cout << al[i] << " ";
    cout << endl << "chi^2    : "<< chi2;
    cout << endl << "n.step   : "<< nstep;
    cout << endl << "xgood    : "; for(int i=0; i<6; i++)cout << XGood(i) ;
    cout << endl << "ygood    : "; for(int i=0; i<6; i++)cout << YGood(i) ;
    cout << endl << "xm       : "; for(int i=0; i<6; i++)cout << xm[i] << " ";
    cout << endl << "ym       : "; for(int i=0; i<6; i++)cout << ym[i] << " ";
    cout << endl << "zm       : "; for(int i=0; i<6; i++)cout << zm[i] << " ";
    cout << endl << "xv       : "; for(int i=0; i<6; i++)cout << xv[i] << " ";
    cout << endl << "yv       : "; for(int i=0; i<6; i++)cout << yv[i] << " ";
    cout << endl << "zv       : "; for(int i=0; i<6; i++)cout << zv[i] << " ";
    cout << endl << "resx     : "; for(int i=0; i<6; i++)cout << resx[i] << " ";
    cout << endl << "resy     : "; for(int i=0; i<6; i++)cout << resy[i] << " ";
    cout << endl << "coval    : "; for(int i=0; i<5; i++)cout << coval[0][i]<<" ";
    cout << endl << "           "; for(int i=0; i<5; i++)cout << coval[1][i]<<" ";
    cout << endl << "           "; for(int i=0; i<5; i++)cout << coval[2][i]<<" ";
    cout << endl << "           "; for(int i=0; i<5; i++)cout << coval[3][i]<<" ";
    cout << endl << "           "; for(int i=0; i<5; i++)cout << coval[4][i]<<" ";
    cout << endl << "dedx_x   : "; for(int i=0; i<6; i++)cout << dedx_x[i] << " ";
    cout << endl << "dedx_y   : "; for(int i=0; i<6; i++)cout << dedx_y[i] << " ";
    cout << endl;
}
/**
 * Set the TrkTrack position measurements 
 */
void TrkTrack::SetMeasure(double *xmeas, double *ymeas, double *zmeas){
    for(int i=0; i<6; i++) xm[i]=*xmeas++;
    for(int i=0; i<6; i++) ym[i]=*ymeas++;
    for(int i=0; i<6; i++) zm[i]=*zmeas++;
}
/**
 * Set the TrkTrack position resolution 
 */
void TrkTrack::SetResolution(double *rx, double *ry){
    for(int i=0; i<6; i++) resx[i]=*rx++;
    for(int i=0; i<6; i++) resy[i]=*ry++;
}
/**
 * Set the TrkTrack good measurement.
 */
void TrkTrack::SetGood(int *xg, int *yg){

    for(int i=0; i<6; i++) xgood[i]=*xg++;
    for(int i=0; i<6; i++) ygood[i]=*yg++;
}

/**
 * Load the magnetic field
 */
void TrkTrack::LoadField(TString path){
    
//     strcpy(path_.path,path.Data());
//     path_.pathlen = path.Length();
//     path_.error   = 0;
//     readb_();

    TrkParams::SetTrackingMode();
    TrkParams::SetPrecisionFactor();
    TrkParams::SetStepMin();

    TrkParams::Set(path,1);
    TrkParams::Load(1);

};


/**
 * Method to fill minimization-routine common
 */
void TrkTrack::FillMiniStruct(cMini2track& track){

    for(int i=0; i<6; i++){ 

// 	cout << i<<" - "<<xgood[i]<<" "<<XGood(i)<<endl;
// 	cout << i<<" - "<<ygood[i]<<" "<<YGood(i)<<endl;
	track.xgood[i]=XGood(i);
	track.ygood[i]=YGood(i);
	
	track.xm[i]=xm[i];
	track.ym[i]=ym[i];
	track.zm[i]=zm[i];
	
//      --- temporaneo ----------------------------
//      andrebbe inserita la dimensione del sensore
	float segment = 100.;
	track.xm_a[i]=xm[i];
	track.xm_b[i]=xm[i];
	track.ym_a[i]=ym[i];
	track.ym_b[i]=ym[i];
	if(       XGood(i) && !YGood(i) ){
	    track.ym_a[i] = track.ym_a[i]+segment;
	    track.ym_b[i] = track.ym_b[i]-segment;
	}else if( !XGood(i) && YGood(i)){
	    track.xm_a[i] = track.xm_a[i]+segment;
	    track.xm_b[i] = track.xm_b[i]-segment;
	}
//      --- temporaneo ----------------------------
	
	track.resx[i]=resx[i];
	track.resy[i]=resy[i];
    }

    for(int i=0; i<5; i++) track.al[i]=al[i]; 
    track.zini = 23.5; 
// ZINI = 23.5 !!! it should be the same parameter in all codes
    
}
/**
 * Method to set values from  minimization-routine common
 */
void TrkTrack::SetFromMiniStruct(cMini2track *track){

    for(int i=0; i<5; i++) {
	al[i]=track->al[i];
	for(int j=0; j<5; j++) coval[i][j]=track->cov[i][j];
    }
    chi2  = track->chi2;
    nstep = track->nstep;
    for(int i=0; i<6; i++){ 
	xv[i]  = track->xv[i];
	yv[i]  = track->yv[i];
	zv[i]  = track->zv[i];
	xm[i]  = track->xm[i];
	ym[i]  = track->ym[i];
	zm[i]  = track->zm[i];
	axv[i] = track->axv[i];
	ayv[i] = track->ayv[i];	
    }
    
}
/**
 * \brief Method to re-evaluate coordinates of clusters associated with a track.
 *
 * The method can be applied only after recovering level1 information 
 * (either by reprocessing single events from level0 or from  
 * the TrkLevel1 branch, if present); it calls F77 subroutines that 
 * read the level1 common and fill the minimization-routine common.
 * Some clusters can be excluded or added by means of the methods:
 *
 * TrkTrack::ResetXGood(int ip)
 * TrkTrack::ResetYGood(int ip)
 * TrkTrack::SetXGood(int ip, int cid, int is)
 * TrkTrack::SetYGood(int ip, int cid, int is)
 *
 * NB! The method TrkTrack::SetGood(int *xg, int *yg) set the plane-mask (0-1) 
 * for the minimization-routine common. It deletes the cluster information
 * (at least for the moment...) thus cannot be applied before 
 * TrkTrack::EvaluateClusterPositions().  
 *
 * Different p.f.a. can be applied by calling (once) the method:
 * 
 * TrkParams::SetPFA(0); //Set ETA p.f.a.
 *
 * @see TrkParams::SetPFA(int)
 */
void TrkTrack::EvaluateClusterPositions(){
    
//     cout << "void TrkTrack::GetClusterPositions() "<<endl;

    TrkParams::Load( );
    if( !TrkParams::IsLoaded() )return;
    
    for(int ip=0; ip<6; ip++){
//	cout << ip<<" ** "<<xm[ip]<<" / "<<ym[ip]<<endl;;
	int icx = GetClusterX_ID(ip)+1;
	int icy = GetClusterY_ID(ip)+1;
	int sensor = GetSensor(ip)+1;//<< convenzione "Paolo"
	if(ip==5 && sensor!=0)sensor=3-sensor;//<< convenzione "Elena"
	int ladder = GetLadder(ip)+1;
	float ax = axv[ip];
	float ay = ayv[ip];
	float v[3];
	v[0]=xv[ip];
	v[1]=yv[ip];
	v[2]=zv[ip];
	float bfx = 10*TrkParams::GetBX(v);//Tesla
	float bfy = 10*TrkParams::GetBY(v);//Tesla
	int ipp=ip+1;
	xyzpam_(&ipp,&icx,&icy,&ladder,&sensor,&ax,&ay,&bfx,&bfy);
    }
}
/**
 * \brief Tracking method. It calls F77 mini routine.
 *
 * @param pfixed Particle momentum. If pfixed=0 the momentum 
 * is left as a free parameter, otherwise it is fixed to the input value.
 * @param fail Output flag (!=0 if the fit failed). 
 * @param iprint Flag to set debug mode ( 0 = no output; 1 = verbose; 2 = debug).
 * @param froml1 Flag to re-evaluate positions (see TrkTrack::GetClusterPositions()). 
 *
 * The option to re-evaluate positions can be used only after recovering
 * level1 information, eg. by reprocessing the single event. 
 *
 * Example:
 *
 * if( !event->GetTrkLevel0() )return false;
 * event->GetTrkLevel0()->ProcessEvent(); // re-processing level0->level1
 * int fail=0;
 * event->GetTrkLevel2()->GetTrack(0)->Fit(0.,fail,0,1);
 *
 * @see EvaluateClusterPositions()
 *
 * The fitting procedure can be varied by changing the tracking mode, 
 * the fit-precision factor and the minimum number of step.
 * @see SetTrackingMode(int)
 * @see SetPrecisionFactor(double)
 * @see SetStepMin(int)
 */
void TrkTrack::Fit(double pfixed, int& fail, int iprint, int froml1){

    float al_ini[] = {0.,0.,0.,0.,0.};

    TrkParams::Load( );
    if( !TrkParams::IsLoaded() )return;

    extern cMini2track track_;
    fail = 0;
    FillMiniStruct(track_);
    
    if(froml1!=0)EvaluateClusterPositions();
    
    // if fit variables have been reset, evaluate the initial guess
    if(al[0]==-9999.&&al[1]==-9999.&&al[2]==-9999.&&al[3]==-9999.&&al[4]==-9999.)guess_();

    // --------------------- free momentum 
    if(pfixed==0.) {
	track_.pfixed=0.; 
    }
    // --------------------- fixed momentum 
    if(pfixed!=0.) {
	al[4]=1./pfixed;     
	track_.pfixed=pfixed;
    }

    //  store temporarily the initial guess
    for(int i=0; i<5; i++) al_ini[i]=track_.al[i]; 

    //  ------------------------------------------
    //  call mini routine
//     TrkParams::Load(1);
//     if( !TrkParams::IsLoaded(1) ){
// 	cout << "void TrkTrack::Fit(double pfixed, int& fail, int iprint) --- ERROR --- m.field not loaded"<<endl;
// 	return;
//     }
    int istep=0;
    int ifail=0;
    mini2_(&istep,&ifail, &iprint);
    if(ifail!=0) {
	if(iprint)cout << "ERROR: ifail= " << ifail << endl;
	fail = 1;
    }
    //  ------------------------------------------
    
    SetFromMiniStruct(&track_);

    if(fail){
 	if(iprint)cout << " >>>> fit failed "<<endl;
 	for(int i=0; i<5; i++) al[i]=al_ini[i]; 
    }

};
/**
 * Reset the fit parameters 
 */
void TrkTrack::FitReset(){
    for(int i=0; i<5; i++) al[i]=-9999.;
    chi2=0.;
    nstep=0;
//     for(int i=0; i<6; i++) xv[i]=0.;
//     for(int i=0; i<6; i++) yv[i]=0.;
//     for(int i=0; i<6; i++) zv[i]=0.;
//     for(int i=0; i<6; i++) axv[i]=0.;
//     for(int i=0; i<6; i++) ayv[i]=0.;
    for(int i=0; i<5; i++) {
	for(int j=0; j<5; j++) coval[i][j]=0.;
    }
}
/**
 * Set the tracking mode 
 */
void TrkTrack::SetTrackingMode(int trackmode){
    extern cMini2track track_;
    track_.trackmode = trackmode;
}
/**
 * Set the factor scale for tracking precision 
 */
void TrkTrack::SetPrecisionFactor(double fact){
    extern cMini2track track_;
    track_.fact = fact;
}
/**
 * Set the factor scale for tracking precision 
 */
void TrkTrack::SetStepMin(int istepmin){
    extern cMini2track track_;
    track_.istepmin = istepmin;
}


/**
 * Method to retrieve ID (0,1,...) of x-cluster (if any) associated to this track.
 * If no cluster is associated, ID=-1.
 * @param ip Tracker plane (0-5)
 */
Int_t TrkTrack::GetClusterX_ID(int ip){
    return ((Int_t)fabs(xgood[ip]))%10000000-1;
};
/**
 * Method to retrieve ID (0-xxx) of y-cluster (if any) associated to this track.
 * If no cluster is associated, ID=-1.
 * @param ip Tracker plane (0-5)
 */
Int_t TrkTrack::GetClusterY_ID(int ip){
    return ((Int_t)fabs(ygood[ip]))%10000000-1;
};
/**
 * Method to retrieve the ladder (0-4, increasing x) traversed by the track on this plane.
 * If no ladder is traversed (dead area) the metod retuns -1.
 * @param ip Tracker plane (0-5)
 */
Int_t TrkTrack::GetLadder(int ip){
    if(XGood(ip))return (Int_t)fabs(xgood[ip]/100000000)-1;
    if(YGood(ip))return (Int_t)fabs(ygood[ip]/100000000)-1;
    return -1;
};
/**
 * Method to retrieve the sensor (0-1, increasing y) traversed by the track on this plane.
 * If no sensor is traversed (dead area) the metod retuns -1.
 * @param ip Tracker plane (0-5)
 */
Int_t TrkTrack::GetSensor(int ip){
    if(XGood(ip))return (Int_t)((Int_t)fabs(xgood[ip]/10000000)%10)-1;
    if(YGood(ip))return (Int_t)((Int_t)fabs(ygood[ip]/10000000)%10)-1;
    return -1;
};

/**
 * \brief Method to include a x-cluster to the track.
 * @param ip Tracker plane (0-5)
 * @param clid Cluster ID (0,1,...)
 * @param is Sensor (0-1, increasing y) 
 * @see Fit(double pfixed, int& fail, int iprint, int froml1)
 */
void TrkTrack::SetXGood(int ip, int clid, int is){
    int il=0;       //ladder (temporary)
    bool bad=false; //ladder (temporary)
    xgood[ip]=il*100000000+is*10000000+clid;
    if(bad)xgood[ip]=-xgood[ip];
};
/**
 * \brief Method to include a y-cluster to the track.
 * @param ip Tracker plane (0-5)
 * @param clid Cluster ID (0,1,...)
 * @param is Sensor (0-1)
 * @see Fit(double pfixed, int& fail, int iprint, int froml1)
 */
void TrkTrack::SetYGood(int ip, int clid, int is){
    int il=0;       //ladder (temporary)
    bool bad=false; //ladder (temporary)
    ygood[ip]=il*100000000+is*10000000+clid;
    if(bad)ygood[ip]=-ygood[ip];
};

//--------------------------------------
//
//
//--------------------------------------
void TrkTrack::Clear(){
//    cout << "TrkTrack::Clear()"<<endl;
    seqno = -1; 
    image = -1; 
    chi2  = 0;
    nstep = 0;
    for(int it1=0;it1<5;it1++){
	al[it1] = 0;
	for(int it2=0;it2<5;it2++)coval[it1][it2] = 0;
    };
    for(int ip=0;ip<6;ip++){
	xgood[ip]  = 0;
	ygood[ip]  = 0;
	xm[ip]     = 0;
	ym[ip]     = 0;
	zm[ip]     = 0;
	resx[ip]   = 0;
	resy[ip]   = 0;
	tailx[ip]  = 0;
	taily[ip]  = 0;
	xv[ip]     = 0;
	yv[ip]     = 0;
	zv[ip]     = 0;
	axv[ip]    = 0;
	ayv[ip]    = 0;
	dedx_x[ip] = 0;
	dedx_y[ip] = 0;

    };
//     if(clx)clx->Clear();
//     if(cly)cly->Clear();
//    clx.Clear();
//    cly.Clear();
};
//--------------------------------------
//
//
//--------------------------------------
void TrkTrack::Delete(){
//    cout << "TrkTrack::Delete()"<<endl;
    Clear();
//    if(clx)delete clx;
//    if(cly)delete cly;
};
//--------------------------------------
//
//
//--------------------------------------

//--------------------------------------
//
//
//--------------------------------------
TrkSinglet::TrkSinglet(){
//    cout << "TrkSinglet::TrkSinglet() " << GetUniqueID()<<endl;
    plane    = 0;
    coord[0] = 0; 
    coord[1] = 0;
    sgnl     = 0;
//    cls      = 0;
};
//--------------------------------------
//
//
//--------------------------------------
TrkSinglet::TrkSinglet(const TrkSinglet& s){
//    cout << "TrkSinglet::TrkSinglet(const TrkSinglet& s) " << GetUniqueID()<<endl;
    plane    = s.plane;
    coord[0] = s.coord[0]; 
    coord[1] = s.coord[1];
    sgnl     = s.sgnl;
//	cls      = 0;//<<<<pointer
//    cls      = TRef(s.cls);
};
//--------------------------------------
//
//
//--------------------------------------
void TrkSinglet::Dump(){
    int i=0;
    cout << endl << "========== Singlet " ;
    cout << endl << "plane    : " << plane;
    cout << endl << "coord[2] : "; while( i<2 && cout << coord[i] << " ") i++;
    cout << endl << "sgnl     : " << sgnl;
}
//--------------------------------------
//
//
//--------------------------------------
void TrkSinglet::Clear(){
//    cout << "TrkSinglet::Clear() " << GetUniqueID()<<endl;
//    cls=0;
    plane=-1;
    coord[0]=-999;
    coord[1]=-999;
    sgnl=0;
    
}
//--------------------------------------
//
//
//--------------------------------------
TrkLevel2::TrkLevel2(){
  //    cout <<"TrkLevel2::TrkLevel2()"<<endl;
    for(Int_t i=0; i<12 ; i++){
	good[i] = -1;
	VKmask[i] = 0;
	VKflag[i] = 0;	
    };
    Track    = 0;
    SingletX = 0;
    SingletY = 0;

}
//--------------------------------------
//
//
//--------------------------------------
void TrkLevel2::Set(){
    if(!Track)Track    = new TClonesArray("TrkTrack");
    if(!SingletX)SingletX = new TClonesArray("TrkSinglet");
    if(!SingletY)SingletY = new TClonesArray("TrkSinglet");
}
//--------------------------------------
//
//
//--------------------------------------
void TrkLevel2::Dump(){
	
	//
    cout << endl << endl << "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-";
    cout << endl << "good     : "; for(int i=0; i<12; i++) cout << good[i]<<" ";
    cout << endl << "ntrk()   : " << this->ntrk() ;
    cout << endl << "nclsx()  : " << this->nclsx();
    cout << endl << "nclsy()  : " << this->nclsy();
    if(Track){
	TClonesArray &t  = *Track;
	for(int i=0; i<ntrk(); i++)     ((TrkTrack *)t[i])->Dump();
    }	    
    if(SingletX){
	TClonesArray &sx = *SingletX;
	for(int i=0; i<nclsx(); i++) ((TrkSinglet *)sx[i])->Dump();
    }
    if(SingletY){
	TClonesArray &sy = *SingletY;
	for(int i=0; i<nclsy(); i++) ((TrkSinglet *)sy[i])->Dump();
    }
}
//--------------------------------------
//
//
//--------------------------------------
/**
 * The method returns false if the viking-chip was masked  
 * either apriori ,on the basis of the mask read from the DB, 
 * or run-by-run, on the basis of the calibration parameters)
 * @param iv Tracker view (0-11)
 * @param ivk Viking-chip number (0-23)
 */
Bool_t TrkLevel2::GetVKMask(int iv, int ivk){
    Int_t whichbit = (Int_t)pow(2,ivk);
    return (whichbit&VKmask[iv])!=0;    
}
/**
 * The method returns false if the viking-chip was masked  
 * for this event due to common-noise computation failure.
 * @param iv Tracker view (0-11)
 * @param ivk Viking-chip number (0-23)
 */
Bool_t TrkLevel2::GetVKFlag(int iv, int ivk){
    Int_t whichbit = (Int_t)pow(2,ivk);
    return (whichbit&VKflag[iv])!=0;    
}
/**
 * The method returns true if the viking-chip was masked, either
 * forced (see TrkLevel2::GetVKMask(int,int)) or 
 * for this event only (TrkLevel2::GetVKFlag(int,int)). 
 * @param iv Tracker view (0-11)
 * @param ivk Viking-chip number (0-23)
 */
Bool_t TrkLevel2::IsMaskedVK(int iv, int ivk){
    return !(GetVKMask(iv,ivk)&&GetVKFlag(iv,ivk) ); 
};

//--------------------------------------
//
//
//--------------------------------------
/**
 * Fills a TrkLevel2 object with values from a struct cTrkLevel2 (to get data from F77 common). 
 * Ref to Level1 data (clusters) is also set. If l1==NULL no references are set.
 * (NB It make sense to set references only if events are stored in a tree that contains also the Level1 branch)
 */
void TrkLevel2::SetFromLevel2Struct(cTrkLevel2 *l2, TrkLevel1 *l1){

//    cout << "void TrkLevel2::SetFromLevel2Struct(cTrkLevel2 *l2, TrkLevel1 *l1)"<<endl;
    Clear();

//  temporary objects:
    TrkSinglet* t_singlet = new TrkSinglet();
    TrkTrack*   t_track   = new TrkTrack();

//  -----------------
//  general variables
//  -----------------
    for(Int_t i=0; i<12 ; i++){
	good[i] = l2->good[i];
	VKmask[i]=0;
	VKflag[i]=0;
	for(Int_t ii=0; ii<24 ; ii++){
	    Int_t setbit = (Int_t)pow(2,ii);
	    if( l2->vkflag[ii][i]!=-1 )VKmask[i]=VKmask[i]|setbit;
	    if( l2->vkflag[ii][i]!=0  )VKflag[i]=VKflag[i]|setbit;
	};
    };
//  --------------
//  *** TRACKS ***
//  --------------
    if(!Track) Track = new TClonesArray("TrkTrack");
    TClonesArray &t = *Track;

    for(int i=0; i<l2->ntrk; i++){
	t_track->seqno = i;// NBNBNBNB deve sempre essere = i
	t_track->image = l2->image[i]-1;
	t_track->chi2  = l2->chi2_nt[i];
	t_track->nstep = l2->nstep_nt[i];
	for(int it1=0;it1<5;it1++){
	    t_track->al[it1] = l2->al_nt[i][it1];
	    for(int it2=0;it2<5;it2++)
		t_track->coval[it1][it2] = l2->coval[i][it2][it1];
	};
	for(int ip=0;ip<6;ip++){
	    // ---------------------------------
	    // new implementation of xgood/ygood 
	    // ---------------------------------
	    t_track->xgood[ip]  = l2->cltrx[i][ip]; //cluster ID
	    t_track->ygood[ip]  = l2->cltry[i][ip]; //cluster ID
	    t_track->xgood[ip] += 10000000*l2->ls[i][ip]; // ladder+sensor
	    t_track->ygood[ip] += 10000000*l2->ls[i][ip]; // ladder+sensor
	    if(l2->xbad[i][ip]>0)t_track->xgood[ip]=-t_track->xgood[ip];
	    if(l2->ybad[i][ip]>0)t_track->ygood[ip]=-t_track->ygood[ip];
//  	    if(l2->xbad[i][ip]>0 || l2->ybad[i][ip]>0){
//   	    if(l2->dedx_x[i][ip]<0 || l2->dedx_y[i][ip]<0){
//   		cout << ip << " - "<< l2->cltrx[i][ip] << " "<<l2->cltry[i][ip]<<" "<<l2->ls[i][ip]<<endl;
//   		cout << ip << " - "<<t_track->xgood[ip]<<" "<<t_track->ygood[ip]<<endl;
//   		cout << ip << " - "<<t_track->GetClusterX_ID(ip)<<" "<<t_track->GetClusterY_ID(ip)<<" "<<t_track->GetLadder(ip)<<" "<<t_track->GetSensor(ip)<<endl;
//  		cout << ip << " - "<<t_track->BadClusterX(ip)<<" "<<t_track->BadClusterY(ip)<<endl;
//  		cout << ip << " - "<<t_track->SaturatedClusterX(ip)<<" "<<t_track->SaturatedClusterY(ip)<<endl;
//   	    }
	    t_track->xm[ip]     = l2->xm_nt[i][ip];
	    t_track->ym[ip]     = l2->ym_nt[i][ip];
	    t_track->zm[ip]     = l2->zm_nt[i][ip];
	    t_track->resx[ip]   = l2->resx_nt[i][ip];
	    t_track->resy[ip]   = l2->resy_nt[i][ip];
	    t_track->tailx[ip]  = l2->tailx[i][ip];
	    t_track->taily[ip]  = l2->taily[i][ip];
	    t_track->xv[ip]     = l2->xv_nt[i][ip];
	    t_track->yv[ip]     = l2->yv_nt[i][ip];
	    t_track->zv[ip]     = l2->zv_nt[i][ip];
	    t_track->axv[ip]    = l2->axv_nt[i][ip];
	    t_track->ayv[ip]    = l2->ayv_nt[i][ip];
	    t_track->dedx_x[ip] = l2->dedx_x[i][ip];
	    t_track->dedx_y[ip] = l2->dedx_y[i][ip];
	    //-----------------------------------------------------
	    //-----------------------------------------------------
	    //-----------------------------------------------------
	    //-----------------------------------------------------
	};
// 	if(t_track->IsSaturated())t_track->Dump();
	new(t[i]) TrkTrack(*t_track);
	t_track->Clear();
    };

//  ----------------
//  *** SINGLETS ***
//  ----------------
    if(!SingletX)SingletX = new TClonesArray("TrkSinglet");
    TClonesArray &sx = *SingletX;
    for(int i=0; i<l2->nclsx; i++){
	t_singlet->plane    = l2->planex[i];
	t_singlet->coord[0] = l2->xs[i][0];
	t_singlet->coord[1] = l2->xs[i][1];
	t_singlet->sgnl     = l2->signlxs[i];
	//-----------------------------------------------------
//	if(l1) t_singlet->cls      = l1->GetCluster(l2->clsx[i]-1);
	//-----------------------------------------------------
	new(sx[i]) TrkSinglet(*t_singlet);
	t_singlet->Clear();
    }
    if(!SingletY)SingletY = new TClonesArray("TrkSinglet");
    TClonesArray &sy = *SingletY;
    for(int i=0; i<l2->nclsy; i++){
	t_singlet->plane    = l2->planey[i];
	t_singlet->coord[0] = l2->ys[i][0];
	t_singlet->coord[1] = l2->ys[i][1];
	t_singlet->sgnl     = l2->signlys[i];
	//-----------------------------------------------------
//	if(l1) t_singlet->cls      = l1->GetCluster(l2->clsy[i]-1);
	//-----------------------------------------------------
	new(sy[i]) TrkSinglet(*t_singlet);
	t_singlet->Clear();
    };
	
    delete t_track;
    delete t_singlet;
}
/**
 * Fills a struct cTrkLevel2 with values from a TrkLevel2 object (to put data into a F77 common).
 */

void TrkLevel2::GetLevel2Struct(cTrkLevel2 *l2) const {
  
//  general variables
//    l2->good2 = good2 ;
    for(Int_t i=0; i<12 ; i++){
//	l2->crc[i] = crc[i];
		l2->good[i] = good[i];
    };
//  *** TRACKS ***

    if(Track){
	l2->ntrk              =  Track->GetEntries();    
	for(Int_t i=0;i<l2->ntrk;i++){
	    l2->image[i] = 1 + ((TrkTrack *)Track->At(i))->image;
	    l2->chi2_nt[i] =  ((TrkTrack *)Track->At(i))->chi2;
	    l2->nstep_nt[i] =  ((TrkTrack *)Track->At(i))->nstep;
	    for(int it1=0;it1<5;it1++){
		l2->al_nt[i][it1] = ((TrkTrack *)Track->At(i))->al[it1];
		for(int it2=0;it2<5;it2++)
		    l2->coval[i][it2][it1] = ((TrkTrack *)Track->At(i))->coval[it1][it2];
	    };
	    for(int ip=0;ip<6;ip++){
		l2->xgood_nt[i][ip] = ((TrkTrack *)Track->At(i))->XGood(ip);
		l2->ygood_nt[i][ip] = ((TrkTrack *)Track->At(i))->YGood(ip);
		l2->xm_nt[i][ip]    = ((TrkTrack *)Track->At(i))->xm[ip];
		l2->ym_nt[i][ip]    = ((TrkTrack *)Track->At(i))->ym[ip];
		l2->zm_nt[i][ip]    = ((TrkTrack *)Track->At(i))->zm[ip];
		l2->resx_nt[i][ip]  = ((TrkTrack *)Track->At(i))->resx[ip];
		l2->resy_nt[i][ip]  = ((TrkTrack *)Track->At(i))->resy[ip];
		l2->tailx[i][ip]  = ((TrkTrack *)Track->At(i))->tailx[ip];
		l2->taily[i][ip]  = ((TrkTrack *)Track->At(i))->taily[ip];
		l2->xv_nt[i][ip]    = ((TrkTrack *)Track->At(i))->xv[ip];
		l2->yv_nt[i][ip]    = ((TrkTrack *)Track->At(i))->yv[ip];
		l2->zv_nt[i][ip]    = ((TrkTrack *)Track->At(i))->zv[ip];
		l2->axv_nt[i][ip]   = ((TrkTrack *)Track->At(i))->axv[ip];
		l2->ayv_nt[i][ip]   = ((TrkTrack *)Track->At(i))->ayv[ip];
		l2->dedx_x[i][ip]   = ((TrkTrack *)Track->At(i))->dedx_x[ip];
		l2->dedx_y[i][ip]   = ((TrkTrack *)Track->At(i))->dedx_y[ip];
	    };
	}
    }
//  *** SINGLETS ***    
    if(SingletX){
	l2->nclsx              = SingletX->GetEntries();
	for(Int_t i=0;i<l2->nclsx;i++){
	    l2->planex[i]  = ((TrkSinglet *)SingletX->At(i))->plane;
	    l2->xs[i][0]   = ((TrkSinglet *)SingletX->At(i))->coord[0];
	    l2->xs[i][1]   = ((TrkSinglet *)SingletX->At(i))->coord[1];
	    l2->signlxs[i] = ((TrkSinglet *)SingletX->At(i))->sgnl;
	}
    }

    if(SingletY){
	l2->nclsy              = SingletY->GetEntries();
	for(Int_t i=0;i<l2->nclsy;i++){
	    l2->planey[i]  = ((TrkSinglet *)SingletY->At(i))->plane;
	    l2->ys[i][0]   = ((TrkSinglet *)SingletY->At(i))->coord[0];
	    l2->ys[i][1]   = ((TrkSinglet *)SingletY->At(i))->coord[1];
	    l2->signlys[i] = ((TrkSinglet *)SingletY->At(i))->sgnl;
	}
    }
}
//--------------------------------------
//
//
//--------------------------------------
void TrkLevel2::Clear(){
    for(Int_t i=0; i<12 ; i++){
	good[i] = -1;
	VKflag[i] = 0;
	VKmask[i] = 0;
    };
//    if(Track)Track->Clear("C");
//    if(SingletX)SingletX->Clear("C");
//    if(SingletY)SingletY->Clear("C");
    if(Track)Track->Delete();
    if(SingletX)SingletX->Delete();
    if(SingletY)SingletY->Delete();
}
// //--------------------------------------
// //
// //
// //--------------------------------------
void TrkLevel2::Delete(){
	
//    cout << "void TrkLevel2::Delete()"<<endl;
    Clear();
    if(Track)delete Track;
    if(SingletX)delete SingletX;
    if(SingletY)delete SingletY;

}
//--------------------------------------
//
//
//--------------------------------------
/**
 * Sort physical tracks and stores them in a TObjectArray, ordering by increasing chi**2 value (in case of track image, it selects the one with lower chi**2). The total number of physical tracks is given by GetNTracks() and the it-th physical track can be retrieved by means of the method GetTrack(int it).
 * This method is overridden by PamLevel2::GetTracks(), where calorimeter and TOF information is used.
 */
TRefArray *TrkLevel2::GetTracks_NFitSorted(){

    if(!Track)return 0;

    TRefArray *sorted = new TRefArray();
	
    TClonesArray &t  = *Track;
//    TClonesArray &ts = *PhysicalTrack;
    int N = ntrk();
    vector<int> m(N); for(int i=0; i<N; i++)m[i]=1;
//	int m[50]; for(int i=0; i<N; i++)m[i]=1;
	
    int indo=0;
    int indi=0;
    while(N > 0){
//    while(N != 0){
	int nfit =0;
	float chi2ref = numeric_limits<float>::max();
		
	// first loop to search maximum num. of fit points
	for(int i=0; i < ntrk(); i++){
	    if( ((TrkTrack *)t[i])->GetNtot() >= nfit && m[i]==1){
		nfit =    ((TrkTrack *)t[i])->GetNtot();
	    }
	}
	//second loop to search minimum chi2 among selected
	for(int i=0; i<ntrk(); i++){
	    Float_t chi2 = ((TrkTrack *)t[i])->chi2; 
	    if(chi2 < 0) chi2 = -chi2*1000;
	    if(    chi2 < chi2ref
		   && ((TrkTrack *)t[i])->GetNtot() == nfit 
		   && m[i]==1){
		chi2ref = ((TrkTrack *)t[i])->chi2;
		indi = i;
	    };
	};
	if( ((TrkTrack *)t[indi])->HasImage() ){
	    m[((TrkTrack *)t[indi])->image] = 0;
	    N--;
	
//	    cout << "i** "<< ((TrkTrack *)t[indi])->image << " " << nfiti <<" "<<chi2i<<endl;
	};
	sorted->Add( (TrkTrack*)t[indi] );	
		
	m[indi] = 0;
//	cout << "SORTED "<< indo << " "<< indi << " "<< N << " "<<((TrkTrack *)t[indi])->image<<" "<<chi2ref<<endl; 
	N--;	
	indo++;	
    }
    m.clear();
//    cout << "GetTracks_NFitSorted(it): Done"<< endl;

    return sorted;
//    return PhysicalTrack;
}
//--------------------------------------
//
//
//--------------------------------------
/**
 * Retrieves the is-th stored track. 
 * @param it Track number, ranging from 0 to ntrk().
 * Fitted tracks ( images included ) are stored in a TObjectArray ( TrkLevel2::Track ) in the same order they are returned by the F77 fitting routine. 
 */
TrkTrack *TrkLevel2::GetStoredTrack(int is){

    if(is >= this->ntrk()){
	cout << "** TrkLevel2 ** Track "<< is << "doen not exits! " << endl; 
	cout << "                Stored tracks ntrk() = "<< this->ntrk() << endl;
	return 0;
    }
    if(!Track){
	cout << "TrkTrack *TrkLevel2::GetStoredTrack(int is) >> (TClonesArray*) Track ==0 "<<endl;
    };
    TClonesArray &t = *(Track);
    TrkTrack *track = (TrkTrack*)t[is];
    return track;
}
//--------------------------------------
//
//
//--------------------------------------
/**
 * Retrieves the is-th stored X singlet. 
 * @param it Singlet number, ranging from 0 to nclsx().
 */
TrkSinglet *TrkLevel2::GetSingletX(int is){

	if(is >= this->nclsx()){
		cout << "** TrkLevel2 ** Singlet "<< is << "doen not exits! " << endl; 
		cout << "                Stored x-singlets nclsx() = "<< this->nclsx() << endl;
		return 0;
	}
	if(!SingletX)return 0;
	TClonesArray &t = *(SingletX);
	TrkSinglet *singlet = (TrkSinglet*)t[is];
	return singlet;
}
//--------------------------------------
//
//
//--------------------------------------
/**
 * Retrieves the is-th stored Y singlet. 
 * @param it Singlet number, ranging from 0 to nclsx().
 */
TrkSinglet *TrkLevel2::GetSingletY(int is){

	if(is >= this->nclsy()){
		cout << "** TrkLevel2 ** Singlet "<< is << "doen not exits! " << endl; 
		cout << "                Stored y-singlets nclsy() = "<< this->nclsx() << endl;
		return 0;
	}
	if(!SingletY)return 0;
	TClonesArray &t = *(SingletY);
	TrkSinglet *singlet = (TrkSinglet*)t[is];
	return singlet;
}
//--------------------------------------
//
//
//--------------------------------------
/**
 * Retrieves the it-th "physical" track, sorted by the method GetNTracks(). 
 * @param it Track number, ranging from 0 to GetNTracks().
 */

TrkTrack *TrkLevel2::GetTrack(int it){
    
	if(it >= this->GetNTracks()){
		cout << "** TrkLevel2 ** Track "<< it << "does not exits! " << endl; 
		cout << "                Physical tracks GetNTracks() = "<< this->ntrk() << endl;
		return 0;
	}
	
	TRefArray *sorted = GetTracks();  //TEMPORANEO	
	if(!sorted)return 0;
	TrkTrack *track = (TrkTrack*)sorted->At(it); 
	sorted->Clear();
	delete sorted;
	return track;
}
/**
 * Give the number of "physical" tracks, sorted by the method GetTracks(). 
 */
Int_t TrkLevel2::GetNTracks(){
		
	Float_t ntot=0;
	if(!Track)return 0;
	TClonesArray &t = *Track;
	for(int i=0; i<ntrk(); i++) {	  
		if( ((TrkTrack *)t[i])->GetImageSeqNo() == -1 ) ntot+=1.;
		else ntot+=0.5;
	}
	return (Int_t)ntot;

};
//--------------------------------------
//
//
//--------------------------------------
/**
 * Retrieves (if present) the image of the it-th "physical" track, sorted by the method GetNTracks(). 
 * @param it Track number, ranging from 0 to GetNTracks().
 */
TrkTrack *TrkLevel2::GetTrackImage(int it){

    if(it >= this->GetNTracks()){
	cout << "** TrkLevel2 ** Track "<< it << "does not exits! " << endl; 
	cout << "                Physical tracks GetNTracks() = "<< this->ntrk() << endl;
	return 0;
    }
	
    TRefArray* sorted = GetTracks(); //TEMPORANEO
    if(!sorted)return 0;
    TrkTrack *track = (TrkTrack*)sorted->At(it);
	
    if(!track->HasImage()){
	cout << "** TrkLevel2 ** Track "<< it << "does not have image! " << endl; 
	return 0;
    }
    if(!Track)return 0;
    TrkTrack *image = (TrkTrack*)(*Track)[track->image];

    sorted->Delete(); 
    delete sorted;

    return image;
    
}
//--------------------------------------
//
//
//--------------------------------------
/**
 * Loads the magnetic field. 
 * @param s Path of the magnetic-field files.
 */
void TrkLevel2::LoadField(TString path){
//
//     strcpy(path_.path,path.Data());
//     path_.pathlen = path.Length();
//     path_.error   = 0;
//     readb_();

    TrkParams::SetTrackingMode();
    TrkParams::SetPrecisionFactor();
    TrkParams::SetStepMin();

    TrkParams::Set(path,1);
    TrkParams::Load(1);

//
};
// /**
//  * Get BY (kGauss)
//  * @param v (x,y,z) coordinates in cm
//  */
// float TrkLevel2::GetBX(float* v){
//     float b[3];
//     gufld_(v,b);
//     return b[0]/10.;
// }
// /**
//  * Get BY (kGauss)
//  * @param v (x,y,z) coordinates in cm
//  */
// float TrkLevel2::GetBY(float* v){
//     float b[3];
//     gufld_(v,b);
//     return b[1]/10.;
// }
// /**
//  * Get BY (kGauss)
//  * @param v (x,y,z) coordinates in cm
//  */
// float TrkLevel2::GetBZ(float* v){
//     float b[3];
//     gufld_(v,b);
//     return b[2]/10.;
// }
//--------------------------------------
//
//
//--------------------------------------
/**
 * Get tracker-plane (mechanical) z-coordinate
 * @param plane_id plane index (1=TOP,2,3,4,5,6=BOTTOM)
 */
Float_t TrkLevel2::GetZTrk(Int_t plane_id){
	switch(plane_id){
		case 1: return ZTRK1;
		case 2: return ZTRK2;
		case 3: return ZTRK3;
		case 4: return ZTRK4;
		case 5: return ZTRK5;
		case 6: return ZTRK6;
		default: return 0.;
	};
};
//--------------------------------------
//
//
//--------------------------------------
/**
 * Trajectory default constructor. 
 * (By default is created with z-coordinates inside the tracking volume)
  */
Trajectory::Trajectory(){
    npoint = 10;
    x = new float[npoint];
    y = new float[npoint];
    z = new float[npoint];
    thx = new float[npoint];
    thy = new float[npoint];
    tl = new float[npoint];
    float dz = ((ZTRK1)-(ZTRK6))/(npoint-1);
    for(int i=0; i<npoint; i++){
	x[i] = 0;
	y[i] = 0;
	z[i] = (ZTRK1) - i*dz;
	thx[i] = 0;
	thy[i] = 0;
	tl[i] = 0;
    }
}
//--------------------------------------
//
//
//--------------------------------------
/**
 * Trajectory constructor.
 * (By default is created with z-coordinates inside the tracking volume)
 * \param n Number of points
 */
Trajectory::Trajectory(int n){
    if(n<=0){
	cout << "NB! Trajectory must have at least 1 point >>> created with 10 points" << endl;
	n=10;
    }
    npoint = n;
    x = new float[npoint];
    y = new float[npoint];
    z = new float[npoint];
    thx = new float[npoint];
    thy = new float[npoint];
    tl = new float[npoint];
    float dz = ((ZTRK1)-(ZTRK6))/(npoint-1);
    for(int i=0; i<npoint; i++){
    	x[i] = 0;
	y[i] = 0;
	z[i] = (ZTRK1) - i*dz;
	thx[i] = 0;
	thy[i] = 0;
	tl[i] = 0;
    }
}
//--------------------------------------
//
//
//--------------------------------------
/**
 * Trajectory constructor.
 * \param n Number of points
 * \param pz Pointer to float array, defining z coordinates
 */
Trajectory::Trajectory(int n, float* zin){
    npoint = 10;
    if(n>0)npoint = n;
    x = new float[npoint];
    y = new float[npoint];
    z = new float[npoint];
    thx = new float[npoint];
    thy = new float[npoint];
    tl = new float[npoint];
    int i=0;
    do{
	x[i] = 0;
	y[i] = 0;
	z[i] = zin[i];
	thx[i] = 0;
	thy[i] = 0;
	tl[i] = 0;
	i++;		
    }while(zin[i-1] > zin[i] && i < npoint);
    npoint=i;
    if(npoint != n)cout << "NB! Trajectory created with "<<npoint<<" points"<<endl;
}
void Trajectory::Delete(){
    
    if(x) delete [] x;
    if(y) delete [] y;
    if(z) delete [] z;
    if(thx) delete [] thx;
    if(thy) delete [] thy;
    if(tl) delete [] tl;

}
//--------------------------------------
//
//
//--------------------------------------
/**
 * Dump the trajectory coordinates.
 */
void Trajectory::Dump(){
    cout <<endl<< "Trajectory ========== "<<endl;
    for (int i=0; i<npoint; i++){
	cout << i <<" >> " << x[i] <<" "<< y[i] <<" "<< z[i] ;
	cout <<" -- " << thx[i] <<" "<< thy[i] ;
	cout <<" -- " << tl[i] << endl;
    };
}
//--------------------------------------
//
//
//--------------------------------------
/**
 * Get trajectory length between two points
 * @param ifirst first point (default 0)
 * @param ilast last point (default npoint)
 */
float Trajectory::GetLength(int ifirst, int ilast){
    if( ifirst<0    ) ifirst = 0;
    if( ilast>=npoint) ilast  = npoint-1;
    float l=0;
    for(int i=ifirst;i<=ilast;i++){
	l=l+tl[i]; 
    };
    if(z[ilast] > ZINI)l=l-tl[ilast];
    if(z[ifirst] < ZINI)   l=l-tl[ifirst];
    
    return l;

}

/**
 * Evaluates the trajectory in the apparatus associated to the track. 
 * It integrates the equations of motion in the magnetic field. The magnetic field should be previously loaded ( by calling  TrkLevel2::LoadField() ), otherwise an error message is returned.  
 * @param t pointer to an object of the class Trajectory, 
 * which z coordinates should be previously initialized by calling the proper constructor ( Trajectory::Trajectory(int n, float* zin) ).
 * @return error flag.
 */
int Trajectory::DoTrack2(float* al){

    double *dxout   = new double[npoint];
    double *dyout   = new double[npoint];
    double *dthxout = new double[npoint];
    double *dthyout = new double[npoint];
    double *dtlout  = new double[npoint];
    double *dzin    = new double[npoint];
    double dal[5];

    int ifail = 0;

    for (int i=0; i<5; i++)      dal[i]  = (double)al[i];
    for (int i=0; i<npoint; i++) dzin[i] = (double)z[i];

    TrkParams::Load(1);
    if( !TrkParams::IsLoaded(1) ){
	cout << "int Trajectory::DoTrack2(float* al) --- ERROR --- m.field not loaded"<<endl;
	return 0;
    }
    dotrack2_(&(npoint),dzin,dxout,dyout,dthxout,dthyout,dtlout,dal,&ifail);
    
    for (int i=0; i<npoint; i++){
	x[i]   = (float)*dxout++;
	y[i]   = (float)*dyout++;
	thx[i] = (float)*dthxout++;
	thy[i] = (float)*dthyout++;
	tl[i]  = (float)*dtlout++;
    }

    return ifail;
};

ClassImp(TrkLevel2);
ClassImp(TrkSinglet);
ClassImp(TrkTrack);
ClassImp(Trajectory);
