/*****************************************************************************
 * $CAMITK_LICENCE_BEGIN$
 *
 * CamiTK - Computer Assisted Medical Intervention ToolKit
 * (c) 2001-2025 Univ. Grenoble Alpes, CNRS, Grenoble INP - UGA, TIMC, 38000 Grenoble, France
 *
 * Visit http://camitk.imag.fr for more information
 *
 * This file is part of CamiTK.
 *
 * CamiTK is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * CamiTK 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 Lesser General Public License version 3 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with CamiTK.  If not, see <http://www.gnu.org/licenses/>.
 *
 * $CAMITK_LICENCE_END$
 ****************************************************************************/

#ifndef ATOM_H
#define ATOM_H

#include <string>

#include "Structure.h"
#include "AtomProperties.h"
#include "RenderingMode.h"

//pmlschema forward declarations
namespace physicalModel {
class Atom;
}

/**
  * @ingroup group_cepmodeling_libraries_pml
  *
  * @brief
  * An atom has an unique index in the physical model object, a 3D position, and different basic properties.
  * It is the most basic structure composing a physical model.
  * It is on an atoms that the forces and loads could be applied in order to generate dynamics.
  *
 **/
class Atom : public Structure {
public:
    /** Default constructor : set the position to the origin, generate a unique index
     *  @param myPM the physical model the atom belongs to
     */
    Atom(PhysicalModel* myPM);

    /** constructor from xml node: try to read and get the parameters from xml and set the index in atom SC (if possible)
     *  @param myPM the physical model the atom belongs to
     *  @param atom the xsd class representing the atom to read information from.
     *  @param id the index in the atoms structural component (useful to directly access the memory block corresponding to the position)
     * 	@see getIndexInAtoms()
    */
    Atom(PhysicalModel* myPM,  physicalModel::Atom atom, unsigned int id = -1);

    /** constructor : generate a unique index
     *  @param myPM the physical model the atom belongs to
     *  @param pos the initial position of the created atom (array of 3 double)
     */
    Atom(PhysicalModel* myPM, const double pos[3]);

    /** set the position to the origin
     *  @param myPM the physical model the atom belongs to
     *  @param ind give the unique index
     */
    Atom(PhysicalModel* myPM, const unsigned int ind);

    /** constructor : generate a unique index
     *  @param myPM the physical model the atom belongs to
     *  @param ind give the unique index
     *  @param pos the initial position of the created atom (array of 3 double)
     */
    Atom(PhysicalModel* myPM, const unsigned int ind, const double pos[3]);

    /// std destructor
    ~Atom() override;

    /** print to an output stream in "pseudo" XML format.
       */
    void xmlPrint(std::ostream&, const StructuralComponent*) override;

    /// get the position of the atom (array of 3 doubles)
    void getPosition(double pos[3]) const;

    /// set the position of the atom
    void setPosition(const double [3]);

    /// set the position of the atom
    void setPosition(const double, const double, const double);

    /** set the index.
     *  The index <b>have to be unique</b> otherwise this method
     *  has no effect.
     *  The sub-classes method will check that this index is not in use.
     *  @return true only if the index of the structure was changed
     */
    bool setIndex(const unsigned int) override;

    /// get the index of this atom in the global atom structural component, i.e. its order number in atoms
    unsigned int getIndexInAtoms() const;

    /// return true only if the parameter is equal to "Atom"
    bool isInstanceOf(const char*) const override;

    /// Get a ptr to the AtomProperties
    AtomProperties* getProperties() const;

private:
    unsigned int indexInAtoms;
};

// -------------------- inline ---------------------
inline void Atom::getPosition(double p[3]) const {
    return getProperties()->getPosition(p);
}

inline void Atom::setPosition(const double pos[3])  {
    getProperties()->setPosition(pos);
}
inline void Atom::setPosition(const double x, const double y, const double z)  {
    getProperties()->setPosition(x, y, z);
}

inline bool Atom::isInstanceOf(const char* className) const {
    return (std::string(className) == std::string("Atom"));
}
inline AtomProperties* Atom::getProperties() const {
    return (AtomProperties*) properties;
}

#endif //ATOM_H
