/* Copyright (c) 2015  Gerald Knizia
 * 
 * This file is part of the IboView program (see: http://www.iboview.org)
 * 
 * IboView is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3.
 * 
 * IboView is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with bfint (LICENSE). If not, see http://www.gnu.org/licenses/
 * 
 * Please see IboView documentation in README.txt for:
 * -- A list of included external software and their licenses. The included
 *    external software's copyright is not touched by this agreement.
 * -- Notes on re-distribution and contributions to/further development of
 *    the IboView software
 */

#ifndef ORBVIEW_DOCUMENT_H
#define ORBVIEW_DOCUMENT_H

#include "Iv.h"

#include <map>
#include <set>
#include <vector>

#include <QString>
#include <QAbstractTableModel>
#include <QAction>
#include <QExplicitlySharedDataPointer>
#include <QSharedData>


#include "CtAtomSet.h"
#include "CtBasisSet.h"
#include "CxPodArray.h"
// #include "CxColor.h"
#include "IvMesh.h"
#include "IvGl.h"
#include "IvIsoSurface.h"
#include "CtMatrix.h"
#include "IvLog.h"
#include "IvTables.h"


using ct::FAtomSetPtr;
using ct::FBasisSetPtr;
using ct::TArray;
using ct::FIntrusivePtrDest;
namespace ct {
   struct FHfOptions;
   struct FWfDecl;
}


// // abstract base class for storing intermediate data for rendering,
// // which is associated with data sets
// struct FRenderCache : public ct::FIntrusivePtrDest
// {
//    virtual ~FRenderCache();
// private:
//    FRenderCache(FRenderCache const &); // not implemented
//    void operator = (FRenderCache const &); // not implemented
// };
//
// typedef boost::intrusive_ptr<FRenderCache>
//    FRenderCachePtr;

class FView3d;
class FDocument;

class FWfOptions : public QObject
{
   Q_OBJECT

public:
#include "prop_FWfOptions.h.inl"

public:
   FWfOptions(QObject *parent = 0);

   // assign basis sets from HfOptions to pAtoms
   void AssignBasisSets(ct::FAtomSet *pAtoms);

   void AssignScfOptions(ct::FHfOptions &HfOptions);
   void AssignWfDecl(ct::FWfDecl &WfDecl, ct::FAtomSet *pAtoms);
};

struct FDataSet : public FIntrusivePtrDest
{
   explicit FDataSet(QString const &Desc_, FAtomSetPtr pAtoms_ = 0, FDocument *pDocument_ = 0);

   bool
      Active;
   FAtomSetPtr
      pAtoms;
   enum FDescFlags {
      DESC_Full = 0x01,
      DESC_Compact = 0x02
   };

//    FRenderCachePtr
//       pRenderCache; // may be 0. may be set to 0 at any point in time.
   virtual QString GetType() const = 0;
   virtual QString GetDesc(uint Flags=0) const; // default: return m_Desc

   // rebuild the visual representation of the object on next rendering.
   virtual void InvalidateRenderCache();
   virtual void BuildRenderCache(FView3d *pView3d);

   virtual uint32_t GetBaseColor() const;

   virtual bool DependsOnWaveFunction() const;

   // return pointer to its parent object.
   FDocument *GetDocument() { return m_pDocument; };
protected:
   QString m_Desc;
   FDocument *m_pDocument;
};
typedef boost::intrusive_ptr<FDataSet>
   FDataSetPtr;

enum FBondFlags {
   BOND_Partial = 0x01,
   BOND_Grey = 0x02 // make the bond grey instead of the usual half-bond with their attached atom colors.
};

struct FBondLine {
   int
      iAt, jAt;
   uint
      Flags;
   FBondLine() {};
   FBondLine(int iAt_, int jAt_, uint Flags_) : iAt(iAt_), jAt(jAt_), Flags(Flags_) {}
};

enum FAtomFlag {
   // do not show the atom in renderings
   ATOM_Hidden = 0x01,
   // if aligning the molecule in space, ignore this atom when determining
   // the aligning transformation.
   ATOM_NoAlign = 0x02,
   // atom is part of an currently active selection
   ATOM_Selected = 0x04
};

