#ifndef OBJECTIVESETTINGS_HPP_INCLUDED
#define OBJECTIVESETTINGS_HPP_INCLUDED

#include <iostream>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <vector>
#include <NBO/NBO/ImmersionLiquid.h>
#include <NBO/NBO/ObjectiveID_Type.h>
#include <NBO/NBO/Settings_Type.h>
#include <NBO/NBO/UnitsTemperature_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 ObjectiveSettings.
*
* This element holds the Setting applied to the Objective used during the Acquisition of this Image as well as a reference (the ID attribute) to the Objective in question.
*/
class NBO_EXPORT ObjectiveSettings : public Settings_Type {

public:
	
	ObjectiveSettings();
	~ObjectiveSettings();

	/*!
	* \brief Cast a NBOBaseClass to a ObjectiveSettings.
	*
	* \param base The base class to cast
	* \return The casted element, or nullptr if the cast fails
	*/
	static std::shared_ptr<ObjectiveSettings> 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 ID attribute.
	*
	* This is the Unique Identifier of the Objective used in this case.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setID(const Inscoper::NBO::ObjectiveID_TypePtr& value, bool validate = true);

	/*!
	* \brief Returns the value of the ID attribute.
	*
	* This is the Unique Identifier of the Objective used in this case.
	*
	* \return The value of the attribute
	*/
	ObjectiveID_TypePtr getID() const;

	/*!
	* \brief Resets the ID attribute to an unset state.
	*
	* This is the Unique Identifier of the Objective used in this case.
	*/
	void resetID();

	/*!
	* \brief Checks whether the optional ID attribute is present.
	*
	* This is the Unique Identifier of the Objective used in this case.
	*
	* \return true if the optional attribute has been set, false otherwise
	*/
	bool hasID() const;

	/*!
	* \brief Sets the value of the CorrectionCollarPosition attribute.
	*
	* The Correction Collar typically consists of an adjustable ring on the Objective whose position can be modified. This field records the position of the collar during the Acquisition of this Image. Each correction collar has an arbitrary scale or it might be scale-less and instead have fixed positions with qualitative designations (i.e., Oil, Water in case in which the Objective might be corrected for Immersion Liquid).
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setCorrectionCollarPosition(const std::string& value, bool validate = true);

	/*!
	* \brief Returns the value of the CorrectionCollarPosition attribute.
	*
	* The Correction Collar typically consists of an adjustable ring on the Objective whose position can be modified. This field records the position of the collar during the Acquisition of this Image. Each correction collar has an arbitrary scale or it might be scale-less and instead have fixed positions with qualitative designations (i.e., Oil, Water in case in which the Objective might be corrected for Immersion Liquid).
	*
	* \return The value of the attribute
	*/
	std::string getCorrectionCollarPosition() const;

	/*!
	* \brief Resets the CorrectionCollarPosition attribute to an unset state.
	*
	* The Correction Collar typically consists of an adjustable ring on the Objective whose position can be modified. This field records the position of the collar during the Acquisition of this Image. Each correction collar has an arbitrary scale or it might be scale-less and instead have fixed positions with qualitative designations (i.e., Oil, Water in case in which the Objective might be corrected for Immersion Liquid).
	*/
	void resetCorrectionCollarPosition();

	/*!
	* \brief Checks whether the CorrectionCollarPosition attribute is present.
	*
	* The Correction Collar typically consists of an adjustable ring on the Objective whose position can be modified. This field records the position of the collar during the Acquisition of this Image. Each correction collar has an arbitrary scale or it might be scale-less and instead have fixed positions with qualitative designations (i.e., Oil, Water in case in which the Objective might be corrected for Immersion Liquid).
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasCorrectionCollarPosition() const;

	/*!
	* \brief Returns the allowed values for this attribut.
	*
	* The Correction Collar typically consists of an adjustable ring on the Objective whose position can be modified. This field records the position of the collar during the Acquisition of this Image. Each correction collar has an arbitrary scale or it might be scale-less and instead have fixed positions with qualitative designations (i.e., Oil, Water in case in which the Objective might be corrected for Immersion Liquid).
	*
	* \return The list of allowed values
	*/
	static const std::set<std::string>& getCorrectionCollarPositionAllowedValues();

