//_____________________________________________________________________________
///
/// \class AlgFitTrackSA
///
/// AlgFitTrackSA - iterative least squares track fitter.
/// This package provides an iterative least squares track fitter (as
/// described in NuMI-301 note). It works on candidate tracks produced
/// by a track finding (or track fitting) package.  
/// 
/// This fitter can be added to the job path by inserting 
/// "FitTrackSAListModule::Reco" job module.
/// 
/// Fit results are not saved in the standard ntuple, but can be 
/// saved in a NtpFitSA by adding the following job path (or adding 
/// to an existing path):
/// 
///   //Ntuple record has its own output file so needs its own output module
///   j.Path.Create("Ntp",
///                         "NtpFitSAModule::Reco " // create NtpStRecord
///                         "Output::Put ");
/// 
///   j.Path("Ntp").Mod("Output").Cmd("DefineStream NtpFitSA NtpFitSARecord");
///   j.Path("Ntp").Mod("Output").Set("Streams=NtpFitSA");
///   j.Path("Ntp").Mod("Output").Set("FileName=ntpSA.root");
/// 
/// \author Sergei avva@fnal.gov
///

#include <cassert>
#include <vector>

#include "TStopwatch.h"

#include "MessageService/MsgService.h"
#include "Plex/PlexPlaneId.h"
#include "RecoBase/CandTrackHandle.h"

#include "Swimmer/SwimSwimmer.h"

#include "CandFitTrackSA/AlgFitTrackSA.h"
#include "CandFitTrackSA/CandFitTrackSAHandle.h"
#include "CandFitTrackSA/FitContext.h"
#include "CandFitTrackSA/FitStateFactory.h"
#include "CandFitTrackSA/Ntp/NtpFitSA.h"
#include "CandFitTrackSA/TracerSA.h"
#include "CandFitTrackSA/TrackContext.h"
#include "CandFitTrackSA/TrackFilter.h"
#include "CandFitTrackSA/TrackFilterFactory.h"
#include "CandFitTrackSA/TrackSegmentMaker.h"

#include "CandFitTrackSA/TrackSegmentMakerDummy.h"
#include "CandFitTrackSA/TrackEstimatorFixed.h"

CVSID("$Id: AlgFitTrackSA.cxx,v 1.33 2006/02/04 21:47:35 avva Exp $");

using std::vector;

ClassImp(AlgFitTrackSA)

AlgFitTrackSA::AlgFitTrackSA() :
    fFilter(0), fSegmentMaker(0), 
    fEstimator(0), fSwimmer(0)
{
    TracerSA trace("AlgFitTrackSA::AlgFitTrackSA()");
}


AlgFitTrackSA::~AlgFitTrackSA()
{
    TracerSA trace("AlgFitTrackSA::~AlgFitTrackSA()");        
    delete fSegmentMaker; fSegmentMaker = 0;
    delete fEstimator; fEstimator = 0;
    delete fSwimmer; fSwimmer = 0;
}

///
/// The "main" method of the algorithm (also the only public method) 
///
void AlgFitTrackSA::RunAlg(AlgConfig& ac,
                            CandHandle& ch, CandContext& candTrackContext)
{
    TracerSA trace("AlgFitTrackSA::RunAlg(AlgConfig& , CandHandle& , CandContext& )");

    CandFitTrackSAHandle& cftsah = (CandFitTrackSAHandle&) ch;
    TrackContext trackContext(candTrackContext);

    // todo on first call
    static Bool_t first = kTRUE;
    if ( first ) {
        first = kFALSE;
        // create filter, segment maker, estimator and swimmer
        // and configure them
        
        // TrackFilter 
        const char* filterName = ac.GetCharString("TrackFilter");
        fFilter = TrackFilterFactory::Instance().GetTrackFilter(filterName);
        fFilter->Config(ac); 
        
        // Segment Maker
        fSegmentMaker = new TrackSegmentMakerDummy();
        fSegmentMaker->Config(ac); 
        
        // TrackExtimator        
        fEstimator = new TrackEstimatorFixed();
        fEstimator->Config(ac);
        
        // Swimmer
        fSwimmer = new SwimSwimmer(trackContext.GetVldContext());
    }
            
    // check if the track passes filter (return otherwise)
    // (don't really have to configure fiter every time)
    if ( ! fFilter->Pass(trackContext) ) {
        MSG("FitTrackSA",Msg::kVerbose) 
           << "Track failed cuts, skipping." << "\n";
        return;
    }
    
    // split track into segments
    vector<TrackContext> segments;
    Int_t status = fSegmentMaker->MakeSegments(trackContext, segments);
    assert( status == 0 && "Couldn't make segments!" );
    
    // loop over track segments and fit each one
    typedef vector<TrackContext>::const_iterator TCItr;
    for ( TCItr it = segments.begin(); it != segments.end(); ++it) {
        NtpFitSA ntp = DoFit(ac, *it);
        // Add ntuple to CandFitTrackSA 
        cftsah.AddNtpFitSA(ntp);
    }
 
    // that's all
    return;   
}


///
/// main fitting method
///
NtpFitSA AlgFitTrackSA::DoFit(const AlgConfig& ac, const TrackContext& trackContext)
{
    TracerSA trace("AlgFitTrackSA::DoFit(const TrackContext& )");
        
    FitContext fit(ac, trackContext, fEstimator, fSwimmer);

    FitStateFactory& fitStateFactory = FitStateFactory::Instance();
    
    // Start timer
    TStopwatch timer;
    timer.Start();
    
    // main loop -> iterate until fit goes into "Final" state
    while ( fit.fState != fitStateFactory.GetFitState("Final") ) {
        fit.Iterate();
    }
    
    fit.Iterate();    
    
    // stop timer and save cputime
    timer.Stop();
    fit.SetCpu(timer.CpuTime());
    
    return fit.MakeNtpFitSA();
}