struct FGeometry : public FDataSet
{
   explicit FGeometry(QString const &Desc_, FAtomSetPtr pAtoms_, FDocument *pDocument_);
   QString GetType() const; // override
   // add a dotted bond to indicate the formation/breaking of a bond between the indexed atoms.
   void AddBond(FBondLine const &bl);
   void AddBond(int iAt, int jAt, QString const &Flags);
   void DeleteBond(int iAt, int jAt, bool ComplainIfNotThere=true);
   void FindBondLines(FDocument *pDocument);
public:
   std::vector<FBondLine>
      m_BondLines;
protected:
   void FixMinBasis();
};


struct FOrbital;

// describes the configuration of the visual representation of an orbital iso surface.
// These objects are *shared* between associated orbitals in different frames.
struct FOrbitalVisualConfig : public FIntrusivePtrDest
{
   bool
      bColorSet;
   FIsoType
      iIsoType;
   float
      fIsoValue;
   uint32_t
      cIsoPlus, cIsoMinus;
   void AssignDefaultColor(FDocument *pDocument);

   FOrbitalVisualConfig();
public:
   typedef std::set<FOrbital*>
      FOrbitalChain;
   FOrbitalChain
      // list of all orbitals which are linked with this configuration object
      // (note: these are weak refs; the orbitals own the config object (via
      // ref), not the other way around!)
      LinkedOrbitals;
   void Link(FOrbital *pOrbital);
   void Unlink(FOrbital *pOrbital);

   enum FUpdateFlags {
      UPDATE_InvalidateIsoSettings = 0x01,
      UPDATE_InvalidateColors = 0x02,
      UPDATE_Rebuild = 0x04 // <- for this pView3d must be supplied!
   };

   // Apply given update/change to all data sets which share this object.
   // argument: bit field of UPDATE_* flags.
   void UpdateLinkedRepresentations(uint32_t Flags, FView3d *pView3d=0);
private:
   void operator = (FOrbitalVisualConfig const &); // not implemented
   FOrbitalVisualConfig(FOrbitalVisualConfig const &); // not implemented
   // ^- note: it is not the actual config part of which copying is the problem...
   //    the linked reference chain is. It might be useful to split this class into
   //    two parts: one "shared dataset properties" class which represents the links,
   //    and one for the actual visual configuration. This may become useful once other
   //    kinds of data sets besides orbitals and geometries are introduced.
};
typedef boost::intrusive_ptr<FOrbitalVisualConfig>
   FOrbitalVisualConfigPtr;

typedef std::vector<int>
   FAtomIdList;

// encodes the result of a partial charge analysis
struct FChargeAnalysis
{
   struct FKey {
      int iAt; // atom number (in frame, not element)
      int AngMom; // angular momentum of the AO carrying the current entry.

      FKey() {}
      explicit FKey(int iAt_, int AngMom_) : iAt(iAt_), AngMom(AngMom_) {}
      bool operator < (FKey const &other) const {
         if (iAt < other.iAt) return true;
         if (other.iAt < iAt) return false;
         return AngMom < other.AngMom;
      }
   };
   struct FValue {
      double fCharge;
      double fSpin;
      FValue() {}
      explicit FValue(double fCharge_, double fSpin_) : fCharge(fCharge_), fSpin(fSpin_) {}
   };
   typedef std::map<FKey, FValue>
      FMap;
   FMap
      m_Data;
   bool
      m_RestrictAtoms; // if given: exclude atoms not in m_SelectedAtoms.
   FAtomIdList
      m_SelectedAtoms;
   ct::FAtomSet
      &m_Atoms;

   void Add(int iAt, int AngMom, double fCharge, double fSpin);
   void MakeReport(ct::FLog &Log); // document only used for making labels..
   bool IsIncluded(int iAt) const;

   std::string AtomLabel(int iAt) const;

   int CountAtoms() const;
   int FindMaxL() const;
   bool bNonzeroSpin() const;
   double MakeAtomTotalCharge(int iAt, double fCharge) const;

