#ifndef OME_HPP_INCLUDED
#define OME_HPP_INCLUDED

#include <iostream>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <vector>
#include <NBO/NBO/OME_Choice.h>
#include <NBO/NBO/Rights.h>
#include <NBO/NBO/UniversallyUniqueIdentifier_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 OME.
*
* The OME element is a container for all information objects accessible by OME. These information objects include descriptions of the imaging experiments and the people who perform them, descriptions of the microscope, the resulting images and how they were acquired, the analyses performed on those images, and the analysis results themselves. An OME file may contain any or all of this information. With the creation of the Metadata Only Companion OME-XML and Binary Only OME-TIFF files the top level OME node has changed slightly. It can EITHER: Contain all the previously expected elements OR: Contain a single BinaryOnly element that points at its Metadata Only Companion OME-XML file. 
*/
class NBO_EXPORT OME : public NBOBaseClass {

public:
	
	OME();
	~OME();

	/*!
	* \brief Cast a NBOBaseClass to a OME.
	*
	* \param base The base class to cast
	* \return The casted element, or nullptr if the cast fails
	*/
	static std::shared_ptr<OME> 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 UUID attribute.
	*
	* This unique identifier is used to keep track of multi part files. It allows the links between files to survive renaming. While OPTIONAL in the general case this is REQUIRED in a MetadataOnly Companion to a collection of BinaryOnly files. 
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setUUID(const Inscoper::NBO::UniversallyUniqueIdentifier_TypePtr& value, bool validate = true);

	/*!
	* \brief Returns the value of the UUID attribute.
	*
	* This unique identifier is used to keep track of multi part files. It allows the links between files to survive renaming. While OPTIONAL in the general case this is REQUIRED in a MetadataOnly Companion to a collection of BinaryOnly files. 
	*
	* \return The value of the attribute
	*/
	UniversallyUniqueIdentifier_TypePtr getUUID() const;

	/*!
	* \brief Resets the UUID attribute to an unset state.
	*
	* This unique identifier is used to keep track of multi part files. It allows the links between files to survive renaming. While OPTIONAL in the general case this is REQUIRED in a MetadataOnly Companion to a collection of BinaryOnly files. 
	*/
	void resetUUID();

	/*!
	* \brief Checks whether the optional UUID attribute is present.
	*
	* This unique identifier is used to keep track of multi part files. It allows the links between files to survive renaming. While OPTIONAL in the general case this is REQUIRED in a MetadataOnly Companion to a collection of BinaryOnly files. 
	*
	* \return true if the optional attribute has been set, false otherwise
	*/
	bool hasUUID() const;

	/*!
	* \brief Sets the value of the Creator attribute.
	*
	* This is the name of the creating application of the OME-XML and preferably its full version. e.g "CompanyName, SoftwareName, V2.6.3456" This is optional but we hope it will be set by applications writing out OME-XML from scratch. 
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setCreator(const std::string& value, bool validate = true);

	/*!
	* \brief Returns the value of the Creator attribute.
	*
	* This is the name of the creating application of the OME-XML and preferably its full version. e.g "CompanyName, SoftwareName, V2.6.3456" This is optional but we hope it will be set by applications writing out OME-XML from scratch. 
	*
	* \return The value of the attribute
	*/
	std::string getCreator() const;

	/*!
	* \brief Resets the Creator attribute to an unset state.
	*
	* This is the name of the creating application of the OME-XML and preferably its full version. e.g "CompanyName, SoftwareName, V2.6.3456" This is optional but we hope it will be set by applications writing out OME-XML from scratch. 
	*/
	void resetCreator();

	/*!
	* \brief Checks whether the Creator attribute is present.
	*
	* This is the name of the creating application of the OME-XML and preferably its full version. e.g "CompanyName, SoftwareName, V2.6.3456" This is optional but we hope it will be set by applications writing out OME-XML from scratch. 
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasCreator() const;

	/*!
	* \brief Returns the allowed values for this attribut.
	*
	* This is the name of the creating application of the OME-XML and preferably its full version. e.g "CompanyName, SoftwareName, V2.6.3456" This is optional but we hope it will be set by applications writing out OME-XML from scratch. 
	*
	* \return The list of allowed values
	*/
	static const std::set<std::string>& getCreatorAllowedValues();

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

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

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

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

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

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

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


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

	UniversallyUniqueIdentifier_TypePtr UUID = nullptr; // Optional attribute
    std::optional<std::string> Creator; // Optional attribute
    static const std::set<std::string> CreatorAllowedValues;
    Inscoper::NBO::RightsPtr Rights = nullptr;
    Inscoper::NBO::OME_ChoicePtr ome_choice = nullptr;
};

/*! Shared pointer for OME*/
typedef std::shared_ptr<OME> OMEPtr;

} // namespace Inscoper::NBO

#endif // OME_HPP_INCLUDED