//_____________________________________________________________________________
///
/// \class GeometryHelper 
///
/// Utility class provides methods to access geometry data used by the fitter.  
///
/// \author Sergei avva@fnal.gov
///

#include <cassert>
#include <cmath>

#include "MessageService/MsgService.h"
#include "RecoBase/CandStripHandle.h"
#include "RecoBase/CandTrackHandle.h"
#include "UgliGeometry/UgliScintPlnHandle.h"
#include "UgliGeometry/UgliSteelPlnHandle.h"

#include "CandFitTrackSA/ConstFT.h"
#include "CandFitTrackSA/GeometryHelper.h"
#include "CandFitTrackSA/TrackContext.h"
#include "CandFitTrackSA/TracerSA.h"

CVSID("$Id: GeometryHelper.cxx,v 1.4 2007/02/06 16:32:29 avva Exp $");

using namespace ConstFT;

///
///
///
GeometryHelper::GeometryHelper(const VldContext& vldc) :
    fVldc(vldc), fUgh(vldc)
{
    TracerSA trace("GeometryHelper::GeometryHelper(const VldContext& vldc)");
}

///
///
///
GeometryHelper::GeometryHelper(const TrackContext& tc) :
    fVldc(tc.GetVldContext()), fUgh(tc.GetVldContext())
{
    TracerSA trace("GeometryHelper::GeometryHelper(const VldContext& vldc)");
}


///
///
///
Double_t GeometryHelper::GetZ(PlexPlaneId id)
{
    // Return z-position of the i-th scint plane (or the i-th steel 
    // plane in case there is no scintillator)
    if ( id.IsValid() ) {
        UgliScintPlnHandle usph = fUgh.GetScintPlnHandle(id);
        return usph.GetZ0();
    }

    // not valid === no scint plane here - use Z of steel     
    id.SetIsSteel(kTRUE);
    if ( id.IsValid() ) {
        UgliSteelPlnHandle usph = fUgh.GetSteelPlnHandle(id);
        return usph.GetZ0();
    }
    
    // should never get here
    assert(!"Neither scint, not steel are valid here");
    return 0.;
}

///
/// Return z position of the track vertex, given begin plane and 
/// track direction. Vertex position is defined to be in the 
/// middle of the previous (ie against track direction) steel
/// plane if it exists, or just 0.03m "upstream" of begplane
///  
Double_t GeometryHelper::GetZVtx(PlexPlaneId begin, Int_t idir)
{
    // get the adjoin steel plane; note direction '-idir' - 
    // we want a "previous" plane
    PlexPlaneId prevSteel = begin.GetAdjoinSteel(-idir);
    if ( prevSteel.IsValid() ) {
        // have a steel plane
        UgliSteelPlnHandle usph = fUgh.GetSteelPlnHandle(prevSteel);
        return usph.GetZ0();
    } else {
        // no steel plane - just go 0.03m "upstream" of beg plane
        return GetZ(begin) - idir*0.03;                
    }
}

///
///
///
Double_t GeometryHelper::GetX0(PlexPlaneId id)
{
    // Amount of material in units of radiation length
    Double_t x0=0.;
    // add X0 of scint        
    if ( id.IsValid() ) {
        UgliScintPlnHandle uscph = fUgh.GetScintPlnHandle(id);
        x0 += 2.*uscph.GetHalfThickness()/X0_Scint;
    }
    // add X0 of steel
    id.SetIsSteel(kTRUE);
    if ( id.IsValid() ) {
        UgliSteelPlnHandle ustph = fUgh.GetSteelPlnHandle(id);
        x0 += 2.*ustph.GetHalfThickness()/X0_Steel;
    }
    return x0;
}

///
///
///
Double_t GeometryHelper::GetdZSteel(PlexPlaneId id)
{
    // Steel thickness
    Double_t dZSteel=0.;    
    
    // 
    id.SetIsSteel(kTRUE);
    if ( id.IsValid() ) {
        UgliSteelPlnHandle ustph = fUgh.GetSteelPlnHandle(id);
        dZSteel += 2.*ustph.GetHalfThickness();
    }
    
    return dZSteel;
}

///
///
///
Float_t GeometryHelper::GetRotationCorrectedTPos(const CandStripHandle* csh, 
                                            const CandTrackHandle* cth)
{
    Int_t plane = csh->GetPlane();
    Float_t lpos(0.);
    // get lpos from the track (calculated by the tracker or fitter)
    if ( csh->GetPlaneView() == PlaneView::kU ) {
        lpos = cth->GetV(plane);
    } else if ( csh->GetPlaneView() == PlaneView::kV ) {
        lpos = cth->GetU(plane);
    }

    // check that lpos value looks valid
    if ( fabs(lpos) > 5 ) {
        MSG("FitTrackSA", Msg::kDebug) << "lpos = " << lpos  
        << " is either bad fit or hasn't been calculated, setting it to 0." 
        << endl;
        lpos = 0.;
    }
    
    UgliStripHandle ush = fUgh.GetStripHandle(csh->GetStripEndId());
    return ush.GetTPos(lpos);
}

///
///
///
Float_t GeometryHelper::GetRotationCorrectedTPos(const Reco::Strip_t strip, 
                                            const CandTrackHandle* cth)
{
    Int_t plane = strip->GetPlane();
    Float_t lpos(0.);
    // get lpos from the track (calculated by the tracker or fitter)
    if ( strip->GetPlaneView() == PlaneView::kU ) {
        lpos = cth->GetV(plane);
    } else if ( strip->GetPlaneView() == PlaneView::kV ) {
        lpos = cth->GetU(plane);
    }

    // check that lpos value looks valid
    if ( fabs(lpos) > 5 ) {
        MSG("FitTrackSA", Msg::kDebug) << "lpos = " << lpos  
        << " is either bad fit or hasn't been calculated, setting it to 0." 
        << endl;
        lpos = 0.;
    }
    
    UgliStripHandle ush = fUgh.GetStripHandle(strip->GetStripEndId());
    return ush.GetTPos(lpos);
}