   explicit FChargeAnalysis(ct::FAtomSet *pAtoms, FAtomIdList *pSelectedAtoms=0);
   ~FChargeAnalysis();
};


// Maybe I should even use bitfields for Alpha and Beta? Then closed would be ALPHA | BETA.
enum FOrbitalSpin {
   ORBSPIN_SpinFree,
   ORBSPIN_Alpha,
   ORBSPIN_Beta,
   ORBSPIN_Unknown
};
char const *pOrbDescFromType(FOrbitalSpin Type, double fOcc);

struct FOrbitalInfo {
   double
      fEnergy,
      fOcc;
   int
      iSym;
   FOrbitalSpin
      Spin;
   int
      iOriginalIndex;
   explicit FOrbitalInfo(double fEnergy_=0, double fOcc_=0., int iSym_=0, FOrbitalSpin OrbSpin_=ORBSPIN_Unknown);
   QString MakeDesc(QString RefName) const;
   QString MakeDesc(size_t iOrb) const;

   double fChargeFactor() const;
   double fSpinFactor() const;
};

enum FWfType {
   WFTYPE_Rhf, // only orbitals with occupancy closed or alpha
   WFTYPE_Uhf, // only orbitals with occupancy alpha or beta
   WFTYPE_Mcscf, // spin-free orbitals, but with occupation numbers other than 1.0 or 2.0 (can still make IAO charges, but not bond orders or IBOs for the active space)
   WFTYPE_Other
};

struct FOrbital : public FDataSet
{
   typedef FDataSet
      FBase;

   explicit FOrbital(QString const &Desc_, FAtomSetPtr pAtoms_, FDocument *pDocument_, FBasisSetPtr pBasisSet_, double *pCoeffs_, FOrbitalInfo const &info_, FOrbitalVisualConfigPtr pRefVisConfig, double *pDm=0, double *pQm=0);
   ~FOrbital();

   FOrbitalVisualConfigPtr
      pVisConfig;
   void LinkVisualConfig(FOrbitalVisualConfigPtr p);

   bool HaveMoments;
   double vDipMom[3]; // dipole moment and quadrupole moment.
   double mQuadMom[3][3];


   FOrbitalInfo
      info;
   FBasisSetPtr
      pBasisSet;
   TArray<double>
      pCoeffs;
      // ^- if this is a orbital-like-quantity, then these are its expansion
      //    coefficients. over pBasisSet.

   // minimal basis and IAO coefficients of the orbitals; used for tracking
   // orbital changes.
   FBasisSetPtr
      pMinBasis;
   TArray<double>
      pIaoCoeffs;
   TArray<double> MakeIaoCharges(bool UseOccupationNumbers=true) const; // make IAO charges from IAO coeffs.
   void AddChargeContributions(FChargeAnalysis &Charges) const;

   QString GetType() const; // override

   enum FFullDescOptions {
      ORBDESC_ChargesOnly = 0x01,
      ORBDESC_CompactSpace = 0x02
   };
   QString MakeFullDesc(double ThrPrint = 0.02, uint Flags = 0, int nMaxAtoms = -1) const;

   QString GetDesc(uint Flags=0) const; // override
   void UpdateDescFromInfo(size_t iOrb);

   // multiply coefficients by -1.
   void FlipPhase();

   // just update the colors of the mesh (i.e., rebuild the GL mesh), but leave
   // the mesh itself alone.
   void InvalidateColors();

   virtual uint32_t GetBaseColor() const;
   virtual bool DependsOnWaveFunction() const; // override
public:
   FGlMeshPtr
      pGlMesh; // should probably not be here (and wasn't before), but need it for
               // changing color data/iso surface settings.

   void InvalidateRenderCache(); // override
   void BuildRenderCache(FView3d *pView3d); // override
};
typedef boost::intrusive_ptr<FOrbital>
   FOrbitalPtr;

typedef std::vector<FDataSetPtr>
   FDataSetList;
struct FFrame : public QObject, FIntrusivePtrDest
{
   explicit FFrame(QString Desc_, FDocument *pDocument_);

