#ifndef LIGHTGUIDE_HPP_INCLUDED
#define LIGHTGUIDE_HPP_INCLUDED

#include <iostream>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <vector>
#include <NBO/NBO/LightGuideGeometry_Type.h>
#include <NBO/NBO/LightGuideMaterialName_Type.h>
#include <NBO/NBO/LightGuideType_Type.h>
#include <NBO/NBO/LightGuideWaveguideMode_Type.h>
#include <NBO/NBO/LightSourceCoupling_Type.h>
#include <NBO/NBO/UnitsAngle_Type.h>
#include <NBO/NBO/UnitsLength_Type.h>
#include <NBO/NBO/WavelengthRange.h>
#include <NBO/NBO/ENBOType.h>
#include <NBO/NBOGlobal.h>
#include <NBO/Shared/Base/NBOBaseClass.h>


namespace Inscoper::NBO {

/*!
* \brief Represents the XML element LightGuide.
*
* A Light Guide coupling between the Light Source and the Microscope Stand generally consists of a casing enclosing a medium (i.e., typically fiber optic) capable of transferring light from the illuminator to the back of the Microscope Stand.
*/
class NBO_EXPORT LightGuide : public LightSourceCoupling_Type {

public:
	
	LightGuide();
	~LightGuide();

	/*!
	* \brief Cast a NBOBaseClass to a LightGuide.
	*
	* \param base The base class to cast
	* \return The casted element, or nullptr if the cast fails
	*/
	static std::shared_ptr<LightGuide> fromBase(NBOBaseClassPtr base);

	/*!
	* \brief Returns the class type name.
	*
	* \return The class type name
	*/
	std::string getTypeName() const override;

	/*!
	* \brief Returns the XML element name corresponding to this class.
	*
	* \return The XML element name
	*/
	std::string getXMLName() const override;

	/*!
	* \brief Returns the NBO Type corresponding to this class.
	*
	* \return The NBO Type value
	*/
	ENBOType getNBOType() const override;

	/*!
	* \brief Returns a list of all classes derived from this class.
	*
	* \return The list of derived classes
	*/
	std::vector<NBOBaseClassPtr> getChildren() const override;

	/*!
	* \brief Returns a list of all child elements contained in this class.
	*
	* \return The list of child classes
	*/
	std::vector<NBOBaseClassPtr> getSubElements() const override;

	/*!
	* \brief Populates this object from a JSON file.
	*
	* \param path The path to the JSON file
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void fromJsonFile(const std::string& path, bool validate = true);

	/*!
	* \brief Populates this object from a JSON string.
	*
	* \param json_string The JSON content as a string
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void fromJsonString(const std::string& json_string, bool validate = true);

	/*!
	* \brief Populates this object from a XML file.
	*
	* \param path The path to the XML file
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void fromXmlFile(const std::string& path, bool validate = true);

	/*!
	* \brief Populates this object from a XML string.
	*
	* \param xml_string The XML content as a string
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void fromXmlString(const std::string& xml_string, bool validate = true);

	/*!
	* \brief Serializes this object to an XML file.
	*
	* \param filename The path to the output XML file
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void toXmlFile(const std::string& filename, bool validate = true) const;

	/*!
	* \brief Serializes this object to an XML string.
	*
	* \param validate If true, validates constraints on value. Default is true.
	* \return A string containing the XML representation of this object
	*/
	std::string toXmlString(bool validate = true) const;

	/*!
	* \brief Sets the value of the Type attribute.
	*
	* This field records the general category of Light Guide used in this case.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setType(const Inscoper::NBO::LightGuideType_TypePtr& value, bool validate = true);

	/*!
	* \brief Returns the value of the Type attribute.
	*
	* This field records the general category of Light Guide used in this case.
	*
	* \return The value of the attribute
	*/
	LightGuideType_TypePtr getType() const;

	/*!
	* \brief Resets the Type attribute to an unset state.
	*
	* This field records the general category of Light Guide used in this case.
	*/
	void resetType();

	/*!
	* \brief Checks whether the optional Type attribute is present.
	*
	* This field records the general category of Light Guide used in this case.
	*
	* \return true if the optional attribute has been set, false otherwise
	*/
	bool hasType() const;

