#ifndef MD_SIMULATOR_IMPL_H
#define MD_SIMULATOR_IMPL_H

#ifndef OWN_H
#include "Own.h"
#endif

#ifndef ARRAY_OF_OWN_H
#include "Array_of_own.h"
#endif

#ifndef ARRAY_OF_REF_H
#include "Array_of_ref.h"
#endif

#ifndef INTERACTION_H
#include "Interaction.h"
#endif

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

#ifndef MD_METHOD_H
#include "MD_method.h"
#endif

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

#ifndef MD_SIMULATOR_H
#include "MD_simulator.h"
#endif

#ifndef TEMPERATURE_UNIT_H
#include "Temperature_unit.h"
#endif

#ifndef THERMOSTAT_H
#include "Thermostat.h"
#endif

#ifndef BAROSTAT_H
#include "Barostat.h"
#endif

namespace MM
{
class Prototype;

class MD_simulator_impl : public  MD_simulator
{
    Own <MD_method>                     method_;
    Own <MD_subject>                    subject_;
    Own <Thermostat>                    thermostat_;
    Own <Barostat>                      barostat_;
    Own <MD>                            simulation_;

    //Temperature_unit                    starting_temperature_;
    double                              starting_pressure_;
    Temperature_unit                    final_temperature_;
    double                              final_pressure_;

    static Array_of_own <MD_method>     method_prototype_;//fix remove
    static MD_simulator_impl                 prototype_;

public:
    MD_simulator_impl (Prototype &);
    //MD_simulator_impl ();
    virtual Simulator *     clone () const {return new MD_simulator_impl (Model::none());}
    static MD_simulator_impl &   singleton ();

    explicit MD_simulator_impl (Model & model);

    //explicit MD_simulator_impl (Model &       model,
    //                       char const *  method_name = "Velocity_verlet");

    void                    add_comment (Text const & comment);

    Text const&             title () const {static Text r="MD"; return r;}

    void                    publish_step_finished ()                            {simulation_().publish_step_finished ();}

    MD_method &             method ()                                           {return method_();}
    char const *            method_name () const;
    void                    set_method      (char const * name);

    MD_subject &            subject ()                                          {return subject_();}

    Barostat &              barostat ()                                         {return barostat_();}
    Barostat const&         barostat () const                                   {return barostat_();}

    Thermostat &            thermostat ()                                       {return thermostat_();}
    Thermostat const&       thermostat () const                                 {return thermostat_();}

    void                    set_thermostat  (char const * name);
    void                    set_barostat    (char const * name);
    void                    add_monitor     (char const * name);

    bool                    is_running () const                                 {return simulation_().is_running();}
    void                    stop ()                                             {simulation_().stop();}

    void                    tune  ();
    void                    handle_start ();

    void                    edit_options (){}//fix

    bool                    support_duration () const                           {return true;}
    Duration_unit           duration () const;
    void                    set_duration (Duration_unit l);

    int                     steps     () const;
    void                    set_steps (int steps);

    bool                    support_temperature      () const                   {return true;}
    void                    setup_velocities         (Temperature_unit const& ){}//fix

    Temperature_unit        desired_temperature () const                        {return thermostat_().desired_temperature();}
    void                    set_desired_temperature (Temperature_unit const & t){thermostat_().set_desired_temperature(t);}

    double                  desired_pressure () const                           {return barostat_().desired_pressure();}
    void                    set_desired_pressure (double p)                     {barostat_().set_desired_pressure(p);}

    //void                    set_starting_temperature (Temperature_unit const& v){starting_temperature_=v;}//fix
//    void                    set_starting_pressure    (double v)                 {starting_pressure_=v;}//fix
    void                    set_final_temperature    (Temperature_unit const& v){final_temperature_=v;}
//    void                    set_final_pressure       (double v)                 {final_pressure_=v;}
    bool                    support_thermostat       () const                   {return true; /*method_().support_thermostat ();*/}
    bool                    support_barostat         () const                   {return true; /*method_().support_barostat ();*/}
    bool                    has_thermostat           () const                   {return simulation_().thermostat().is_on ();}//{return method_().has_thermostat ();}
    bool                    has_barostat             () const                   {return simulation_().barostat  ().is_on (); /*method_().has_barostat ();*/}
    void                    set_thermostat (bool on)                            {simulation_().thermostat().turn (on);}//fix {method_(). set_thermostat (on);}
    void                    set_barostat   (bool on)                            {simulation_().barostat  ().turn (on);}
    void                    after_each_step           (Command * to_do);
    void                    after_stop                (Command * to_do);
    void                    eliminate_after_each_step (Command & to_do);
    void                    eliminate_after_stop      (Command & to_do);
//    void                    unsubscribe (MD_monitor & to_do);    //fix

    void                    update ();
};

}//MM

#endif //MD_SIMULATOR_IMPL_H
