/*****************************************************************************
 * $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$
 ****************************************************************************/
#include "AtomProperties.h"

// XSD / XercesC stuffs
#include <xercesc/util/XercesDefs.hpp>
#include <xercesc/dom/DOMAttr.hpp>
#include <xercesc/util/XMLString.hpp>

// pmlschema includes
#include <AtomProperties.hxx>

//----------------------- Class member init -----------------------
void AtomProperties::resetUniqueIndex() {
    AtomProperties::maxUniqueIndex = 0;
}

// initializing the static class member
unsigned int AtomProperties::maxUniqueIndex = 0;

//----------------------- Constructors -----------------------
AtomProperties::AtomProperties(PhysicalModel* p)  : StructureProperties(p, StructureProperties::ATOM) {
    allocate();
    setPosition(0.0, 0.0, 0.0);
    index = maxUniqueIndex++;
}

AtomProperties::AtomProperties(PhysicalModel* p, physicalModel::AtomProperties xmlAtomProp)  : StructureProperties(p, StructureProperties::ATOM) {
    allocate();

    // Begin the search by required atom's properties, such as index and its position (x,y,z)
    setIndex(xmlAtomProp.index());
    setPosition(xmlAtomProp.x(), xmlAtomProp.y(), xmlAtomProp.z());

    // Search for any optional name given to the atom
    if (xmlAtomProp.name().present()) {
        setName(xmlAtomProp.name().get());
    }

    // Add the eventually unkown attributes
    xmlToFields(xmlAtomProp.any_attribute());
}

AtomProperties::AtomProperties(PhysicalModel* p, const double pos[3]) : StructureProperties(p, StructureProperties::ATOM) {
    allocate();
    setPosition(pos);
    index = maxUniqueIndex++;
}

AtomProperties::AtomProperties(PhysicalModel* p, const unsigned int ind)  :  StructureProperties(p, StructureProperties::ATOM) {
    allocate();
    setPosition(0.0, 0.0, 0.0);
    index = ind;

    if (ind >= maxUniqueIndex) {
        maxUniqueIndex = ind + 1;
    }
}

AtomProperties::AtomProperties(PhysicalModel* p, const unsigned int ind, const double pos[3]) : StructureProperties(p, StructureProperties::ATOM) {
    allocate();
    setPosition(pos);
    index = ind;

    if (ind >= maxUniqueIndex) {
        maxUniqueIndex = ind + 1;
    }
}

//----------------------- destructor -----------------------
AtomProperties::~AtomProperties() {
    if (allocated) {
        delete [] X;
    }
}

//----------------------- allocate -----------------------
void AtomProperties::allocate() {
    X = new double[3];
    allocated = true;
}

//----------------------- setPositionPointer -----------------------
void AtomProperties::setPositionPointer(double* ptr, bool update) {
    // store previous position if needed
    double pos[3];

    if (update) {
        getPosition(pos);
    }

    // delete previous memory to avoid memory leaks, if needed
    if (allocated) {
        delete [] X;
        allocated = false;
    }

    X = ptr;

    // restore if needed
    if (update) {
        setPosition(pos);
    }
}

// --------------- xmlPrint ---------------
void AtomProperties::xmlPrint(std::ostream& o) {

    // beginning of the atom properties
    o << "<atomProperties index=\"" << index << "\"";
    o << " x=\"" << X[0] << "\" y=\"" << X[1] << "\" z=\"" << X[2] << "\"";

    if (getName() != "") {
        o << " name=\"" << getName().c_str() << "\"";
    }

    for (std::map<std::string, std::string>::iterator it = fields.begin(); it != fields.end() ; ++it) {
        o << " " << (*it).first << "=\"" << (*it).second << "\"";
    }

    // end of the properties
    o << "/>" << std::endl;

}