	/*!
	* \brief Sets the value of the RefractiveIndex attribute.
	*
	* This field records the Refractive Index of the material used to construct this Light Guide.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setRefractiveIndex(const float& value, bool validate = true);

	/*!
	* \brief Returns the value of the RefractiveIndex attribute.
	*
	* This field records the Refractive Index of the material used to construct this Light Guide.
	*
	* \return The value of the attribute
	*/
	float getRefractiveIndex() const;

	/*!
	* \brief Resets the RefractiveIndex attribute to an unset state.
	*
	* This field records the Refractive Index of the material used to construct this Light Guide.
	*/
	void resetRefractiveIndex();

	/*!
	* \brief Checks whether the RefractiveIndex attribute is present.
	*
	* This field records the Refractive Index of the material used to construct this Light Guide.
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasRefractiveIndex() const;

	/*!
	* \brief Sets the value of the NumericalAperture attribute.
	*
	* The Numerical Aperture (NA) of this device expressed as a floating-point (real) number. NA can be calculated from the Angular Aperture (alpha) using the following formula, NA = n(sin alpha), and is a measure of how much of the incident light actually passes through this device. The larger the angular aperture, the more information this device can transmit. Expected range 0.02 - 1.5.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setNumericalAperture(const float& value, bool validate = true);

	/*!
	* \brief Returns the value of the NumericalAperture attribute.
	*
	* The Numerical Aperture (NA) of this device expressed as a floating-point (real) number. NA can be calculated from the Angular Aperture (alpha) using the following formula, NA = n(sin alpha), and is a measure of how much of the incident light actually passes through this device. The larger the angular aperture, the more information this device can transmit. Expected range 0.02 - 1.5.
	*
	* \return The value of the attribute
	*/
	float getNumericalAperture() const;

	/*!
	* \brief Resets the NumericalAperture attribute to an unset state.
	*
	* The Numerical Aperture (NA) of this device expressed as a floating-point (real) number. NA can be calculated from the Angular Aperture (alpha) using the following formula, NA = n(sin alpha), and is a measure of how much of the incident light actually passes through this device. The larger the angular aperture, the more information this device can transmit. Expected range 0.02 - 1.5.
	*/
	void resetNumericalAperture();

	/*!
	* \brief Checks whether the NumericalAperture attribute is present.
	*
	* The Numerical Aperture (NA) of this device expressed as a floating-point (real) number. NA can be calculated from the Angular Aperture (alpha) using the following formula, NA = n(sin alpha), and is a measure of how much of the incident light actually passes through this device. The larger the angular aperture, the more information this device can transmit. Expected range 0.02 - 1.5.
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasNumericalAperture() const;

	/*!
	* \brief Sets the value of the AcceptanceAngle attribute.
	*
	* The angle within which the light beam produced by a Light Source may be coupled with the bound modes of this Light Guide.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setAcceptanceAngle(const float& value, bool validate = true);

	/*!
	* \brief Returns the value of the AcceptanceAngle attribute.
	*
	* The angle within which the light beam produced by a Light Source may be coupled with the bound modes of this Light Guide.
	*
	* \return The value of the attribute
	*/
	float getAcceptanceAngle() const;

	/*!
	* \brief Resets the AcceptanceAngle attribute to an unset state.
	*
	* The angle within which the light beam produced by a Light Source may be coupled with the bound modes of this Light Guide.
	*/
	void resetAcceptanceAngle();

	/*!
	* \brief Checks whether the AcceptanceAngle attribute is present.
	*
	* The angle within which the light beam produced by a Light Source may be coupled with the bound modes of this Light Guide.
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasAcceptanceAngle() const;

	/*!
	* \brief Sets the value of the AcceptanceAngleUnit attribute.
	*
	* No description available in the XSD standard.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setAcceptanceAngleUnit(const Inscoper::NBO::UnitsAngle_TypePtr& value, bool validate = true);

	/*!
	* \brief Returns the value of the AcceptanceAngleUnit attribute.
	*
	* No description available in the XSD standard.
	*
	* \return The value of the attribute
	*/
	UnitsAngle_TypePtr getAcceptanceAngleUnit() const;

	/*!
	* \brief Resets the AcceptanceAngleUnit attribute to an unset state.
	*
	* No description available in the XSD standard.
	*/
	void resetAcceptanceAngleUnit();

