// Molecule.h: interface for the CMolecule class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_MOLECULE_H__4A25AAA7_10C1_4F46_B82A_56A6C57A0AF3__INCLUDED_)
#define AFX_MOLECULE_H__4A25AAA7_10C1_4F46_B82A_56A6C57A0AF3__INCLUDED_

#include <string>
#include <vector>



//This is the definition for one atom c are cartesian coordiantes
//name is C,N,H
//label will be the atom numbering
//and conexion is a vector of integers containg atoms connected with
#include "atom.h"
#include "frequency.h"
#include "iarrays.h"
#include "threshold.h"
#include "aim.h"
#include "kryomolecule_export.h"

class KRYOMOLECULE_EXPORT CMolecule
{
public:  //public methods
  enum Charge { ESP, MULLIKEN, NBO, AIM };
  struct pair
  {
  public:
    pair() {i=j=-1; value="";}
    pair(int a,int b,const std::string& s) {i=a;j=b;value=s;}
    int i; int j; std::string value;
  };
  struct triad
  {
  public:
    triad() { i=j=k=-1; value="";}
    triad(int a, int b, int c, const std::string& s) {i=a;j=b;k=c;value=s;}
    int i; int j; int k; std::string value;
  };
  struct quad
  {
  public:
    quad() { i=j=k=l=-1; value="";}
    quad(int a, int b, int c, int d,const std::string& s) {i=a;j=b;k=c;l=d;value=s;}
    int i; int j; int k; int l; std::string value;
  };

  class Coupling
  {
   public:
   Coupling(int i, int j, double value)  { _i=i; _j=j; _value=value; }
   int I() const { return _i; }
   int J() const { return _j; }
   double Value() const { return _value; }
   private:
   int _i;
   int _j;
   double _value;
  };



  CMolecule();
  virtual ~CMolecule();
  std::vector<CAtom> m_atom;
  void SelectAtom(int i,bool b=true);
  /** No descriptions */
  float CalculateDihedral(int i, int j);
  /** No descriptions */
  float GetDistance(int atom1, int atom2);
  /** No descriptions */
  float GetHCdistance(int h);
  /** returns molecular weight */
  double GetMolecularWeight();
  /** Calculate an approximate center of masses for better rotation handling
  it is not really CM cause all atoms have the same weight */
  void CalculateMassCenter(bool real=false);
  /** Get the mass center*/
  coordinate GetMassCenter();
  IBArray<double> GetInertiaTensor();
  /** Get the cell*/
 std::vector<coordinate>& Cell() { return m_cell; }
 const std::vector<coordinate>& Cell() const { return m_cell; } 
  /** Get the a->b vector */
  coordinate GetVector(int& a,int& b);
 /** Get the centroid*/
  coordinate Centroid() const;
  /** No descriptions */
  void ResetSelection();
  /** No descriptions */
  void GetHydrogenList(std::vector<int>& list);
  /** Calculate Molecular Weight */
  float CalculateWeight();
  /** Get the surrounding box as given by front-left-top 
   *  and back-right-bottom coordinates
   */
  void GetBox(coordinate& flt, coordinate& brb) const;
  /** No descriptions */
  void SetAtomPair(int i, int j);
  /** No descriptions */
  void ResetAtomPairs();
  /** returns a string with the enviroment of the atom
    * useful for b-effect in Haasnoot equations*/
  void GetEnviroment(int s1, int s2,std::vector< std::vector<std::string> >& subs_str);
  /** Get Hybridization type for atom i */
  std::string GetHybridization(int i);
  /** determine if Hydrogens with numbers i and j  */
  bool AreSp3Connected(int i, int j);
  /** A simple function to set the bond orders */
  void SetBondOrders();
  /** Get Angles to apply in Barfield Equation */
  void GetHCCAngles(int s1, int s2,float* angle);
  /** set dihedral ijkl to d degress*/
  void SetDihedral(int i, int j, int k, int l,float d);
  /** No descriptions */
  void ResetIrradiations();
  /** No descriptions */
  bool IsMethyl(int i);
  /** */
  bool IsLinear();
  /** return the number of vibrational modes 3N-5 or 3N-6*/
  int GetNVib();
  /** returns the number of substituents different from hydrogen */
  int GetNSubstituents(int i);
  /** Count the number of heavy atoms*/
 unsigned int CountHeavyAtoms() const;
  /** No descriptions */
  float GetAngle(int a1, int a2, int a3, bool degrees=false);
  float GetDihedral(int a1, int a2, int a3, int a4, bool degrees=false);
  void RotateBond(int i, int j, int sense);
  static const char* GetAtomName(int i);
  static int GetZ(const char* name);
  void SetConexions();
  void AllocateVectors(bool rottransmodes=false);
  std::vector<frequency>& GetFrequencies() { return m_modes; }
  std::vector<spectralline>& GetSpectralLines() { return m_spectrallines; }
  std::vector<AIM::Attractor>& GetAttractors() { return m_attractors;}
  std::vector<AIM::CriticalPoint>& GetBondPoints() { return m_bondpoints; }
  std::vector<AIM::CriticalPoint>& GetRingPoints() { return m_ringpoints; }
  std::vector<AIM::CriticalPoint>& GetCagePoints() { return m_cagepoints; }
  std::vector<size_t> Methyls() const;
  /** Create a bond between atoms i and j*/
  void CreateBond(int i, int j);
  void DeleteBond(int i, int j);
  const std::vector<CAtom>& Atoms() const { return m_atom; }
  std::vector<CAtom>& Atoms() { return m_atom; }
  std::vector<coordinate>& InputOrientation() { return m_inputorientation; }
  const std::vector<coordinate>& InputOrientation() const { return m_inputorientation; }
public: //public members
  std::vector<pair> m_pairs;
  float GetAnglePlanes(std::vector<int>& v, bool degrees=false);
  coordinate m_dipole;
  IMArray<double>& GetForces()  { return m_forces; }
  IBArray<double>& GetHessian()  { return m_hessian; }
  IBArray<double>& GetDipoleDerivatives() { return m_dipolederivatives; }
  std::vector < Coupling >& GetCouplings() { return m_couplings; }
    const std::vector < Coupling >& GetCouplings() const { return m_couplings; }
  void AllocateForces();
  void AllocateHessian();
  void CalculateFrequencies();
  void CalculateInertialAxis();
  std::vector < std::string >  GetNuclei();
  
