#ifndef CONVENTIONAL_INTERACTIONS_H
#define CONVENTIONAL_INTERACTIONS_H

#ifndef BOND_GROUP_CACHE_H
#include "Bond_group_cache.h"
#endif

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

#ifndef ENERGY_H
#include "Energy.h"
#endif

#ifndef COMMON_INTERACTIONS_H
#include "Common_interactions.h"
#endif

#include <set>

namespace MM
{
struct Bond_cache;
struct Atom_cache;

class Conventional_interactions :
    public Bond_group_cache,
    public Common_interactions
{
protected:
    static const int water;
    std::set <Atom_cache const *>   miss_set_;

public:
    Interaction * clone () const
    {
        return new Conventional_interactions (model_);
            //(atom_group_, bond_group_, force_field_);
    }

    //virtual Common_interactions * clone (Atom_group &  atom_group,
    //                               Bond_group &  bond_group,
    //                               Force_field & ff) const
    //{return new Conventional_interactions (atom_group, bond_group, ff);}

    virtual Common_interactions * clone (Model & model/*,
                                   Force_field & ff*/) const
    {return new Conventional_interactions (model/*, ff*/);}

    //Conventional_interactions (Atom_group & atom_group, Force_field & ff);

    //Conventional_interactions (Atom_group & atom_group,
    //                     Bond_group & bond_group, Force_field & ff);

    Conventional_interactions (Model & model/*, Force_field & ff*/);

    virtual double      potential ();
    virtual void        add_force ();

    virtual Text        title () const {return "Conventional";}

protected:
    friend class Covalent_interactions_test;

    virtual void        zero_forces ();
    virtual int         atom_count()    {return atom_group_.atom_count();}
    virtual int         bond_count()    {return bond_group_.bond_count();}

    virtual void        atom_potential          (Atom_cache & atom);
    virtual void        bond_potential          (Bond_cache const & bond);

    virtual void        nonbonded_potential         (Atom_cache       & atom);
    virtual void        angle_potential             (Atom_cache const & atom);
    virtual void        SPCf_potential              (Atom_cache  & atom, bool force = false);
    virtual void        improper_torsion_potential  (Atom_cache const & bond);
    virtual void        bond_stretch_potential      (Bond_cache const & bond);
    virtual void        torsion_potential           (Bond_cache const & bond);

    virtual void        add_atom_force              (Atom_cache &       atom);
    virtual void        add_bond_force              (Bond_cache &       bond);

    virtual void        add_nonbonded_force         (Atom_cache & atom);
    virtual void        add_angle_force             (Atom_cache & atom, Force_field & ff);
    virtual void        add_improper_torsion_force  (Atom_cache & bond);
    virtual void        add_bond_stretch_force      (Bond_cache & bond);
    virtual void        add_torsion_force           (Bond_cache & bond);

    virtual void        process_14              (Atom_cache &, Task );
    virtual void        nonbonded_potential_14  (Atom_cache &, Atom_cache &);
    virtual void        add_nonbonded_force_14  (Atom_cache &, Atom_cache &);
    virtual void        list_nonbonded_14       (Atom_cache &, Atom_cache &);
    virtual void        miss_neighbours         (Atom_cache const &);
    virtual void        restore_neighbours      ();
};

}//MM

#endif //CONVENTIONAL_INTERACTIONS_H
