#ifndef MD_H
#define MD_H

#ifndef SIMULATION_H
#include "Simulation.h"
#endif

#ifndef TEXT_H
#include "Text.h"
#endif

#ifndef MD_SUBJECT_H
#include "MD_subject.h"
#endif

#ifndef EVENT_H
#include "Event.h"
#endif

namespace MM
{
class MD_method;
class Thermostat;
class Barostat;
class Temperature_unit;

class MD : public Simulation, protected MD_subject
{
    friend class Replica_exchange;

protected:
    double                              step_length_;   // AKMA time units
    double                              drift_length_;  //fix Why? Sum!
    double                              kick_length_;

    MD_subject *                        subject_;
    MD_method  *                        method_;
    Thermostat *                        thermostat_;
    Barostat *                          barostat_;

    Event                               step_finished_;
    Event                               stop_;
    bool                                stop_flag_;

public:
    MD ();
    explicit MD (MD_subject & subject, MD_method & method);

    virtual char const *    class_name () const {return "MD";}
    MD_subject &    interface_for (MD_method const*) {return *this;}

    void                publish_step_finished () {step_finished_.publish();}

    //virtual MD *    clone (MD_subject & subject) const =0;

    //bool           is_running () const  {return !stop_flag_;}

    // externally in picoseconds and internally in AKMA time units
    double              step_length () const;
    void                set_step_length (double new_length);

    void                set_method  (MD_method & new_method);
    void                set_subject (MD_subject & new_subject);

    void                setup_velocities ();
    void                setup_velocities (Temperature_unit const& t);

    Thermostat &        thermostat ()                                           {return *thermostat_;}
    Thermostat const&   thermostat () const                                     {return *thermostat_;}
    void                set_thermostat (Thermostat & thermostat)                {thermostat_ = &thermostat;}

    Barostat &          barostat ()                                             {return *barostat_;}
    Barostat const&     barostat () const                                       {return *barostat_;}
    void                set_barostat (Barostat & barostat)                      {barostat_ = &barostat;}

    void    after_each_step (Command * to_do)
    {
        step_finished_.subscribe (to_do);
    }

    void    eliminate_after_each_step (Command & to_do)
    {
        step_finished_.subscribe (&to_do, false);
    }

    void    after_stop (Command * to_do)
    {
        stop_.subscribe (to_do);
    }

    void    eliminate_after_stop (Command & to_do)
    {
        stop_.subscribe (&to_do, false);
    }

    void                    stop () {stop_flag_ = true;}


    virtual Text    title () const;
//        { static const Text name = "MD";    return name;}
    virtual bool        locked () const;
    virtual void        set_lock (bool on);

protected:
    virtual void        start      ();
    virtual void        cycle      ();     //fix loop
    //virtual void        step       () =0;
    virtual int         iterations () const;
    virtual void        finish     ();

    virtual void        zero_virial ();
    double              degrees_of_freedom ();
    double              H ();
    double              K ();
    double              U ();
    virtual void        list  (Hint hint, double skin);
    virtual void        list  (Hint hint, double R, double skin);
    virtual void        F     (Hint hint);
    virtual void        F     (Hint hint, double R, double Switching);
    virtual void        clear_moment (Hint hint);
    virtual void        kick  (double h, Hint hint);
    virtual void        kick  (int substeps, double dT, Hint hint);
    virtual void        drift (double h);
    virtual void        keep_configuration ();
    virtual void        restore_configuration ();
    virtual void        update (bool force = false);

protected:
    //bool                invariant () const;
};

}//MM

#endif //MD_H
