#ifndef ADDITIONALDIMENSIONMAP_HPP_INCLUDED
#define ADDITIONALDIMENSIONMAP_HPP_INCLUDED

#include <iostream>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <vector>
#include <NBO/NBO/AdditionalDimensionType_Type.h>
#include <NBO/NBO/AnnotationRef.h>
#include <NBO/NBO/Denomination_Type.h>
#include <NBO/NBO/Description.h>
#include <NBO/NBO/LSID_Type.h>
#include <NBO/NBO/TheAdditionalDimension.h>
#include <NBO/NBO/ENBOType.h>
#include <NBO/NBOGlobal.h>
#include <NBO/Shared/Base/NBOBaseClass.h>


namespace Inscoper::NBO {

/*!
* \brief Represents the XML element AdditionalDimensionMap.
*
* This map defines any additional dimension beyond the canonical 5 dimensions XYZCT. It contains a number of elements for each Plane of data referring to this Additional Dimension.
*/
class NBO_EXPORT AdditionalDimensionMap : public NBOBaseClass {

public:
	
	AdditionalDimensionMap();
	~AdditionalDimensionMap();

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

	/*!
	* \brief Returns the value of the Name attribute.
	*
	* A user assigned Name for this component.
	*
	* \return The value of the attribute
	*/
	Denomination_TypePtr getName() const;

	/*!
	* \brief Resets the Name attribute to an unset state.
	*
	* A user assigned Name for this component.
	*/
	void resetName();

	/*!
	* \brief Checks whether the optional Name attribute is present.
	*
	* A user assigned Name for this component.
	*
	* \return true if the optional attribute has been set, false otherwise
	*/
	bool hasName() const;

	/*!
	* \brief Sets the value of the Size attribute.
	*
	* This field captures the number of sample points recorded along this dimension.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setSize(const long long& value, bool validate = true);

	/*!
	* \brief Returns the value of the Size attribute.
	*
	* This field captures the number of sample points recorded along this dimension.
	*
	* \return The value of the attribute
	*/
	long long getSize() const;

	/*!
	* \brief Resets the Size attribute to an unset state.
	*
	* This field captures the number of sample points recorded along this dimension.
	*/
	void resetSize();

	/*!
	* \brief Checks whether the Size attribute is present.
	*
	* This field captures the number of sample points recorded along this dimension.
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasSize() const;

	/*!
	* \brief Sets the value of the Type attribute.
	*
	* This field describes the Type of this Additional Dimension.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setType(const Inscoper::NBO::AdditionalDimensionType_TypePtr& value, bool validate = true);

	/*!
	* \brief Returns the value of the Type attribute.
	*
	* This field describes the Type of this Additional Dimension.
	*
	* \return The value of the attribute
	*/
	AdditionalDimensionType_TypePtr getType() const;

	/*!
	* \brief Resets the Type attribute to an unset state.
	*
	* This field describes the Type of this Additional Dimension.
	*/
	void resetType();

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

	/*!
	* \brief Sets the value of the TypeDescription attribute.
	*
	* This is a description of the Type used to indicate to an application or user how the data should be interpreted.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setTypeDescription(const std::string& value, bool validate = true);

	/*!
	* \brief Returns the value of the TypeDescription attribute.
	*
	* This is a description of the Type used to indicate to an application or user how the data should be interpreted.
	*
	* \return The value of the attribute
	*/
	std::string getTypeDescription() const;

	/*!
	* \brief Resets the TypeDescription attribute to an unset state.
	*
	* This is a description of the Type used to indicate to an application or user how the data should be interpreted.
	*/
	void resetTypeDescription();

	/*!
	* \brief Checks whether the TypeDescription attribute is present.
	*
	* This is a description of the Type used to indicate to an application or user how the data should be interpreted.
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasTypeDescription() const;

	/*!
	* \brief Returns the allowed values for this attribut.
	*
	* This is a description of the Type used to indicate to an application or user how the data should be interpreted.
	*
	* \return The list of allowed values
	*/
	static const std::set<std::string>& getTypeDescriptionAllowedValues();

	/*!
	* \brief Sets the value of the Order attribute.
	*
	* This field describes the order in which the individual Planes of data referring to this dimension are interleaved in the Image past the canonical 5 dimension XYZCT. The number should be zero based, e.g., 0, 1, 2 etc.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setOrder(const long long& value, bool validate = true);

	/*!
	* \brief Returns the value of the Order attribute.
	*
	* This field describes the order in which the individual Planes of data referring to this dimension are interleaved in the Image past the canonical 5 dimension XYZCT. The number should be zero based, e.g., 0, 1, 2 etc.
	*
	* \return The value of the attribute
	*/
	long long getOrder() const;

	/*!
	* \brief Resets the Order attribute to an unset state.
	*
	* This field describes the order in which the individual Planes of data referring to this dimension are interleaved in the Image past the canonical 5 dimension XYZCT. The number should be zero based, e.g., 0, 1, 2 etc.
	*/
	void resetOrder();