   enum FOrbitalMatrixFlags {
      ORBMAT_OccupiedOnly = 0x01,
      ORBMAT_VirtualOnly = 0x02,
      ORBMAT_AlphaAndClosedOnly = 0x04,
      ORBMAT_BetaAndClosedOnly = 0x08,
      ORBMAT_AlphaOnly = 0x10,
      ORBMAT_ClosedOnly = 0x20,
      ORBMAT_BetaOnly = 0x40
   };

   FGeometry *pGetGeometry();
   FGeometry const *pGetGeometry() const{ return const_cast<FFrame*>(this)->pGetGeometry(); };
   ct::FAtomSet *pGetAtoms();
   ct::FAtomSet const *pGetAtoms() const { return const_cast<FFrame*>(this)->pGetAtoms(); };
   FOrbital *pGetOrbital(int iMo); // note: this is an "orbital number" (i.e., starts a 1, goes to nMo).
   double GetEnergy() const;
   double GetGradient() const;

   QString GetBaseInputFileName() const;
   QString GetFullInputFileName() const;

   // collect all coefficients (and the current basis) of orbitals in *this.
   // notes:
   //   - COrb (output) is allocated on Mem.
   //   - If pRefOrbitals != 0, then a pointer to COrb(:,iOrb) will be stored in (*pRefOrbitals)[iOrb].
   void MakeOrbitalMatrix(ct::FMatrixView &COrb, FBasisSetPtr &pBasis2, TArray<FOrbital*> *pRefOrbitals, uint32_t Flags, ct::FMemoryStack &Mem);
//    void MakeIaoCoeffs(FWfOptions *pWfOptions, ct::FMemoryStack &Mem);
   void RunIaoAnalysis(ct::FLog &Log, FWfOptions *pWfOptions, bool AllowLocalize, ct::FMemoryStack &Mem);
   void MakeOrbitalMoments(ct::FMemoryStack &Mem);
   void LinkOrbitalsToPreviousFrame(FFrame *pPrevFrame, ct::FMemoryStack &Mem);
//    bool CanDoIaoAnalysis();

   ct::FMatrixView MakeIaoBasis(ct::FAtomSet *pAtoms, ct::FMemoryStack &Mem);

   void RunChargeAnalysis(ct::FLog &Log, FAtomIdList *pSelectedAtoms = 0);

   // returns whether or not any orbital data sets are present.
   bool HaveOrbitals() const;
   // delete all electronic structure stuff we might be keeping.
   void ClearOrbitals();

   FWfType GetWfType();

   // find the data set row in which a given object is currently stored.
   int FindRow(FDataSet* pSet);
   int rowCount() const { return (int)m_Data.size(); }

   FDataSetList
      m_Data;

   FMemoryLogQt &Log() { return *m_pFrameLog; }
protected:
   FMemoryLogQt
      *m_pFrameLog;
   QString
      m_InputFileName;
   FBasisSetPtr
      m_pOrbBasis,
      m_pMinBasis;
   TArray<double>
      m_CIaoData; // coefficients of IAOs in terms of main basis
   ct::FMatrixView
      m_CIb;
   FDocument
      *m_pDocument; // parent of the frame. used to take settings from.
};


// script interface
class IFrame : public FFrame
{
   Q_OBJECT

   Q_PROPERTY(QString name READ get_name WRITE set_name);
public slots:
   // add/remove bond lines. Atom indices are 1-based here.
   virtual void add_bond(int iAt, int jAt, QString const &Flags); // = 0;
   virtual void delete_bond(int iAt, int jAt); // = 0;
   virtual void reset_bonds(); // = 0; // reset all bonds to normal.
   virtual QString get_name();
   virtual void set_name(QString const &Name);

   virtual void scale_mo(int iMo, double fFactor); // = 0;
   virtual void rot_mos_2x2(int iMo, int jMo, double fAngle); // = 0;
public:
   explicit IFrame(QString Desc_, FDocument *pDocument_);
};

typedef boost::intrusive_ptr<IFrame>
   FFramePtr;


enum FSelectionMode {
   SELECT_Select, // delete previous selection and make a new selection with given objects
   SELECT_Toggle, // toggle selection state of given objects
   SELECT_Add // add to previous selection
};


