/*****************************************************************************
 * $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 RENDERING_MODE_H
#define RENDERING_MODE_H
//#include "PhysicalModelIO.h"
#include <string>
/**
 * @ingroup group_cepmodeling_libraries_pml
 *
 * @brief
 * Handle rendering options (surface and wireframe) of an Object3D.
 *
 **/
class RenderingMode {
public:
    /** This is a duplicate of RenderingMode Mode.... BEURK!!! */
    enum Mode {
        NONE,
        POINTS,
        POINTS_AND_SURFACE,
        SURFACE,
        WIREFRAME_AND_SURFACE,
        WIREFRAME_AND_POINTS,
        WIREFRAME,
        WIREFRAME_AND_SURFACE_AND_POINTS
    };

    /// default constructor with initialisation
    RenderingMode(const Mode mode = SURFACE) {
        // set the visibility flags
        setMode(mode);
    }

    /** another constructor provided for conveniance
      * @param surface tells if by default the surface is visible
      * @param wireframe tells if by default the surface is visible
      * @param points tells if by default the surface is visible
      */
    RenderingMode(const bool surface, const bool wireframe, const bool points) {
        setVisible(SURFACE, surface);
        setVisible(WIREFRAME, wireframe);
        setVisible(POINTS, points);
    }

    /** Set a rendering mode visible or not.*/
    void setVisible(const Mode mode, const bool value) {
        switch (mode) {
            case SURFACE:
                surfaceVisibility = value;
                break;
            case WIREFRAME:
                wireframeVisibility = value;
                break;
            case POINTS:
                pointsVisibility = value;
                break;
            case POINTS_AND_SURFACE:
                wireframeVisibility = !value;
                surfaceVisibility = pointsVisibility = value;
                break;
            case WIREFRAME_AND_SURFACE_AND_POINTS:
                surfaceVisibility = wireframeVisibility = pointsVisibility = value;
                break;
            case WIREFRAME_AND_SURFACE:
                surfaceVisibility = wireframeVisibility = value;
                pointsVisibility = !value;
                break;
            case WIREFRAME_AND_POINTS:
                pointsVisibility = wireframeVisibility = value;
                surfaceVisibility = !value;
                break;
            default:
                break;
        }
    }

    /** Return if a rendering mode is currently visible or not.*/
    bool isVisible(const Mode mode) const {
        switch (mode) {
            case SURFACE:
                return surfaceVisibility;
                break;
            case WIREFRAME:
                return wireframeVisibility;
                break;
            case POINTS:
                return pointsVisibility;
                break;
            case POINTS_AND_SURFACE:
                return (surfaceVisibility && pointsVisibility);
                break;
            case WIREFRAME_AND_SURFACE:
                return (wireframeVisibility && surfaceVisibility);
                break;
            case WIREFRAME_AND_POINTS:
                return (wireframeVisibility && pointsVisibility);
                break;
            case WIREFRAME_AND_SURFACE_AND_POINTS:
                return (wireframeVisibility && surfaceVisibility && pointsVisibility);
                break;
            default:
                return false;
                break;
        }
    }

    /** Return true if at least a mode is currently visible, false otherwise.*/
    bool isVisible() const {
        // true if at least a mode is visible
        return (surfaceVisibility || wireframeVisibility || pointsVisibility);
    }

    /** set a vizualisation mode */
    void setMode(const Mode mode)  {
        switch (mode) 	{
            case NONE:
                surfaceVisibility = wireframeVisibility = pointsVisibility = false;
                break;
            case POINTS:
                surfaceVisibility = wireframeVisibility = false;
                pointsVisibility = true;
                break;
            case POINTS_AND_SURFACE:
                wireframeVisibility = false;
                surfaceVisibility = pointsVisibility = true;
                break;
            case SURFACE:
                surfaceVisibility = true;
                wireframeVisibility = pointsVisibility = false;
                break;
            case WIREFRAME_AND_SURFACE_AND_POINTS:
                surfaceVisibility = wireframeVisibility = pointsVisibility = true;
                break;
            case WIREFRAME_AND_SURFACE:
                surfaceVisibility = wireframeVisibility = true;
                pointsVisibility = false;
                break;
            case WIREFRAME_AND_POINTS:
                pointsVisibility = wireframeVisibility = true;
                surfaceVisibility = false;
                break;
            case WIREFRAME:
                surfaceVisibility = pointsVisibility = false;
                wireframeVisibility = true;
                break;
        }
    }

    /** get current mode */
    RenderingMode::Mode getMode() const {
        if (pointsVisibility) {
            if (surfaceVisibility) {
                if (wireframeVisibility) {
                    return WIREFRAME_AND_SURFACE_AND_POINTS;
                }
                else {
                    return POINTS_AND_SURFACE;
                }
            }
            else {
                if (wireframeVisibility) {
                    return WIREFRAME_AND_POINTS;
                }
                else {
                    return POINTS;
                }
            }
        }
        else {
            if (surfaceVisibility) {
                if (wireframeVisibility) {
                    return WIREFRAME_AND_SURFACE;
                }
                else {
                    return SURFACE;
                }
            }
            else {
                if (wireframeVisibility) {
                    return WIREFRAME;
                }
                else {
                    return NONE;
                }
            }
        }
    }

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

        if (pointsVisibility) {
            if (surfaceVisibility) {
                if (wireframeVisibility) {
                    n = "WIREFRAME_AND_SURFACE_AND_POINTS";
                }
                else {
                    n = "POINTS_AND_SURFACE";
                }
            }
            else {
                if (wireframeVisibility) {
                    n = "WIREFRAME_AND_POINTS";
                }
                else {
                    n = "POINTS";
                }
            }
        }
        else {
            if (surfaceVisibility) {
                if (wireframeVisibility) {
                    n = "WIREFRAME_AND_SURFACE";
                }
                else {
                    n = "SURFACE";
                }
            }
            else {
                if (wireframeVisibility) {
                    n = "WIREFRAME";
                }
                else {
                    n = "NONE";
                }
            }
        }

        return n;
    }

private:

    // Visibility flags
    /** Flag indicating weither the surface mode is currenly visible or not. */
    bool surfaceVisibility;
    /** Flag indicating weither the wireframe mode is currenly visible or not. */
    bool wireframeVisibility;
    /** Flag indicating weither the points mode is currenly visible or not. */
    bool pointsVisibility;
};

#endif
