/*
 * File:   Angle.h
 * Author: flong
 *
 * Created on August 9, 2011, 11:32 AM
 */

#ifndef ANGLE_H
#define	ANGLE_H

#ifndef KERNEL_H
#include "kernel.h"
#endif

#ifndef ATOM_H
#include "atom.h"
#endif

#ifndef ATOMASSEMBLY_H
#include "atomAssembly.h"
#endif

#ifndef BOND_H
#include "bond.h"
#endif

#ifndef UTILITY_H
#include "utility.h"
#endif

namespace LIBMOL // temp
{
    class Atom;
    class AtomDict;
    class Bond;

    /* Angle class describes the angle formed among three atoms *
     *
     *
     */

    class Angle
    {
    public:

        // default constructor
        Angle();
        // copy constructor
        Angle(const Angle& tA);
        // constructor using 3 atoms
        Angle(Atom& tAtm1, Atom& tAtm2, Atom tAtm3);

        // destructor
        ~Angle();

        Angle & operator = (const Angle & tA);

        Name getName() const;
        void setName(Name tNa);
        ID   getID() const;
        void setID(ID tID);
        SeriNumber getSeriNum() const;
        void setSeriNum(SeriNumber tSer);

        Angle & create(Atom& tAtm1, Atom& tAtm2, Atom& tAtm3);
        void    swapOneAtom(Atom & tAtm);
        void    destroy();   // set everything to null


        REAL getValue(bool tL) const;
        void setValue();
        void setValue(REAL tV, bool tL);
        void setValue(Atom& tA1, Atom& tA2, Atom tA3);

        REAL getSigValue(bool tL) const;
        void setSigValue(REAL tV, bool tL);

        inline REAL getForceConst() const
        {
            return itsFrceConst;
        }
        inline void setForceConst(REAL tF)
        {
            itsFrceConst = tF;
        }

        REAL getValuePre() const;
        void setValuePre(REAL tVP);


        // set those member variables public for efficiency

        bool            isItTouched;


        std::vector<Atom>    atoms;

    private:




        Name           itsName;
        ID             itsID;
        SeriNumber     itsSeriNum;

        REAL            itsValue;
        REAL            itsValueSt;
        REAL            itsSigValue;
        REAL            itsSigValueSt;

        REAL            itsFrceConst;

    };

    class AngleDict
    {
    public:
        // Default constructor
        AngleDict();
        // Copy constructor
        AngleDict(const AngleDict & tAngle);
        // Constructor using atoms
        AngleDict(ID tAnchID, int tAnchPos, std::vector<AtomDict> & tAtoms);
        // Constructor using atom idxs
        AngleDict(ID tAnchID, int tAnchPos, std::vector<int> & tAtmIdxs);
        // Default destructor
        ~AngleDict();

        void setValue(std::vector<AtomDict> & tAtoms);


        int                     seriNum;
        REAL                    value;
        REAL                    sigValue;
        REAL                    valueST;
        REAL                    sigValueST;
        bool                    hasCodValue;
        int                     numCodValues;
        REAL                    valueP;
        REAL                    sigValueP;
        int                     numCodValuesP;

        ID                      anchorID;
        int                     anchorPos;

        bool                    isFixed;
        int                     approxLevel;
        int                     isInSameRing;

        std::vector<int>        atoms;
        std::vector<ID>         atomsId;
        std::vector<ID>         atomChemTypes;
        std::vector<ID>         atomsCodClasses;
        std::vector<ID>         atomsNB2Rep;
        std::vector<ID>         atomsNBRep;
        std::map<ID, ID>        atomsSPStats;
        std::map<ID, ID>        atomsNB1NB2SPStats;
        std::vector<REAL>       codAngleValues;
    };

    extern int getAngle(std::vector<AngleDict> & tAllAngles,
                        int cAt, int tAt1, int tAt2);

    extern REAL getAngleValueFromFracCoords(AtomDict  & tAtCen,
                                            AtomDict  & tAt1,
                                            AtomDict  & tAt2,
                                            REAL a, REAL b, REAL c,
                                            REAL alpha, REAL beta, REAL gamma);

}

#endif	/* ANGLE_H */
