/**
 * @if Er7UtilsUseGroups
 * @addtogroup Er7Utils
 * @{
 * @addtogroup Integration
 * @{
 * @endif
 */

/**
 * @file
 * Defines the class BeemanIntegratorConstructor, which constructs integrators
 * that use Beeman's method.
 */

/*
Purpose: ()
*/


#ifndef ER7_UTILS_BEEMAN_INTEGRATOR_CONSTRUCTOR_HH
#define ER7_UTILS_BEEMAN_INTEGRATOR_CONSTRUCTOR_HH

// System includes

// Interface includes
#include "er7_utils/interface/include/er7_class.hh"

// Integration includes
#include "er7_utils/integration/core/include/priming_integrator_constructor.hh"
#include "er7_utils/integration/rk2_heun/include/rk2_heun_integrator_constructor.hh"


namespace er7_utils {

/**
 * Create state and time integrators that propagate using Beeman's method.
 */
class BeemanIntegratorConstructor : public PrimingIntegratorConstructor {
ER7_UTILS_MAKE_SIM_INTERFACES(BeemanIntegratorConstructor)

public:
   // Static member functions.

   /**
    * Named constructor; create a BeemanIntegratorConstructor instance.
    * The caller is responsible for deleting the returned object.
    * @return Newly created BeemanIntegratorConstructor instance.
    */
   static IntegratorConstructor* create_constructor (void);


   // Constructors and assignment operator
   // Note that the destructor is not declared.
   // The implicitly defined destructor is correct.

   /**
    * Beeman default constructor.
    * Note that by default Beeman uses Heun's method for priming.
    */
   BeemanIntegratorConstructor (void)
   :
      Er7UtilsDeletable (),
      PrimingIntegratorConstructor (RK2HeunIntegratorConstructor ())
   {}

   /**
    * BeemanIntegratorConstructor copy constructor.
    */
   BeemanIntegratorConstructor (const BeemanIntegratorConstructor & src)
   :
      Er7UtilsDeletable (),
      PrimingIntegratorConstructor (src)
   {}

   /**
    * BeemanIntegratorConstructor assignment operator.
    */
   BeemanIntegratorConstructor & operator= (BeemanIntegratorConstructor src)
   {
      swap (src);
      return *this;
   }


   // Member functions.

   /**
    * Return the class name.
    */
   virtual const char * get_class_name (void) const
   { return "BeemanIntegratorConstructor"; }

   /**
    * Beeman is a second order technique; it provides but does not implement
    * a first order ODE integrator. It currently does not implement or provide
    * a second order generalized step integrator.
    */
   virtual bool implements (Integration::ODEProblemType problem_type) const
   {
      return (problem_type != Integration::FirstOrderODE) &&
             (problem_type != Integration::GeneralizedStepSecondOrderODE);
   }

   /**
    * Beeman currently does not provide a second order generalized step
    * integrator.
    */
   virtual bool provides (Integration::ODEProblemType problem_type) const
   {
      return (problem_type != Integration::GeneralizedStepSecondOrderODE);
   }

   /**
    * Create a duplicate of the constructor.
    * The caller is responsible for deleting the returned object.
    * @return Duplicated constructor.
    */
   virtual IntegratorConstructor * create_copy (void) const;

   /**
    * Create an integration controls that guides the Beeman integration process.
    * The caller is responsible for deleting the created object.
    * @return Integration controls object
    */
   virtual IntegrationControls * create_integration_controls (void) const;

   /**
    * Create a Beeman state integrator for a first order ODE.
    * The caller is responsible for deleting the created object.
    * @return State integrator
    * @param[in]     size      State size
    * @param[in,out] controls  Integration controls
    */
   virtual FirstOrderODEIntegrator * create_first_order_ode_integrator (
      unsigned int size,
      IntegrationControls & controls) const;

   /**
    * Create a Beeman state integrator for a simple second order ODE.
    * The caller is responsible for deleting the created object.
    * @return State integrator
    * @param[in]     size      State size
    * @param[in,out] controls  Integration controls
    */
   virtual SecondOrderODEIntegrator * create_second_order_ode_integrator (
      unsigned int size,
      IntegrationControls & controls) const;

   /**
    * Create a Beeman state integrator for a generalized second order ODE
    * where generalized position is advanced with the use of the
    * position derivative function.
    * The caller is responsible for deleting the created object.
    * @return State integrator
    * @param[in]     position_size  Size of the generalized position
    * @param[in]     velocity_size  Size of the generalized velocity
    * @param[in]     deriv_funs     Position derivative functions container
    * @param[in,out] controls       Integration controls
    */
   virtual SecondOrderODEIntegrator *
   create_generalized_deriv_second_order_ode_integrator (
      unsigned int position_size,
      unsigned int velocity_size,
      const GeneralizedPositionDerivativeFunctions & deriv_funs,
      IntegrationControls & controls) const;

#if 0
   /**
    * Create a Beeman state integrator for a generalized second order ODE
    * where generalized position is advanced with the use of the
    * position step function.
    * The caller is responsible for deleting the created object.
    * @return State integrator
    * @param[in]     position_size  Size of the generalized position
    * @param[in]     velocity_size  Size of the generalized velocity
    * @param[in]     step_funs      Position step functions container
    * @param[in,out] controls       Integration controls
    */
   virtual SecondOrderODEIntegrator *
   create_generalized_step_second_order_ode_integrator (
      unsigned int position_size,
      unsigned int velocity_size,
      const GeneralizedPositionStepFunctions & step_funs,
      IntegrationControls & controls) const;
#endif


   /**
    * Indicate whether the integration technique explicitly solves a second
    * order ODE. Beeman's method is such a technique.
    * @return Always returns true.
    */
   virtual bool is_second_order_ode_technique (void) const
   { return true; }

   /**
    * Beeman uses two steps per cycle once primed.
    * @return Always returns 2.
    */
   virtual unsigned int get_transition_table_size (void) const
   { return 2; }

   /**
    * Beeman needs a history of two derivatives.
    * @return Always returns 2.
    */
   virtual unsigned int get_history_length (void) const
   { return 2; }
};

}


#ifdef ER7_UTILS_NEED_AUX_INCLUDES
#include "er7_utils/integration/core/include/priming_integration_controls.hh"
#include "er7_utils/integration/rk2_heun/include/rk2_heun_first_order_ode_integrator.hh"
#include "beeman_second_order_ode_integrator.hh"
#endif


#endif
/**
 * @if Er7UtilsUseGroups
 * @}
 * @}
 * @endif
 */
