#ifndef MICROSCOPETUBE_HPP_INCLUDED
#define MICROSCOPETUBE_HPP_INCLUDED

#include <iostream>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <vector>
#include <NBO/NBO/MicroscopeTubeType_Type.h>
#include <NBO/NBO/OpticalAssembly_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 MicroscopeTube.
*
* Illumination Tubes are Lens systems, which might be embedded within the Microscope Stand and therefore not immediately accessible. They are essential for infinity-correction and should be regarded as integral parts of the Objective Lens System when magnification and correction are considered.
*/
class NBO_EXPORT MicroscopeTube : public OpticalAssembly_Type {

public:
	
	MicroscopeTube();
	~MicroscopeTube();

	/*!
	* \brief Cast a NBOBaseClass to a MicroscopeTube.
	*
	* \param base The base class to cast
	* \return The casted element, or nullptr if the cast fails
	*/
	static std::shared_ptr<MicroscopeTube> 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 captures the category of this Tube.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setType(const Inscoper::NBO::MicroscopeTubeType_TypePtr& value, bool validate = true);

	/*!
	* \brief Returns the value of the Type attribute.
	*
	* This field captures the category of this Tube.
	*
	* \return The value of the attribute
	*/
	MicroscopeTubeType_TypePtr getType() const;

	/*!
	* \brief Resets the Type attribute to an unset state.
	*
	* This field captures the category of this Tube.
	*/
	void resetType();

	/*!
	* \brief Checks whether the optional Type attribute is present.
	*
	* This field captures the category of this Tube.
	*
	* \return true if the optional attribute has been set, false otherwise
	*/
	bool hasType() const;

	/*!
	* \brief Sets the value of the MechanicalLength attribute.
	*
	* For Objectives corrected for a finite primary Image distance, this is the length of the Tube in its simplest form, and it corresponds to the distance in air between the Objective and the Camera port. It commonly has a value of 160 mm (ISO 9345-1). For infinity-corrected objectives, the mechanical tube length is hypothetically considered to be infinite.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setMechanicalLength(const float& value, bool validate = true);

	/*!
	* \brief Returns the value of the MechanicalLength attribute.
	*
	* For Objectives corrected for a finite primary Image distance, this is the length of the Tube in its simplest form, and it corresponds to the distance in air between the Objective and the Camera port. It commonly has a value of 160 mm (ISO 9345-1). For infinity-corrected objectives, the mechanical tube length is hypothetically considered to be infinite.
	*
	* \return The value of the attribute
	*/
	float getMechanicalLength() const;

	/*!
	* \brief Resets the MechanicalLength attribute to an unset state.
	*
	* For Objectives corrected for a finite primary Image distance, this is the length of the Tube in its simplest form, and it corresponds to the distance in air between the Objective and the Camera port. It commonly has a value of 160 mm (ISO 9345-1). For infinity-corrected objectives, the mechanical tube length is hypothetically considered to be infinite.
	*/
	void resetMechanicalLength();

	/*!
	* \brief Checks whether the MechanicalLength attribute is present.
	*
	* For Objectives corrected for a finite primary Image distance, this is the length of the Tube in its simplest form, and it corresponds to the distance in air between the Objective and the Camera port. It commonly has a value of 160 mm (ISO 9345-1). For infinity-corrected objectives, the mechanical tube length is hypothetically considered to be infinite.
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasMechanicalLength() const;

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

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

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

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

	/*!
	* \brief Sets the value of the OpticalLength attribute.
	*
	* This is the distance between the back focal Plane of the Objective and the primary Image Plane. This distance is relevant only when using finite primary Image distance Objectives.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setOpticalLength(const float& value, bool validate = true);

	/*!
	* \brief Returns the value of the OpticalLength attribute.
	*
	* This is the distance between the back focal Plane of the Objective and the primary Image Plane. This distance is relevant only when using finite primary Image distance Objectives.
	*
	* \return The value of the attribute
	*/
	float getOpticalLength() const;

	/*!
	* \brief Resets the OpticalLength attribute to an unset state.
	*
	* This is the distance between the back focal Plane of the Objective and the primary Image Plane. This distance is relevant only when using finite primary Image distance Objectives.
	*/
	void resetOpticalLength();

	/*!
	* \brief Checks whether the OpticalLength attribute is present.
	*
	* This is the distance between the back focal Plane of the Objective and the primary Image Plane. This distance is relevant only when using finite primary Image distance Objectives.
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasOpticalLength() const;

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

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

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

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

	/*!
	* \brief Sets the value of the Factor attribute.
	*
	* Factor (q) by which the lateral Magnification at the primary Image is changed by an intermediate Lens or Lens System inserted between the Objective and the primary Image.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setFactor(const float& value, bool validate = true);

	/*!
	* \brief Returns the value of the Factor attribute.
	*
	* Factor (q) by which the lateral Magnification at the primary Image is changed by an intermediate Lens or Lens System inserted between the Objective and the primary Image.
	*
	* \return The value of the attribute
	*/
	float getFactor() const;

	/*!
	* \brief Resets the Factor attribute to an unset state.
	*
	* Factor (q) by which the lateral Magnification at the primary Image is changed by an intermediate Lens or Lens System inserted between the Objective and the primary Image.
	*/
	void resetFactor();

	/*!
	* \brief Checks whether the Factor attribute is present.
	*
	* Factor (q) by which the lateral Magnification at the primary Image is changed by an intermediate Lens or Lens System inserted between the Objective and the primary Image.
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasFactor() const;


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

	MicroscopeTubeType_TypePtr Type = nullptr; // Required attribute
    std::optional<float> MechanicalLength; // Optional attribute
	UnitsLength_TypePtr MechanicalLengthUnit = nullptr; // Optional attribute
    std::optional<float> OpticalLength; // Optional attribute
	UnitsLength_TypePtr OpticalLengthUnit = nullptr; // Optional attribute
    std::optional<float> Factor; // Optional attribute
};

/*! Shared pointer for MicroscopeTube*/
typedef std::shared_ptr<MicroscopeTube> MicroscopeTubePtr;

} // namespace Inscoper::NBO

#endif // MICROSCOPETUBE_HPP_INCLUDED