	/*!
	* \brief Checks whether the Order attribute is present.
	*
	* This field describes the order in which the individual Planes of data referring to this dimension are interleaved in the Image past the canonical 5 dimension XYZCT. The number should be zero based, e.g., 0, 1, 2 etc.
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasOrder() const;

	/*!
	* \brief Sets the value of the PresetStepIncrement attribute.
	*
	* This field records the preset size of Step Increment between Planes of data along this dimension. The Increment is numbered from 0, with default value of 1. Setting a value for this attribute to -1 indicates non-uniform sampling along this Additional Dimension. In this case the actual Step Increment value associated with each Plane along this Additional Dimension will have to be stored in TheIncrementStamp attribute of TheAdditionalDimension.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setPresetStepIncrement(const float& value, bool validate = true);

	/*!
	* \brief Returns the value of the PresetStepIncrement attribute.
	*
	* This field records the preset size of Step Increment between Planes of data along this dimension. The Increment is numbered from 0, with default value of 1. Setting a value for this attribute to -1 indicates non-uniform sampling along this Additional Dimension. In this case the actual Step Increment value associated with each Plane along this Additional Dimension will have to be stored in TheIncrementStamp attribute of TheAdditionalDimension.
	*
	* \return The value of the attribute
	*/
	float getPresetStepIncrement() const;

	/*!
	* \brief Resets the PresetStepIncrement attribute to an unset state.
	*
	* This field records the preset size of Step Increment between Planes of data along this dimension. The Increment is numbered from 0, with default value of 1. Setting a value for this attribute to -1 indicates non-uniform sampling along this Additional Dimension. In this case the actual Step Increment value associated with each Plane along this Additional Dimension will have to be stored in TheIncrementStamp attribute of TheAdditionalDimension.
	*/
	void resetPresetStepIncrement();

	/*!
	* \brief Checks whether the PresetStepIncrement attribute is present.
	*
	* This field records the preset size of Step Increment between Planes of data along this dimension. The Increment is numbered from 0, with default value of 1. Setting a value for this attribute to -1 indicates non-uniform sampling along this Additional Dimension. In this case the actual Step Increment value associated with each Plane along this Additional Dimension will have to be stored in TheIncrementStamp attribute of TheAdditionalDimension.
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasPresetStepIncrement() const;

	/*!
	* \brief Sets the value of the Unit attribute.
	*
	* This field records the Unit used for the metric recorded along this dimension
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setUnit(const std::string& value, bool validate = true);

	/*!
	* \brief Returns the value of the Unit attribute.
	*
	* This field records the Unit used for the metric recorded along this dimension
	*
	* \return The value of the attribute
	*/
	std::string getUnit() const;

	/*!
	* \brief Resets the Unit attribute to an unset state.
	*
	* This field records the Unit used for the metric recorded along this dimension
	*/
	void resetUnit();

	/*!
	* \brief Checks whether the Unit attribute is present.
	*
	* This field records the Unit used for the metric recorded along this dimension
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasUnit() const;

	/*!
	* \brief Returns the allowed values for this attribut.
	*
	* This field records the Unit used for the metric recorded along this dimension
	*
	* \return The list of allowed values
	*/
	static const std::set<std::string>& getUnitAllowedValues();

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

	/*!
	* \brief Returns the value of the TheAdditionalDimension element.
	*
	* No description available in the XSD standard.
	*
	* \return The value of the element
	*/
	Inscoper::NBO::TheAdditionalDimensionPtr getTheAdditionalDimension() const
;
	/*!
	* \brief Resets the TheAdditionalDimension element to an unset state.
	*
	* No description available in the XSD standard.
	*/
	void resetTheAdditionalDimension();

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

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

	/*!
	* \brief Returns the value of the Description element.
	*
	* No description available in the XSD standard.
	*
	* \return The value of the element
	*/
	Inscoper::NBO::DescriptionPtr getDescription() const
;
	/*!
	* \brief Resets the Description element to an unset state.
	*
	* No description available in the XSD standard.
	*/
	void resetDescription();

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

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

	/*!
	* \brief Returns the value of the AnnotationRef element.
	*
	* No description available in the XSD standard.
	*
	* \return The value of the element
	*/
	Inscoper::NBO::AnnotationRefPtr getAnnotationRef() const
;
	/*!
	* \brief Resets the AnnotationRef element to an unset state.
	*
	* No description available in the XSD standard.
	*/
	void resetAnnotationRef();

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


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

	LSID_TypePtr ID = nullptr; // Required attribute
	Denomination_TypePtr Name = nullptr; // Optional attribute
    std::optional<long long> Size; // Required attribute
	AdditionalDimensionType_TypePtr Type = nullptr; // Required attribute
    std::optional<std::string> TypeDescription; // Optional attribute
    static const std::set<std::string> TypeDescriptionAllowedValues;
    std::optional<long long> Order; // Required attribute
    std::optional<float> PresetStepIncrement; // Optional attribute
    std::optional<std::string> Unit; // Required attribute
    static const std::set<std::string> UnitAllowedValues;
    Inscoper::NBO::TheAdditionalDimensionPtr TheAdditionalDimension = nullptr;
    Inscoper::NBO::DescriptionPtr Description = nullptr;
    Inscoper::NBO::AnnotationRefPtr AnnotationRef = nullptr;
};

/*! Shared pointer for AdditionalDimensionMap*/
typedef std::shared_ptr<AdditionalDimensionMap> AdditionalDimensionMapPtr;

} // namespace Inscoper::NBO

#endif // ADDITIONALDIMENSIONMAP_HPP_INCLUDED