struct FBondChangeAction : public QAction
{
   Q_OBJECT
public:
   enum FBondChangeActionType {
      ACTION_Hide,
      ACTION_SetStyleDotted,
      ACTION_Reset
   };

   FBondChangeAction(int iAt_, int jAt_, FBondChangeActionType Type_, QString Text_, QObject *Parent_)
      : QAction(Text_, Parent_), m_Type(Type_), m_iAt(iAt_), m_jAt(jAt_)
   {}

   FBondChangeActionType
      m_Type;
   int
      m_iAt, m_jAt;
};

typedef std::vector<int>
   FFrameIndexList;


int const ColorNotSet = 0x04030201; // if you are thinking of using this: Use black instead 8).

// this class doubles as element properties and per-atom settings container.
// It is used for exposing these settings to user modification and to scripts.
// It is a bit more complicated than the other property classes, as all the properties
// just default to "not set"...
class FElementOptions : public QObject, public QSharedData {
   Q_OBJECT
public:
#include "prop_FElementOptions.h.inl"

   explicit FElementOptions(int iElement_, QObject *parent=0);
   explicit FElementOptions(FElementOptions const *other, QObject *parent=0);

   int iElement() const { return m_iElement; }
   // return the bond color if explicitly set, and otherwise the atom color.
   uint32_t GetBondColor1() const;
protected:
   // these ones get stuff from tables.
   uint32_t GetDefaultColor() const;
   uint32_t GetDefaultBondColor() const;
   double GetDefaultCovalentRadius() const;
   double GetDefaultDrawRadius() const;
   char const *ElementName() const;

   int
      m_iElement;
   void InitForElement(int iElement_);
};
typedef QExplicitlySharedDataPointer<FElementOptions>
   FElementOptionsPtr;
typedef QList<FElementOptionsPtr>
   FElementOptionsList;

struct FAtomOptions {
   uint
      // bitfield of FAtomFlag type. (ATOM_*)
      Flags;
   int64_t
      // sequence number in order to keep track of order in which things were selected
      // (important for bond angle and dihedral measures)
      iSelectionSequenceId;
   FElementOptionsPtr
      // used to provide values to the atom which differ from the default element properties.
      pPropertiesOverride;

   FAtomOptions() : Flags(0), iSelectionSequenceId(-1) {}
};

// used for alignment and IRC/other arc-length purposes.
struct FFrameCoords : public FIntrusivePtrDest
{
   ct::FAtomSet// const
      *pAtoms;
   std::vector<double>
      pAtMass;
   std::vector<ct::FVector3>
      pAtPos;
   FDocument
      *pDocument;
   explicit FFrameCoords(FGeometry *pGeometry);
   virtual ~FFrameCoords();

   bool empty() const { return pAtMass.empty(); }
};
typedef boost::intrusive_ptr<FFrameCoords>
   FFrameCoordsPtr;

// idea: rows == associated data sets per frame,
//       cols == frames.
// (note that they may come in non-natural orders for later frames and that
//  some cells might be missing)
class FDocument : public QAbstractTableModel
{
   Q_OBJECT

public:
   Q_PROPERTY(QString atom_weight_mode READ GetAtomWeightMode WRITE SetAtomWeightMode NOTIFY AtomWeightModeChanged)
   Q_SLOT void SetAtomWeightMode(QString o) { m_AtomWeightMode = o; }
   Q_SIGNAL void AtomWeightModeChanged(QString o);
   QString GetAtomWeightMode() const { return m_AtomWeightMode; };

   Q_PROPERTY(bool skip_virtual_orbitals READ GetSkipVirtualOrbitals WRITE SetSkipVirtualOrbitals NOTIFY SkipVirtualOrbitalsChanged)
   Q_SLOT void SetSkipVirtualOrbitals(bool o) { m_SkipVirtualOrbitals = o; }
   Q_SIGNAL void SkipVirtualOrbitalsChanged(bool o);
   bool GetSkipVirtualOrbitals() const { return m_SkipVirtualOrbitals; };