	/*!
	* \brief Checks whether the optional AcceptanceAngleUnit attribute is present.
	*
	* No description available in the XSD standard.
	*
	* \return true if the optional attribute has been set, false otherwise
	*/
	bool hasAcceptanceAngleUnit() const;

	/*!
	* \brief Sets the value of the Geometry attribute.
	*
	* This field records the cross-section shape of this Light Guide.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setGeometry(const Inscoper::NBO::LightGuideGeometry_TypePtr& value, bool validate = true);

	/*!
	* \brief Returns the value of the Geometry attribute.
	*
	* This field records the cross-section shape of this Light Guide.
	*
	* \return The value of the attribute
	*/
	LightGuideGeometry_TypePtr getGeometry() const;

	/*!
	* \brief Resets the Geometry attribute to an unset state.
	*
	* This field records the cross-section shape of this Light Guide.
	*/
	void resetGeometry();

	/*!
	* \brief Checks whether the optional Geometry attribute is present.
	*
	* This field records the cross-section shape of this Light Guide.
	*
	* \return true if the optional attribute has been set, false otherwise
	*/
	bool hasGeometry() const;

	/*!
	* \brief Sets the value of the MaterialName attribute.
	*
	* This field records the chemical composition or the non-proprietary trade designation of the material used to construct this Light Guide.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setMaterialName(const Inscoper::NBO::LightGuideMaterialName_TypePtr& value, bool validate = true);

	/*!
	* \brief Returns the value of the MaterialName attribute.
	*
	* This field records the chemical composition or the non-proprietary trade designation of the material used to construct this Light Guide.
	*
	* \return The value of the attribute
	*/
	LightGuideMaterialName_TypePtr getMaterialName() const;

	/*!
	* \brief Resets the MaterialName attribute to an unset state.
	*
	* This field records the chemical composition or the non-proprietary trade designation of the material used to construct this Light Guide.
	*/
	void resetMaterialName();

	/*!
	* \brief Checks whether the optional MaterialName attribute is present.
	*
	* This field records the chemical composition or the non-proprietary trade designation of the material used to construct this Light Guide.
	*
	* \return true if the optional attribute has been set, false otherwise
	*/
	bool hasMaterialName() const;

	/*!
	* \brief Sets the value of the SingleMode attribute.
	*
	* This field records whether (True) this Light Guide is single-mode. If not (False), then the guide is assumend to be multi-modal.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setSingleMode(const bool& value, bool validate = true);

	/*!
	* \brief Returns the value of the SingleMode attribute.
	*
	* This field records whether (True) this Light Guide is single-mode. If not (False), then the guide is assumend to be multi-modal.
	*
	* \return The value of the attribute
	*/
	bool getSingleMode() const;

	/*!
	* \brief Resets the SingleMode attribute to an unset state.
	*
	* This field records whether (True) this Light Guide is single-mode. If not (False), then the guide is assumend to be multi-modal.
	*/
	void resetSingleMode();

	/*!
	* \brief Checks whether the SingleMode attribute is present.
	*
	* This field records whether (True) this Light Guide is single-mode. If not (False), then the guide is assumend to be multi-modal.
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasSingleMode() const;

	/*!
	* \brief Sets the value of the WaveguideMode attribute.
	*
	* This field records the transverse mode (or superposition of such modes) that are being imposed by this light guide onto the light wave traversing it. These modes generally follow different propagation constants.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setWaveguideMode(const Inscoper::NBO::LightGuideWaveguideMode_TypePtr& value, bool validate = true);

	/*!
	* \brief Returns the value of the WaveguideMode attribute.
	*
	* This field records the transverse mode (or superposition of such modes) that are being imposed by this light guide onto the light wave traversing it. These modes generally follow different propagation constants.
	*
	* \return The value of the attribute
	*/
	LightGuideWaveguideMode_TypePtr getWaveguideMode() const;

	/*!
	* \brief Resets the WaveguideMode attribute to an unset state.
	*
	* This field records the transverse mode (or superposition of such modes) that are being imposed by this light guide onto the light wave traversing it. These modes generally follow different propagation constants.
	*/
	void resetWaveguideMode();