  void SetEnergy(double e, const std::string& level="") { m_energy=e; m_energylevel=level;  }
  void SetS2(double e) { m_S2=e; }
  void SetKineticEnergy(double e) { m_kenergy=e;}
  void SetPotentialEnergy(double e) { m_venergy=e; }
  void SetRMSForce(double f) { m_rmsforce=f; }
  void SetMaximumForce(double f) { m_maximumforce=f; }
  void SetRMSDisplacement(double d) { m_rmsdisplacement=d; }
  void SetMaximumDisplacement(double d) { m_maximumdisplacement=d; }
  
  double PotentialEnergy() const { return m_venergy; }
  double KineticEnergy() const { return m_kenergy; }
  double GetEnergy() const { return m_energy; }
  double GetRMSForce() const { return m_rmsforce; }
  double GetMaximumForce() const { return m_maximumforce; }
  double GetRMSDisplacement() const { return m_rmsdisplacement; }
  double GetMaximumDisplacement() const { return m_maximumdisplacement; }
  double GetS2() const { return m_S2; }
  Threshold GetThreshold() const { return m_threshold; }
  void SetThreshold(const Threshold& thr) { m_threshold=thr; }
  std::string EnergyLevel() const { return m_energylevel; }
  const std::vector<double>* Charges( Charge type ) const;
  std::vector<double>* Charges(Charge type);
  
  
protected: // Protected methods

  /** molecular weight */
  float m_molecularweight;
  /** axis for bond rotation*/
  coordinate m_rotaxis[2];

  double m_energy;
  double m_kenergy;
  double m_venergy;
  double m_maximumforce;
  double m_rmsforce;
  double m_maximumdisplacement;
  double m_rmsdisplacement;
  double m_S2;

  float m_gradient;
  Threshold m_threshold;
  void RotateNeighbours(int i, int j, int sense,double pass);
private:
  std::vector<frequency>  m_modes;
  std::vector<spectralline> m_spectrallines;

  std::vector<int> m_rotatedatoms;
  IMArray<double> m_forces;
  IBArray<double> m_hessian;
  IBArray<double> m_dipolederivatives;
  std::vector<AIM::Attractor> m_attractors;
  std::vector<AIM::CriticalPoint> m_bondpoints;
  std::vector<AIM::CriticalPoint> m_ringpoints;
  std::vector<AIM::CriticalPoint> m_cagepoints;
  std::vector < Coupling > m_couplings;
  std::vector<coordinate> m_inputorientation;
  std::string m_energylevel;
  std::vector<double> m_espcharges;
  std::vector<coordinate> m_cell;


};

KRYOMOLECULE_EXPORT std::ostream& operator << (std::ostream& s,CMolecule& m);

#endif // !defined(AFX_MOLECULE_H__4A25AAA7_10C1_4F46_B82A_56A6C57A0AF3__INCLUDED_)