   // hmpf... doc is not actually exposed to script currently. Script's 'doc' variable actually links to IApplication.
   // needs bigger re-design to work..
   Q_PROPERTY(FElementOptionsList elements READ GetElementOptions) // note: this COPIES the list!
   FElementOptionsList const &GetElementOptions() const { return m_ElementOptions; };
   FElementOptionsList &GetElementOptions() { return m_ElementOptions; };
public:
   FDocument(QObject *parent);
   int rowCount(const QModelIndex &parent = QModelIndex()) const;
   int columnCount(const QModelIndex &parent = QModelIndex()) const;
   QVariant headerData(int section, Qt::Orientation orientation, int role) const;
   QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;

   uint &AtomFlags(int iAt);
   FAtomOptions &AtomOptions(int iAt);
   bool IsAtomHidden(int iAt);
   bool IsAtomSelected(int iAt);
   bool IsAtomExcludedFromAlignment(int iAt);
   FElementOptions *pElementOptions(int iAt, ct::FAtomSet *pAtoms = 0);
   // ^- pAtoms: if given, take data for atoms from this atom set. Otherwise: from current frame.

   void UnselectAll(bool EmitUpdate=true);
   void SelectAtom(int iAt, FSelectionMode SelectMode);
   void UpdateSelectedAtomsStatusText();
   // count the number of atoms which presently are selected.
   int nSelectedAtoms();
   int nAtomsWithFlags(); // count largest number of defined centers.

   QString AtomLabel(int iAt) const;

public:
   typedef std::vector<FFramePtr>
      FFrameList;
   FDataSetPtr GetActiveDataSet();
//    ct::FAtomSet
//       Atoms;
   void Load(QStringList FileNames);

   // this will change the document by either re-ordering frames or deleting a
   // subset of the previous frames. iNewIndices gives the indices of the new
   // frames in the new order they are supposd to appear in. Any frame not
   // contained herein will be removed.
   void ReorderOrRestrictFrameSet(FFrameIndexList const &iNewIndices);

   IFrame *GetCurrentFrame();
   IFrame *GetCurrentFrame() const;
   FDataSetList *GetCurrentFrameData();
   FDataSetList *GetFrameData(int iFrame);

   IFrame *GetFrame(int Idx, bool AssertExists=true);
   FDataSet *GetRow(int Idx, bool AssertExists=true);
   FDataSet *GetRowCol(int iRow, int iCol, bool AssertExists=true);
   IFrame const *GetFrame(int Idx, bool AssertExists=true) const;
   FDataSet const *GetRow(int Idx, bool AssertExists=true) const;
   FDataSet const *GetRowCol(int iRow, int iCol, bool AssertExists=true) const;
   int GetActiveColIndex() const { return m_ActiveCol; };
   int GetActiveRowIndex() const { return m_ActiveRow; };
   int GetNumFrames() const { return int(m_Frames.size()); }

   void GetNextOrbitalColors(uint32_t &cIsoPlus, uint32_t &cIsoMinus);

   QString GetCurrentInputFileName();
   QString GetCurrentInputBaseFileName();
   QString GetCommonInputFileName();
// public slots:
//    void onToggleDataset(const QModelIndex &index);
//    void onSelectDataset(const QModelIndex &index);

   void AlignFrames(QString Mode);
   void SetInputFileName(QString FileName_) { m_InputFileName = FileName_; }
   QString GetAtomLabel(int iAt);

   FWfOptions *GetWfOptions() { return m_pWfOptions; }; // should this be here?
   void ClearOrbitals(bool EmitSignals=true);

   FDocumentMeasures *GetMeasures() { return m_pMeasures; };

   size_t iFrameId(FFrame *pFrame) const;
   bool HaveEnergies() const;
   bool HaveGradients() const;
   bool HaveOrbitals() const;
public slots:
   void ToggleDataRow(int iIndex);
   void SetActiveCol(int iIndex);
   // ForceUpdate: force emit signal even if new row is equal to old row
   // (e.g., if properties of the row have changed, like its activity status)
   void SetActiveRow(int iIndex, bool ForceUpdate = false, bool UpdateStatus=true);

