// molecule.h -- subclass of Drawable which contains a molecule

#ifndef MOLECULE_H
#define MOLECULE_H

#include <qobject.h>
#include <qlist.h>
#include <qpainter.h>
#include <iostream>
using std::cout;
using std::endl;

#include "render2d.h"
#include "chemdata.h"
#include "drawable.h"
#include "dpoint.h"
#include "bond.h"
#include "text.h"
#include "symbol.h"
#include "molecule_sssr.h"

class Molecule : public Drawable {
  Q_OBJECT
    public:
  Molecule(Render2D *, QObject *parent = 0, const char *name = 0);
  void SetChemdata(ChemData *cd1) { cd = cd1; }
  void Render();  // draw this object
  Render2D* getRender2D() { return r;}
  void drawBonds(QPainter* painter,float scale);
  void drawText(QPainter* painter, float scale);
  int Type();  // return type of object
  bool Find(DPoint *);   // is this DPoint present in this Molecule?
  DPoint *FindNearestPoint(DPoint *, double &);
  Drawable *FindNearestObject(DPoint *, double &);
  void addBond(DPoint *, DPoint *, int, int, QColor, bool hl = false);
  void addBond(Bond *);
  void addText(Text *);
  void addSymbol(Symbol *);
  void CopyTextToDPoint();
  void CalcOffsets();
  void addMolecule(Drawable *);
  Bond *bondsFirst() { return bonds.first(); }
  Bond *bondsNext() { return bonds.next(); }
  Text *labelsFirst() { return labels.first(); }
  Text *labelsNext() { return labels.next(); }
  bool Erase(Drawable *);
  void EraseSelected();
  bool WithinRect(QRect, bool);
  bool WithinBounds(DPoint *);
  void SelectAll();
  void DeselectAll();
  void SetColorIfHighlighted(QColor);
  void Move(double, double);
  void Rotate(DPoint *, double);
  void Rotate(double);
  void Flip(DPoint *, int);
  void Resize(DPoint *, double);
  QRect BoundingBox();
  QRect BoundingBoxAll();
  QList<DPoint> AllPoints();
  QList<Drawable> AllObjects();
  QList<Bond> AllBonds();
  QList<Molecule> MakeSplit();
  int Members() { return bonds.count(); }
  QString ToXML(QString);
  QString ToCDXML(QString);
  QString ToMDLMolfile();
  void FromXML(QString);
  void Changed();
  // defined in molecule_tools.cpp
  QList<DPoint> BreakRingBonds(DPoint *);
  DPoint *GetRingAttachPoint();
  DPoint *GetAttachPoint(QString);
  double CalculateRingAttachAngle(DPoint *);
  void setGroupType(int);
  Text *CalcMW(bool from_change = false);
  Text *CalcEmpiricalFormula(bool from_mw = false);
  Text *CalcElementalAnalysis(bool show_dialog = true);
  QStringList Calc13CNMR(bool show_dialog = true);
  void CalcIR();
  void CalcName();
  QString IUPAC_Name();
  void MakeSSSR();
  void AddHydrogens(bool to_carbon = false);
  double SumBondEnthalpy();
  void Scale(double bond_length = -1.0);
  // defined in molecule_1h_nmr.cpp
  QStringList Calc1HNMR(bool show_dialog = true);
  void AddNMRprotons();
  void RemoveNMRprotons();
  void ProtonEnvironment();
  void Multiplicity_1HNMR();
  void Calc1HMultiplicityAndIntensity();
  double Calc1HShift(QString);
  // defined in molecule_smiles.cpp
  void CleanUp();
  void SDG(bool);
  void FromSMILES(QString);
  QString ToSMILES();
  // defined here:
  bool isInGroup() {
    if (group_type != GROUP_NONE) return true;
    return false;
  }
  int groupType() { return group_type; }
  void FormulaLabelDeleted() { cout << "FLD" << endl; text_formula = 0; }
  void MWLabelDeleted() { text_mw = 0; }
  double Angle(Bond *a1, Bond *b1) {
    // from Bond a1 to Bond b1
    // determine endpoints
    DPoint *a, *c, *b;
    if (a1->Start() == b1->Start()) {
      c = a1->Start();
      a = a1->End();
      b = b1->End();
    }
    if (a1->Start() == b1->End()) {
      c = a1->Start();
      a = a1->End();
      b = b1->Start();
    }
    if (a1->End() == b1->Start()) {
      c = a1->End();
      b = a1->Start();
      a = b1->End();
    }
    if (a1->End() == b1->End()) {
      c = a1->End();
      b = a1->Start();
      a = b1->Start();
    }
    double ang1 = getAngle(c, a);
    double ang2 = getAngle(c, b);
    double ang3 = ang1 - ang2;
    if (ang3 < 0.0) ang3 += 360.0;
    return ang3;
  }
 private:
  // Renderer
  Render2D *r;
  // ChemData
  ChemData *cd;
  // current/temporary Bond
  Bond *tmp_bond;
  // current/temporary Text
  Text *tmp_text;
  // current/temporary Symbol
  Symbol *tmp_sym;
  // current/temporary DPoint
  DPoint *tmp_pt;
  // list of elements which make up this molecule
  QList<Bond> bonds;
  QList<Text> labels;
  QList<Symbol> symbols;
  // Text objects which hold MW and formula
  Text *text_mw, *text_formula;
  // list of unique points used by Move(), Resize(), Rotate(), and
  // function to fill it
  void MakeTomoveList();
  QList<DPoint> tomove;
  // used for elemental analysis (set by CalcEmpiricalFormula)
  double nc, nh, no, nn, nmw;
  // Molecule's SSSR
  SSSR this_sssr;
  // point list for SDG, etc.
  QList<DPoint> up;
  // group data
  int group_type;
  int group_id;
  // proton magnetic environment list(s)
  QStringList protonMagEnvList;
  QStringList protonFinalList;
};

#endif