	/*!
	* \brief Checks whether the optional WaveguideMode attribute is present.
	*
	* This field records the transverse mode (or superposition of such modes) that are being imposed by this light guide onto the light wave traversing it. These modes generally follow different propagation constants.
	*
	* \return true if the optional attribute has been set, false otherwise
	*/
	bool hasWaveguideMode() const;

	/*!
	* \brief Sets the value of the Diameter attribute.
	*
	* This fields records the outer diameter of this Light Guide.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setDiameter(const float& value, bool validate = true);

	/*!
	* \brief Returns the value of the Diameter attribute.
	*
	* This fields records the outer diameter of this Light Guide.
	*
	* \return The value of the attribute
	*/
	float getDiameter() const;

	/*!
	* \brief Resets the Diameter attribute to an unset state.
	*
	* This fields records the outer diameter of this Light Guide.
	*/
	void resetDiameter();

	/*!
	* \brief Checks whether the Diameter attribute is present.
	*
	* This fields records the outer diameter of this Light Guide.
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasDiameter() const;

	/*!
	* \brief Sets the value of the DiameterUnit attribute.
	*
	* No description available in the XSD standard.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setDiameterUnit(const Inscoper::NBO::UnitsLength_TypePtr& value, bool validate = true);

	/*!
	* \brief Returns the value of the DiameterUnit attribute.
	*
	* No description available in the XSD standard.
	*
	* \return The value of the attribute
	*/
	UnitsLength_TypePtr getDiameterUnit() const;

	/*!
	* \brief Resets the DiameterUnit attribute to an unset state.
	*
	* No description available in the XSD standard.
	*/
	void resetDiameterUnit();

	/*!
	* \brief Checks whether the optional DiameterUnit attribute is present.
	*
	* No description available in the XSD standard.
	*
	* \return true if the optional attribute has been set, false otherwise
	*/
	bool hasDiameterUnit() const;

	/*!
	* \brief Sets the list of WavelengthRange elements.
	*
	* This element records a range of Wavelengths this component is designed for, according to the Manufacturer. Multiple of this element may be used.
	*
	* \param value The new list of WavelengthRange elements
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setWavelengthRange_List(const std::vector<Inscoper::NBO::WavelengthRangePtr>& value, bool validate = true);

	/*!
	* \brief Returns the list of WavelengthRange elements.
	*
	* This element records a range of Wavelengths this component is designed for, according to the Manufacturer. Multiple of this element may be used.
	*
	* \return The list of WavelengthRange elements
	*/
	std::vector<Inscoper::NBO::WavelengthRangePtr> getWavelengthRange_List() const;

	/*!
	* \brief Adds a new WavelengthRange element to this object.
	*
	* This element records a range of Wavelengths this component is designed for, according to the Manufacturer. Multiple of this element may be used.
	*
	* \param value The element to add
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void addToWavelengthRange_List(const Inscoper::NBO::WavelengthRangePtr& value, bool validate = true);

	/*!
	* \brief Clear the list of WavelengthRange.
	*
	* This element records a range of Wavelengths this component is designed for, according to the Manufacturer. Multiple of this element may be used.
	*/
	void clearWavelengthRange_List();


private:
	class Impl;
	std::unique_ptr<Impl> pImpl;

	LightGuideType_TypePtr Type = nullptr; // Required attribute
    std::optional<float> RefractiveIndex; // Optional attribute
    std::optional<float> NumericalAperture; // Required attribute
    std::optional<float> AcceptanceAngle; // Optional attribute
	UnitsAngle_TypePtr AcceptanceAngleUnit = nullptr; // Optional attribute
	LightGuideGeometry_TypePtr Geometry = nullptr; // Optional attribute
	LightGuideMaterialName_TypePtr MaterialName = nullptr; // Optional attribute
    std::optional<bool> SingleMode; // Optional attribute
	LightGuideWaveguideMode_TypePtr WaveguideMode = nullptr; // Optional attribute
    std::optional<float> Diameter; // Optional attribute
	UnitsLength_TypePtr DiameterUnit = nullptr; // Optional attribute
    std::vector<Inscoper::NBO::WavelengthRangePtr> WavelengthRange_List;
};

/*! Shared pointer for LightGuide*/
typedef std::shared_ptr<LightGuide> LightGuidePtr;

} // namespace Inscoper::NBO

#endif // LIGHTGUIDE_HPP_INCLUDED