#ifndef M_DYNAMIX_SIMULATOR_H
#define M_DYNAMIX_SIMULATOR_H

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

#ifndef M_DYNAMIX_INPUT_H
#include "M_DynaMix_input.h"
#endif

#ifndef MODEL_H
#include "Model.h"
#endif

//#ifndef ARBITRARY_ATOM_GROUP_H
//#include "Arbitrary_atom_group.h"
//#endif

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

#ifndef M_DYNAMIX_PROCESS_H
#include "M_DynaMix_process.h"
#endif

#ifndef INTERFACE_FOR_M_DYNAMIX_PROCESS_H
#include "Interface_for_M_DynaMix_process.h"
#endif

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

#ifndef CREATE_H
#include "Create.h"
#endif

namespace MM
{
class Prototype;
class Molecule;
class Atom_group;
class Arbitrary_atom_group;
class Bond_group;
class Collect_potential_from_mDynaMix;
class Collect_temperature_from_mDynaMix;
class Collect_pressure_from_mDynaMix;
class Collect_density_from_mDynaMix;
class MD_method;

class M_DynaMix_simulator
    //: public MD_simulator
    : public Simulator_frame
    , protected Interface_for_M_DynaMix_process
{
    M_DynaMix_input                     m_dynamix_input_;
    //M_DynaMix_input &                   m_dynamix_input_;
//    Run_M_DynaMix                       run_M_DynaMix_;
    Own <M_DynaMix_process>             m_DynaMix_process_;

    Event                               step_finished_;
    Event                               stop_;

    Collect_potential_from_mDynaMix *   potential_monitor_;
    Collect_temperature_from_mDynaMix * temperature_monitor_;
    Collect_pressure_from_mDynaMix *    pressure_monitor_;
    Collect_density_from_mDynaMix *     density_monitor_;

    static M_DynaMix_simulator          prototype_;

public:
    explicit            M_DynaMix_simulator (Prototype &);
    explicit            M_DynaMix_simulator ();
    virtual Simulator * clone () const {return new M_DynaMix_simulator;}

    Interface_for_M_DynaMix_process &   interface_for (M_DynaMix_process const*){return *this;}

    MD_method &             method ()                 {return nil<MD_method>();}
    char const *            method_name() const       {FLAW("should not be calld.");}
    void                    set_method (char const *) {FLAW("should not be calld.");}

    virtual char const* class_name () const {return "M_DynaMix_simulator";}
    Text const&         title      () const {static Text r="MDynaMix"; return r;}

    void                add_comment (Text const &){}

    void                set_model (Model &model);

    bool                is_running () const     {return m_DynaMix_process_.is_valid() && m_DynaMix_process_().is_running ();}
    void                stop ();

    void                tune  ();
    void                handle_start ();

    void                edit_options ();

    bool                    support_duration          () const {return true;}
    //double              step_length               () const; // picoseconds
    //void                set_step_length           (double new_length); // picoseconds
    Duration_unit       duration () const;
    void                set_duration (Duration_unit l);

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

    double              desired_pressure () const;
    void                set_desired_pressure (double);

    bool                support_temperature       () const      {return true;}
    void                setup_velocities          (Temperature_unit const& v) {set_desired_temperature (v);}//fix
    Temperature_unit    desired_temperature      () const;
    void                set_desired_temperature  (Temperature_unit const& v);
    void                set_starting_pressure     (double v);
    void                set_final_temperature     (Temperature_unit const& v);
//    void                set_final_pressure        (double v);
    bool                support_thermostat        () const      {return true;}
    bool                support_barostat          () const      {return true;}
    bool                has_thermostat            () const;
    bool                has_barostat              () const;
    void                set_thermostat            (bool on);
    void                set_barostat              (bool on);

    void                add_monitor               (char const * name);

    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                update ();

protected:
    Text                                output_file_name () const               {return m_dynamix_input_.main_file_name() + ".output";}
    Collect_potential_from_mDynaMix &   potential_monitor   ()                  {return *potential_monitor_;}
    Collect_temperature_from_mDynaMix & temperature_monitor ()                  {return *temperature_monitor_;}
    Collect_pressure_from_mDynaMix &    pressure_monitor    ()                  {return *pressure_monitor_;}
    Collect_density_from_mDynaMix &     density_monitor     ()                  {return *density_monitor_;}

    virtual void        publish_step_finish ()                                  {step_finished_.publish();}

    // extention of Simulator_frame::create_monitor
    //MD_monitor *        create_monitor (Text const & monitor);

    void                clear                     (Arbitrary_atom_group *);
    void                remove_STOP_file          ();
    void                detect_molecules          ();
    void                write_type_of_molecules   (Arbitrary_atom_group *);
    void                write_coords              (Atom_group const &);
    void                write_input               ();
    //void                start_mDynaMix            (Atom_group *);

    void                setup_molecular_type      (Text const &       type_name,
                                                   Text const &       formula,
                                                   Atom_group &       atoms,
                                                   Bond_group const & bonds,
                                                   Arbitrary_atom_group *);

    bool                has_the_same_type         (Molecule & first_mol,
                                                   Molecule & second_mol);
    //void                read_mDynaMix_output      (FILE * output, Atom_group *);
};

}//MM

#endif //M_DYNAMIX_SIMULATOR_H
