#ifndef IMMERSIONLIQUID_HPP_INCLUDED
#define IMMERSIONLIQUID_HPP_INCLUDED

#include <iostream>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <vector>
#include <NBO/NBO/ImmersionLiquidType_Type.h>
#include <NBO/NBO/LSID_Type.h>
#include <NBO/NBO/ManufacturerSpec_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 ImmersionLiquid.
*
* This element refers to the Immersion Liquid that was used with this Objective during the Acquisition of this Image. According to ISO 10934-1:2002, an Immersion Liquid is a liquid (commonly immersion oil, water, glycerol or any media in which the Specimen is submerged during acquisition in case a Cover Glass is not used) specified as suitable for use in the space between the front of an Objective lens and the Cover Glass or the Object itself (i.e., such as is the case for Dipping Objectives). Refer to ISO 8036-1 for more details on Immersion Oil. Please NOTE: Because the Immersion Liquid is considered in the computing of corrections to be part of the lens, its refractive index and dispersion (or Abbe number) are critical. Also please NOTE: In case a Cover Glass is not used during Acquisition the Immersion Liquid is most often referred to as Dipping Medium. Examples of Dipping Media include, water-based solutions (biological buffers, culture media, other water-based solutions) and organic-based [FocusClear (CLARITY); CUBIC-1, CUBIC-2, CUBIC-R1, CUBIC-R2; 2,2-thiodiethanol (TDE); ethyl cinnamate; Benzyl Benzoate and BB-PEG (PEGASOS); Benzyl Alcohol, Benzyl Benzoate (BABB); dibenzyl ether (DBE); Ethanol].
*/
class NBO_EXPORT ImmersionLiquid : public ManufacturerSpec_Type {

public:
	
	ImmersionLiquid();
	~ImmersionLiquid();

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

	/*!
	* \brief Returns the value of the ID attribute.
	*
	* A Unique Identifier for this component.
	*
	* \return The value of the attribute
	*/
	LSID_TypePtr getID() const;

	/*!
	* \brief Resets the ID attribute to an unset state.
	*
	* A Unique Identifier for this component.
	*/
	void resetID();

	/*!
	* \brief Checks whether the optional ID attribute is present.
	*
	* A Unique Identifier for this component.
	*
	* \return true if the optional attribute has been set, false otherwise
	*/
	bool hasID() const;

	/*!
	* \brief Sets the value of the Type attribute.
	*
	* This field records the general category to which this Immersion Liquid belongs.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setType(const Inscoper::NBO::ImmersionLiquidType_TypePtr& value, bool validate = true);

	/*!
	* \brief Returns the value of the Type attribute.
	*
	* This field records the general category to which this Immersion Liquid belongs.
	*
	* \return The value of the attribute
	*/
	ImmersionLiquidType_TypePtr getType() const;

	/*!
	* \brief Resets the Type attribute to an unset state.
	*
	* This field records the general category to which this Immersion Liquid belongs.
	*/
	void resetType();

	/*!
	* \brief Checks whether the optional Type attribute is present.
	*
	* This field records the general category to which this Immersion Liquid belongs.
	*
	* \return true if the optional attribute has been set, false otherwise
	*/
	bool hasType() const;

	/*!
	* \brief Sets the value of the RefractiveIndex attribute.
	*
	* This field reocrds the nominal Refractive Index of this Immersion Liquid, as specified by the Manufacturer.
	*
	* \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 reocrds the nominal Refractive Index of this Immersion Liquid, as specified by the Manufacturer.
	*
	* \return The value of the attribute
	*/
	float getRefractiveIndex() const;

	/*!
	* \brief Resets the RefractiveIndex attribute to an unset state.
	*
	* This field reocrds the nominal Refractive Index of this Immersion Liquid, as specified by the Manufacturer.
	*/
	void resetRefractiveIndex();

	/*!
	* \brief Checks whether the RefractiveIndex attribute is present.
	*
	* This field reocrds the nominal Refractive Index of this Immersion Liquid, as specified by the Manufacturer.
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasRefractiveIndex() const;

	/*!
	* \brief Sets the value of the Viscosity attribute.
	*
	* This field records the nominal Viscosity of this Immersion Liquid as specified by the Manufacturer.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setViscosity(const float& value, bool validate = true);

	/*!
	* \brief Returns the value of the Viscosity attribute.
	*
	* This field records the nominal Viscosity of this Immersion Liquid as specified by the Manufacturer.
	*
	* \return The value of the attribute
	*/
	float getViscosity() const;

	/*!
	* \brief Resets the Viscosity attribute to an unset state.
	*
	* This field records the nominal Viscosity of this Immersion Liquid as specified by the Manufacturer.
	*/
	void resetViscosity();

	/*!
	* \brief Checks whether the Viscosity attribute is present.
	*
	* This field records the nominal Viscosity of this Immersion Liquid as specified by the Manufacturer.
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasViscosity() const;


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

	LSID_TypePtr ID = nullptr; // Required attribute
	ImmersionLiquidType_TypePtr Type = nullptr; // Optional attribute
    std::optional<float> RefractiveIndex; // Optional attribute
    std::optional<float> Viscosity; // Optional attribute
};

/*! Shared pointer for ImmersionLiquid*/
typedef std::shared_ptr<ImmersionLiquid> ImmersionLiquidPtr;

} // namespace Inscoper::NBO

#endif // IMMERSIONLIQUID_HPP_INCLUDED