/*****************************************************************************
 * $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 STRUCTURALCOMPONENTPROPERTIES_H
#define STRUCTURALCOMPONENTPROPERTIES_H

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

#include "Properties.h"
#include "RenderingMode.h"

/**
  * @ingroup group_cepmodeling_libraries_pml
  *
  * @brief
  * A class that manages the structural component properties.
  *
 **/
class StructuralComponentProperties  : public Properties {

public:
    /** Default color settings
    */
    enum Color {
        DEFAULT,  /**< no color given, decided by the GUI */
        RED,      /**< full complete flashy red */
        GREEN,    /**< full complete flashy green */
        BLUE,     /**< full complete flashy blue */
        GRAY,     /**< classic gray */
        OTHER     /**< color is defined using RGBA */
    };

    /** use a Color constant to set the color */
    StructuralComponentProperties(PhysicalModel* p, const Color c) : Properties(p) {
        alloc();
        setColor(c);
        setMode(RenderingMode::WIREFRAME_AND_SURFACE);
    };

    StructuralComponentProperties(PhysicalModel* p,  physicalModel::StructuralComponent xmlSC);
    StructuralComponentProperties(PhysicalModel* p, const Color c, const std::string n) : Properties(p, n) {
        alloc();
        setColor(c);
        setMode(RenderingMode::WIREFRAME_AND_SURFACE);
    };

    /** use a double[3] array to set the color */
    StructuralComponentProperties(PhysicalModel* p, const double* rgb) : Properties(p)  {
        alloc();
        setRGB(rgb);
        setAlpha(1.0);
        setMode(RenderingMode::WIREFRAME_AND_SURFACE);
    };

    StructuralComponentProperties(PhysicalModel* p, const double* rgb, const std::string n) : Properties(p, n)  {
        alloc();
        setRGB(rgb);
        setAlpha(1.0);
        setMode(RenderingMode::WIREFRAME_AND_SURFACE);
    };

    /** use 3 floats to set the color */
    StructuralComponentProperties(PhysicalModel* p, const double r, const double g, const double b) : Properties(p)  {
        alloc();
        setRGB(r, g, b);
        setAlpha(1.0);
        setMode(RenderingMode::WIREFRAME_AND_SURFACE);
    };

    StructuralComponentProperties(PhysicalModel* p, const double r, const double g, const double b, const std::string n) : Properties(p, n)  {
        alloc();
        setRGB(r, g, b);
        setAlpha(1.0);
        setMode(RenderingMode::WIREFRAME_AND_SURFACE);
    };

    /** defaultcolor is gray */
    StructuralComponentProperties(PhysicalModel* p) : Properties(p)  {
        alloc();
        setColor(DEFAULT);
        setMode(RenderingMode::WIREFRAME_AND_SURFACE);
    }

    ;
    StructuralComponentProperties(PhysicalModel* p, const std::string n) : Properties(p, n)  {
        alloc();
        setColor(DEFAULT);
        setMode(RenderingMode::WIREFRAME_AND_SURFACE);
    };

    ~StructuralComponentProperties() {
        delete [] colorRGBA;
    };

    double getRed() const;
    double getGreen() const;
    double getBlue() const;
    double getAlpha() const;
    double* getRGB() const;
    double* getRGBA() const;
    Color getColor() const;

    void setRed(const double r);
    void setGreen(const double g);
    void setBlue(const double b);
    void setAlpha(const double a);
    void setRGB(const double* rgb);
    void setRGB(const double r, const double g, const double b);
    void setRGBA(const double r, const double g, const double b, const double a);
    void setRGBA(const double* rgba);
    void setColor(Color c);

    void setMode(const RenderingMode::Mode);
    RenderingMode::Mode getMode() const;
    bool isVisible(const RenderingMode::Mode mode) const;
    void setVisible(const RenderingMode::Mode, const bool);

    /// get the string equivalent to the enum rendering mode
    std::string getModeString() const;

    /** print to an output stream in "pseaudo" XML format.
      * This method is to be implemented in the subclass (StructuralComponentProperties).
      * It HAS to call the beginXML() at the beginning and the endXML() at the end.
      */
    virtual void xmlPrint(std::ostream&);

private:
    double* colorRGBA;
    void alloc();
    Color color;
    RenderingMode mode;
};

// inlines
inline  double StructuralComponentProperties::getRed() const {
    return colorRGBA[0];
}

inline double StructuralComponentProperties::getGreen() const {
    return colorRGBA[1];
}

inline double StructuralComponentProperties::getBlue() const {
    return colorRGBA[2];
}

inline double StructuralComponentProperties::getAlpha() const {
    return colorRGBA[3];
}

inline double* StructuralComponentProperties::getRGB() const {
    return colorRGBA;
}

inline double* StructuralComponentProperties::getRGBA() const {
    return colorRGBA;
}

inline StructuralComponentProperties::Color StructuralComponentProperties::getColor() const {
    return color;
}

// TODO : a test for the color, if a composant is changed it might still be something we know
// so color = OTHER is a bit presumptuous
inline void StructuralComponentProperties::setRed(const double r) {
    colorRGBA[0]  = r;
    color = OTHER;
}

inline void StructuralComponentProperties::setGreen(const double g)  {
    colorRGBA[1] = g;
    color = OTHER;
}

inline void StructuralComponentProperties::setBlue(const double b)  {
    colorRGBA[2] = b;
    color = OTHER;
}

inline void StructuralComponentProperties::setAlpha(const double a)  {
    colorRGBA[3] = a;
    color = OTHER;
}

inline void StructuralComponentProperties::setRGB(const double r, const double g, const double b)  {
    setRed(r);
    setGreen(g);
    setBlue(b);
    color = OTHER;
}

inline void StructuralComponentProperties::setRGB(const double* rgb) {
    setRGB(rgb[0], rgb[1], rgb[2]);
    color = OTHER;
}

inline void StructuralComponentProperties::setRGBA(const double r, const double g, const double b, const double a)   {
    setRed(r);
    setGreen(g);
    setBlue(b);
    setAlpha(a);
    color = OTHER;
}

inline void StructuralComponentProperties::setRGBA(const double* rgba) {
    setRGBA(rgba[0], rgba[1], rgba[2], rgba[3]);
    color = OTHER;
}

inline void StructuralComponentProperties::setColor(Color c) {
    switch (c) {

        case RED:
            setRGBA(1.0, 0.0, 0.0, 1.0);
            break;

        case GREEN:
            setRGBA(0.0, 1.0, 0.0, 1.0);
            break;

        case BLUE:
            setRGBA(0.0, 0.0, 1.0, 1.0);
            break;

        default: // DEFAULT:or GRAY:or OTHER
            setRGBA(0.8, 0.8, 0.8, 1.0);
            break;
    }

    color = c;
}

inline void StructuralComponentProperties::alloc() {
    colorRGBA = new double[4];
}

inline void StructuralComponentProperties::setMode(const RenderingMode::Mode m) {
    mode.setMode(m);
}

inline RenderingMode::Mode StructuralComponentProperties::getMode() const {
    return mode.getMode();
}

inline std::string StructuralComponentProperties::getModeString() const {
    return mode.getModeString();
}

inline bool StructuralComponentProperties::isVisible(const RenderingMode::Mode m) const {
    return mode.isVisible(m);
}

inline void StructuralComponentProperties::setVisible(const RenderingMode::Mode m, const bool b) {
    mode.setVisible(m, b);
}


#endif //STRUCTURALCOMPONENTPROPERTIES_H
