#ifndef PHASERING_HPP_INCLUDED
#define PHASERING_HPP_INCLUDED

#include <iostream>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <vector>
#include <NBO/NBO/OpticalAperture_Type.h>
#include <NBO/NBO/PhaseRingNumber_Type.h>
#include <NBO/NBO/PositiveFloat_Type.h>
#include <NBO/NBO/UnitsLength_Type.h>
#include <NBO/NBO/ENBOType.h>
#include <NBO/NBOGlobal.h>
#include <NBO/Shared/Base/NBOBaseClass.h>


namespace Inscoper::NBO {

/*!
* \brief Represents the XML element PhaseRing.
*
* This element (also called Phase Annulus) refers to an annular (ring-like) slit used to produce contrast modulation following Zernike, in which the Image contrast of a phase object is enhanced by altering the phase and amplitude of the direct light with respect to those of the diffracted light. This illuminating aperture Diaphragm is placed in the front focal Plane of the Condenser and acts in conjunction with an appropriate phase plate, usually in the form of an annulus, placed in the back focal Plane of the objective (or in a succeeding Plane conjugate with this).
*/
class NBO_EXPORT PhaseRing : public OpticalAperture_Type {

public:
	
	PhaseRing();
	~PhaseRing();

	/*!
	* \brief Cast a NBOBaseClass to a PhaseRing.
	*
	* \param base The base class to cast
	* \return The casted element, or nullptr if the cast fails
	*/
	static std::shared_ptr<PhaseRing> 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 PhaseNumber attribute.
	*
	* This field captures the Phase Number used to identify the size of the annular slit of this Phase Ring. The Phase Number must match the Phase Plate found within a Phase-contrast capable Objective lens.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setPhaseNumber(const Inscoper::NBO::PhaseRingNumber_TypePtr& value, bool validate = true);

	/*!
	* \brief Returns the value of the PhaseNumber attribute.
	*
	* This field captures the Phase Number used to identify the size of the annular slit of this Phase Ring. The Phase Number must match the Phase Plate found within a Phase-contrast capable Objective lens.
	*
	* \return The value of the attribute
	*/
	PhaseRingNumber_TypePtr getPhaseNumber() const;

	/*!
	* \brief Resets the PhaseNumber attribute to an unset state.
	*
	* This field captures the Phase Number used to identify the size of the annular slit of this Phase Ring. The Phase Number must match the Phase Plate found within a Phase-contrast capable Objective lens.
	*/
	void resetPhaseNumber();

	/*!
	* \brief Checks whether the optional PhaseNumber attribute is present.
	*
	* This field captures the Phase Number used to identify the size of the annular slit of this Phase Ring. The Phase Number must match the Phase Plate found within a Phase-contrast capable Objective lens.
	*
	* \return true if the optional attribute has been set, false otherwise
	*/
	bool hasPhaseNumber() const;

	/*!
	* \brief Sets the value of the CenterStopDiameter attribute.
	*
	* This filed records the physical diameter of the center-stop (i.e. opaque disk) of this Phase Ring.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setCenterStopDiameter(const float& value, bool validate = true);

	/*!
	* \brief Returns the value of the CenterStopDiameter attribute.
	*
	* This filed records the physical diameter of the center-stop (i.e. opaque disk) of this Phase Ring.
	*
	* \return The value of the attribute
	*/
	float getCenterStopDiameter() const;

	/*!
	* \brief Resets the CenterStopDiameter attribute to an unset state.
	*
	* This filed records the physical diameter of the center-stop (i.e. opaque disk) of this Phase Ring.
	*/
	void resetCenterStopDiameter();

	/*!
	* \brief Checks whether the CenterStopDiameter attribute is present.
	*
	* This filed records the physical diameter of the center-stop (i.e. opaque disk) of this Phase Ring.
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasCenterStopDiameter() const;

	/*!
	* \brief Sets the value of the CenterStopDiameterUnit 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 setCenterStopDiameterUnit(const Inscoper::NBO::UnitsLength_TypePtr& value, bool validate = true);

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

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

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

	/*!
	* \brief Sets the value of the SlitWidth attribute.
	*
	* This field records the physical width of the annular slit of this Phase Ring.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setSlitWidth(const Inscoper::NBO::PositiveFloat_TypePtr& value, bool validate = true);

	/*!
	* \brief Returns the value of the SlitWidth attribute.
	*
	* This field records the physical width of the annular slit of this Phase Ring.
	*
	* \return The value of the attribute
	*/
	PositiveFloat_TypePtr getSlitWidth() const;

	/*!
	* \brief Resets the SlitWidth attribute to an unset state.
	*
	* This field records the physical width of the annular slit of this Phase Ring.
	*/
	void resetSlitWidth();

	/*!
	* \brief Checks whether the optional SlitWidth attribute is present.
	*
	* This field records the physical width of the annular slit of this Phase Ring.
	*
	* \return true if the optional attribute has been set, false otherwise
	*/
	bool hasSlitWidth() const;

	/*!
	* \brief Sets the value of the SlitWidthUnit 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 setSlitWidthUnit(const Inscoper::NBO::UnitsLength_TypePtr& value, bool validate = true);

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

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

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


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

	PhaseRingNumber_TypePtr PhaseNumber = nullptr; // Required attribute
    std::optional<float> CenterStopDiameter; // Optional attribute
	UnitsLength_TypePtr CenterStopDiameterUnit = nullptr; // Optional attribute
	PositiveFloat_TypePtr SlitWidth = nullptr; // Optional attribute
	UnitsLength_TypePtr SlitWidthUnit = nullptr; // Optional attribute
};

/*! Shared pointer for PhaseRing*/
typedef std::shared_ptr<PhaseRing> PhaseRingPtr;

} // namespace Inscoper::NBO

#endif // PHASERING_HPP_INCLUDED