#ifndef MD_METHOD_H
#define MD_METHOD_H

#ifndef DBC_H
#include "DbC.h"
#endif

#ifndef MD_H
#include "MD.h"
#endif

namespace MM
{
//class MD;
//class MD_subject;
class Prototype;

class MD_method : protected DbC
{
protected:
//    MD_subject *                    subject_;
    MD *                        simulation_;
    int                         step_N_;

    int             update_list_;
    double          skin_;

public:
    static MD_method *          create (Text const & method);
    static int                  prototype_count ();
    static MD_method &          prototype (int n);
    static void                 adopt_prototype (MD_method * method);

//    explicit MD_method (MD_subject & subject) : subject_(&subject) { }
    MD_method () : simulation_(0), step_N_(0), update_list_(4), skin_(.5)  { }
    virtual ~MD_method ();

    virtual MD_method * clone () const =0;
    virtual char const* class_name () const =0;
    virtual char const* title      () const =0;
    virtual char const* alias      () const =0;

    virtual void        start  ();
    virtual void        step   () =0;
    virtual void        finish ();

    virtual bool        support_thermostat () const {return false;}
    virtual bool        support_barostat   () const {return false;}
    virtual bool        has_thermostat     () const {return false;}
    virtual bool        has_barostat       () const {return false;}
    virtual void        set_thermostat     (bool)   {FLAW("Not implemented.");}
    virtual void        set_barostat       (bool)   {FLAW("Not implemented.");}

    MD &        simulation ()                     {return *simulation_;}
    MD const &  simulation () const               {return *simulation_;}
    void        set_simulation (MD & simulation)  {simulation_ = &simulation;}
    virtual int iterations () const               {return simulation_->steps();}

    int         update_list ()  const       {return update_list_;}
    void        set_update_list (int v)     {update_list_= v;}

    double      skin ()  const              {return skin_;}
    void        set_skin (double v)         {skin_= v;}

protected:
    void    zero_virial ();
    virtual double  degrees_of_freedom () const;
    virtual double  H () const;
    virtual double  K () const;
    virtual double  U () const;
    void    list (MD_subject::Hint hint, double skin);
    void    list (MD_subject::Hint hint, double R, double skin);
    void    F    (MD_subject::Hint hint = MD_subject::Whole);
    void    F    (MD_subject::Hint hint, double R, double Switching);

    void    clear_moment (MD_subject::Hint hint);
    void    kick (double h, MD_subject::Hint hint = MD_subject::Whole);
    void    kick (int substeps, double dT, MD_subject::Hint hint = MD_subject::Whole);
    void    drift(double h);
    void    keep_configuration ();
    void    restore_configuration ();

    virtual bool invariant() const    {return simulation_ != 0;}
};

}//MM

#endif //MD_METHOD_H