	/*!
	* \brief Sets the value of the NumericalApertureSetting attribute.
	*
	* In case the Numerical Aperture (NA) of this Objective is variable (i.e., as for example in case of Objectives that can be used with or without Cover Glass or Objectives that can be dipped in different media), this field capture the NA setting that was employed for Image Acquisition. NOTE: please note that often NA regulation in these types of Objectives occurs via a rotating collar whose exact position is difficult to measure and reproduce across different Experiments.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setNumericalApertureSetting(const std::string& value, bool validate = true);

	/*!
	* \brief Returns the value of the NumericalApertureSetting attribute.
	*
	* In case the Numerical Aperture (NA) of this Objective is variable (i.e., as for example in case of Objectives that can be used with or without Cover Glass or Objectives that can be dipped in different media), this field capture the NA setting that was employed for Image Acquisition. NOTE: please note that often NA regulation in these types of Objectives occurs via a rotating collar whose exact position is difficult to measure and reproduce across different Experiments.
	*
	* \return The value of the attribute
	*/
	std::string getNumericalApertureSetting() const;

	/*!
	* \brief Resets the NumericalApertureSetting attribute to an unset state.
	*
	* In case the Numerical Aperture (NA) of this Objective is variable (i.e., as for example in case of Objectives that can be used with or without Cover Glass or Objectives that can be dipped in different media), this field capture the NA setting that was employed for Image Acquisition. NOTE: please note that often NA regulation in these types of Objectives occurs via a rotating collar whose exact position is difficult to measure and reproduce across different Experiments.
	*/
	void resetNumericalApertureSetting();

	/*!
	* \brief Checks whether the NumericalApertureSetting attribute is present.
	*
	* In case the Numerical Aperture (NA) of this Objective is variable (i.e., as for example in case of Objectives that can be used with or without Cover Glass or Objectives that can be dipped in different media), this field capture the NA setting that was employed for Image Acquisition. NOTE: please note that often NA regulation in these types of Objectives occurs via a rotating collar whose exact position is difficult to measure and reproduce across different Experiments.
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasNumericalApertureSetting() const;

	/*!
	* \brief Returns the allowed values for this attribut.
	*
	* In case the Numerical Aperture (NA) of this Objective is variable (i.e., as for example in case of Objectives that can be used with or without Cover Glass or Objectives that can be dipped in different media), this field capture the NA setting that was employed for Image Acquisition. NOTE: please note that often NA regulation in these types of Objectives occurs via a rotating collar whose exact position is difficult to measure and reproduce across different Experiments.
	*
	* \return The list of allowed values
	*/
	static const std::set<std::string>& getNumericalApertureSettingAllowedValues();

	/*!
	* \brief Sets the value of the MeasuredRefractiveIndex attribute.
	*
	* The field records the Temperature dependent measured Refractive Index of the Immersion Liquid (or Dipping Medium) utilized in this case.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setMeasuredRefractiveIndex(const float& value, bool validate = true);

	/*!
	* \brief Returns the value of the MeasuredRefractiveIndex attribute.
	*
	* The field records the Temperature dependent measured Refractive Index of the Immersion Liquid (or Dipping Medium) utilized in this case.
	*
	* \return The value of the attribute
	*/
	float getMeasuredRefractiveIndex() const;

	/*!
	* \brief Resets the MeasuredRefractiveIndex attribute to an unset state.
	*
	* The field records the Temperature dependent measured Refractive Index of the Immersion Liquid (or Dipping Medium) utilized in this case.
	*/
	void resetMeasuredRefractiveIndex();

