#ifndef COMMON_INTERACTIONS_H
#define COMMON_INTERACTIONS_H

//#ifndef MODEL_KIT_H
//#include "Model_kit.h"
//#endif

#ifndef INTERACTION_FRAME_H
#include "Interaction_frame.h"
#endif

#ifndef FORCE_FIELD_H
#include "Force_field.h"
#endif

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

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

namespace MM
{
class Atom_group;
class Bond_group;
class Model_kit;

class Common_interactions : public Interaction_frame
{
protected:
    Model &                 model_;
    //Force_field &           force_field_;

    double                  Van_der_Waals_potential_;
    double                  electrostatic_potential_;
    double                  bond_potential_;
    double                  angle_potential_;
    double                  torsion_potential_;
    double                  improper_torsion_potential_;
    double                  hydrophobic_potential_;
    double                  surface_area_potential_;
    double                  generalized_Born_potential_;
    double                  induction_potential_;
    double                  water_potential_;
    static bool             ad_hoc_;

    double                  intermolecular_Van_der_Waals_potential_;
    double                  intermolecular_electrostatic_potential_;
    double                  intermolecular_induction_potential_;

    double                  cutoff_;
    bool                    cutoff_eq_Rm_;

    //double                  I_cut_;

public:
    virtual Interaction *   clone () const =0;
    //virtual Common_interactions * clone (Atom_group &  atom_group,
    //                                     Bond_group &  bond_group,
    //                                     Force_field & ff) const =0;

    virtual Common_interactions * clone (Model & model/*,
                                         Force_field & ff*/) const =0;

    explicit Common_interactions (Model & model/*, Force_field & ff*/)
    :
        model_                      (model),
        //force_field_                (ff),
        Van_der_Waals_potential_    (0.),
        electrostatic_potential_    (0.),
        bond_potential_             (0.),
        angle_potential_            (0.),
        torsion_potential_          (0.),
        improper_torsion_potential_ (0.),
        hydrophobic_potential_      (0.),
        surface_area_potential_     (0.),
        generalized_Born_potential_ (0.),
        induction_potential_        (0.),
        water_potential_            (0.),
        intermolecular_Van_der_Waals_potential_ (0.),
        intermolecular_electrostatic_potential_ (0.),
        intermolecular_induction_potential_     (0.),
        cutoff_                     (1000000.),
        cutoff_eq_Rm_               (true)/*,
        ad_hoc_                     (false)*/
    {
    }

    /*explicit Common_interactions (Force_field & ff)
    : 
        model_                      (nil<Model>()),
        force_field_                (ff),
        Van_der_Waals_potential_    (0.),
        electrostatic_potential_    (0.),
        bond_potential_             (0.),
        angle_potential_            (0.),
        torsion_potential_          (0.),
        improper_torsion_potential_ (0.),
        hydrophobic_potential_      (0.)
    {
    }//*/

    virtual void        report (Text *result, Text const & hint = Text("Full"));

    Force_field &       force_field ();
    Force_field const & force_field () const;

    static bool         ad_hoc () /*const*/                                         {return ad_hoc_;}
    static void         set_ad_hoc (bool on)                                    {ad_hoc_ = on;}

    double              epsilon () const                                        {return force_field().eps;}
    void                set_epsilon (double v)                                  {force_field().eps = v;}


    
    bool                cutoff_eq_Rm () const                                   {return cutoff_eq_Rm_;}
    void                set_cutoff_eq_Rm (bool on)                              {cutoff_eq_Rm_ = on;}

    //double              L () const                                         {return force_field().Rm_;}
    //void                set_L (double v)                                   {force_field().Rm_ = v;}

    double              cutoff () const                                         {return cutoff_eq_Rm() ? force_field().Rm_ : cutoff_;}
    void                set_cutoff (double v)                                   {cutoff_ = v;}

    //double              I_cut () const                                          {return I_cut_;}
    //void                set_I_cut (double v)                                    {I_cut_ = v;}

    double              rm () const                                             {return force_field().Rm_;}
    void                set_rm (double v)                                       {force_field().Rm_ = v;}

    virtual bool        implicit_water () const                                 {return false;}
//    virtual void        set_implicit_water (bool)                               {;}

    virtual double      last_Van_der_Waals_potential    () const                {return Van_der_Waals_potential_;}
    virtual double      last_electrostatic_potential    () const                {return electrostatic_potential_;}
    virtual double      last_bond_potential             () const                {return bond_potential_;}
    virtual double      last_angle_potential            () const                {return angle_potential_;}
    virtual double      last_torsion_potential          () const                {return torsion_potential_;}
    virtual double      last_improper_torsion_potential () const                {return improper_torsion_potential_;}
    virtual double      last_hydrophobic_potential      () const                {return hydrophobic_potential_;}

    virtual double      last_intermolecular_potential               () const    {return intermolecular_Van_der_Waals_potential_ + intermolecular_electrostatic_potential_ + intermolecular_induction_potential_;}
    virtual double      last_intermolecular_Van_der_Waals_potential () const    {return intermolecular_Van_der_Waals_potential_;}
    virtual double      last_intermolecular_electrostatic_potential () const    {return intermolecular_electrostatic_potential_;}
    virtual double      last_intermolecular_induction_potential     () const    {return intermolecular_induction_potential_;}

    virtual double      last_surface_area_potential     () const                {return surface_area_potential_;}
    virtual double      last_generalized_Born_potential () const                {return generalized_Born_potential_;}
    virtual double      last_continuum_solvation_potential () const             {return surface_area_potential_ + generalized_Born_potential_;}
    virtual double      last_induction_potential        () const                {return induction_potential_;}
    virtual double      last_water_potential            () const                {return water_potential_;}

    // Defined in subclasses
    static Common_interactions *    create (Model & Model/*,
                                            Force_field & ff*/);

    //static Common_interactions *    create (Atom_group &  atom_group,
    //                                        Bond_group &  bond_group,
    //                                        Force_field & ff);
};

}//MM

#endif //COMMON_INTERACTIONS_H