   void HideSelectedAtoms();
   void ClearAtomFlags(bool EmitUpdate=true);
   void FindOrbitalsOnSelectedAtoms();
   void CalcChargesOnSelectedAtoms();
   void MakeHybridsForSelectedAtomGroup();
   void ToggleActiveDataRow();
   void MakeBondLinesForSelectedAtoms();
   void ResetBondLines();

   // link most-similar orbitals between all frames
   void LinkOrbitals();

   // data comes in over the QAction (sender), which should be a FBondChangeAction
   void ChangeSelectedBond();

   // these control the way new orbital colors are assigned.
   void SetNextOrbitalColorIndex(int Value);
   void SetNextOrbitalColorScheme(int Index);

   void RebuildWf(FLogQt &Log);
   void Clear(); // delete everything.

   // make a list of the smart pointers (in order to keep references to them)
   // to defer their point of deletion to a later point. Required due to GL-weiredness.
   // See rebuid wf code in IvMain.cpp.
   void AcquireFrameObjectLock(FDataSetList &ObjectLock);

signals:
   void ActiveDatasetChanged();
   void ActiveColChanged(int iIndex);
   void ActiveRowChanged(int iIndex);
   void SelectionChanged();

   // i.e., "please update the 3d view"
   void VisualRepresentationChanged();
   void NextOrbitalColorIndexChanged(int Value);
protected:
   FElementOptionsList
      m_ElementOptions;

   FFrameList
      m_Frames;
   int
      m_ActiveRow,
      m_ActiveCol;
   QString
      m_InputFileName; // only set if this is a script?
   int64_t
      m_SelectionSequenceId;

   typedef std::map<int, FAtomOptions>
      FAtomOptionMap;
   FAtomOptionMap
      m_AtomOptions;
   QString
      // default mode for aligning frame geometries to each other
      // and/or weighting atoms for arc lengths.
      m_AtomWeightMode;
   bool
      // if set, do not load or compute virtual orbitals
      m_SkipVirtualOrbitals;

   FDocumentMeasures
      *m_pMeasures;

   // these two control the way new orbital colors are chosen.
   // (used when orbitals are first rendered iff they have no color sets
   // assigned otherwise)
   ptrdiff_t
      m_iNextOrbitalColor;
   size_t
      m_iNextOrbitalColorScheme;

//    void FindAligningTrafo(double pR[9], double pD[3], ct::FAtomSet *pAtoms, std::string const &Mode, ct::FMemoryStack &Mem);
   FFrameCoordsPtr MakeFrameCoords(int iFrame);
   void FindAligningTrafo(double pR[9], double pD[3], FFrameCoords *pThis, FFrameCoords *pLast, ct::FMemoryStack &Mem);

   // delete all cached geometric data of orbitals
   void ClearOrbitalRepresentations();

   void LoadFile(FFrameList &LoadedFrames, QString FileName);
   // returns true if the given file was identified as an orbital file (independent of whether loading it worked or not).
   bool LoadOrbitalFile(FFrameList &LoadedFrames, QString FileName);
   void LoadXyzFile(FFrameList &LoadedFrames, QString FileName);

   void MakeOrbitalMoments();
   void MakeOrbitalCharges();
   void MakeOrbitalCachedData();

   // not: may be called only during document load.
   void BeginInsertFrames();
   void InsertFrame(FFramePtr pFrame);
   void EndInsertFrames();

   void BeginTotalReset();
   void EndTotalReset();

   int
      m_CallEndInsertRows; // -1: BeginInsertFrames not called.
   FFrameList
      m_FramesToInsert; // used only during InsertFrame operatations.
   FWfOptions
      *m_pWfOptions;

   typedef std::vector<int>
      FAtomIdList;
   FAtomIdList GetSelectedAtoms(bool SortedBySelectionSequence = true);
};


// ^- note: automoc requires Q_OBJECT derived classes to be defined in
//    HEADER FILES. Otherwise it won't find them. Will result in "undefined
//    reference to 'vtable for ...'" errors.




#endif // ORBVIEW_DOCUMENT_H