	/*!
	* \brief Checks whether the MeasuredRefractiveIndex attribute is present.
	*
	* The field records the Temperature dependent measured Refractive Index of the Immersion Liquid (or Dipping Medium) utilized in this case.
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasMeasuredRefractiveIndex() const;

	/*!
	* \brief Sets the value of the Temperature attribute.
	*
	* This field captures the Temperature of the Objective if different from the ImagingEnvironment/Temperature.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setTemperature(const float& value, bool validate = true);

	/*!
	* \brief Returns the value of the Temperature attribute.
	*
	* This field captures the Temperature of the Objective if different from the ImagingEnvironment/Temperature.
	*
	* \return The value of the attribute
	*/
	float getTemperature() const;

	/*!
	* \brief Resets the Temperature attribute to an unset state.
	*
	* This field captures the Temperature of the Objective if different from the ImagingEnvironment/Temperature.
	*/
	void resetTemperature();

	/*!
	* \brief Checks whether the Temperature attribute is present.
	*
	* This field captures the Temperature of the Objective if different from the ImagingEnvironment/Temperature.
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasTemperature() const;

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

	/*!
	* \brief Returns the value of the TemperatureUnit attribute.
	*
	* No description available in the XSD standard.
	*
	* \return The value of the attribute
	*/
	UnitsTemperature_TypePtr getTemperatureUnit() const;

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

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

	/*!
	* \brief Sets the value of the IrisAperture attribute.
	*
	* This field records the aperture of the Iris diaphragm, which determines the size of the objective rear aperture yielding a variable numerical aperture range between 0.5 and the objective's upper limit.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setIrisAperture(const float& value, bool validate = true);

	/*!
	* \brief Returns the value of the IrisAperture attribute.
	*
	* This field records the aperture of the Iris diaphragm, which determines the size of the objective rear aperture yielding a variable numerical aperture range between 0.5 and the objective's upper limit.
	*
	* \return The value of the attribute
	*/
	float getIrisAperture() const;

	/*!
	* \brief Resets the IrisAperture attribute to an unset state.
	*
	* This field records the aperture of the Iris diaphragm, which determines the size of the objective rear aperture yielding a variable numerical aperture range between 0.5 and the objective's upper limit.
	*/
	void resetIrisAperture();

	/*!
	* \brief Checks whether the IrisAperture attribute is present.
	*
	* This field records the aperture of the Iris diaphragm, which determines the size of the objective rear aperture yielding a variable numerical aperture range between 0.5 and the objective's upper limit.
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasIrisAperture() const;

	/*!
	* \brief Sets the value of the ImmersionLiquid element.
	*
	* 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 setImmersionLiquid(const Inscoper::NBO::ImmersionLiquidPtr& value, bool validate = true);

	/*!
	* \brief Returns the value of the ImmersionLiquid element.
	*
	* No description available in the XSD standard.
	*
	* \return The value of the element
	*/
	Inscoper::NBO::ImmersionLiquidPtr getImmersionLiquid() const;

	/*!
	* \brief Resets the ImmersionLiquid element to an unset state.
	*
	* No description available in the XSD standard.
	*/
	void resetImmersionLiquid();

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


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

	ObjectiveID_TypePtr ID = nullptr; // Required attribute
    std::optional<std::string> CorrectionCollarPosition; // Optional attribute
    static const std::set<std::string> CorrectionCollarPositionAllowedValues;
    std::optional<std::string> NumericalApertureSetting; // Optional attribute
    static const std::set<std::string> NumericalApertureSettingAllowedValues;
    std::optional<float> MeasuredRefractiveIndex; // Optional attribute
    std::optional<float> Temperature; // Optional attribute
	UnitsTemperature_TypePtr TemperatureUnit = nullptr; // Optional attribute
    std::optional<float> IrisAperture; // Optional attribute
    Inscoper::NBO::ImmersionLiquidPtr ImmersionLiquid = nullptr;
};

/*! Shared pointer for ObjectiveSettings*/
typedef std::shared_ptr<ObjectiveSettings> ObjectiveSettingsPtr;

} // namespace Inscoper::NBO

#endif // OBJECTIVESETTINGS_HPP_INCLUDED