#ifndef GsfTrajectorySmoother_H_
#define GsfTrajectorySmoother_H_

#include "TrackingTools/PatternTools/interface/TrajectorySmoother.h"
#include "TrackingTools/PatternTools/interface/TrajectoryStateUpdator.h"
#include "TrackingTools/GeomPropagators/interface/Propagator.h"
#include "TrackingTools/TrajectoryState/interface/TrajectoryStateOnSurface.h"
#include "TrackingTools/DetLayers/interface/MeasurementEstimator.h"
#include "TrackingTools/PatternTools/interface/TrajectoryMeasurement.h"
#include "TrackingTools/GsfTracking/interface/GsfPropagatorWithMaterial.h"
#include "TrackingTools/GsfTools/interface/GsfPropagatorAdapter.h"
#include "TrackingTools/GsfTracking/interface/FullConvolutionWithMaterial.h"
#include "TrackingTools/DetLayers/interface/DetLayerGeometry.h"

class MultiTrajectoryStateMerger;

/** A GSF smoother, similar to KFTrajectorySmoother, but (for
 *  testing purposes) without combination with the forward fit. 
 */

class GsfTrajectorySmoother final : public TrajectorySmoother {
private:
  typedef TrajectoryStateOnSurface TSOS;
  typedef TrajectoryMeasurement TM;

public:
  /** Constructor with explicit components for propagation, update,
   *  chi2 calculation, merging and flag for merging before / after
   *  the update (i.e. fully configured). It clones the algorithms. */
  GsfTrajectorySmoother(const GsfPropagatorWithMaterial& aPropagator,
                        const TrajectoryStateUpdator& aUpdator,
                        const MeasurementEstimator& aEstimator,
                        const MultiTrajectoryStateMerger& merger,
                        float errorRescaling,
                        const bool materialBeforeUpdate = true,
                        const DetLayerGeometry* detLayerGeometry = nullptr);

  ~GsfTrajectorySmoother() override;

  Trajectory trajectory(const Trajectory& aTraj) const override;

  const TrajectoryStateUpdator* updator() const { return theUpdator; }
  const MeasurementEstimator* estimator() const { return theEstimator; }

  GsfTrajectorySmoother* clone() const override {
    return new GsfTrajectorySmoother(
        *theAlongPropagator, *theUpdator, *theEstimator, *theMerger, theErrorRescaling, theMatBeforeUpdate, theGeometry);
  }

  void setHitCloner(TkCloner const* hc) override {}

private:
  const GsfPropagatorWithMaterial* theAlongPropagator;
  const GsfPropagatorWithMaterial* theOppositePropagator;
  const GsfPropagatorAdapter* theGeomPropagator;
  const FullConvolutionWithMaterial* theConvolutor;
  const TrajectoryStateUpdator* theUpdator;
  const MeasurementEstimator* theEstimator;
  const MultiTrajectoryStateMerger* theMerger;

  bool theTiming;
  bool theMatBeforeUpdate;
  float theErrorRescaling;

  const DetLayerGeometry dummyGeometry;
  const DetLayerGeometry* theGeometry;
};

#endif  //TR_GsfTrajectorySmoother_H_
