#ifndef PHOTOMULTIPLIERTUBE_HPP_INCLUDED
#define PHOTOMULTIPLIERTUBE_HPP_INCLUDED

#include <iostream>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <vector>
#include <NBO/NBO/MultianodeArrangement_Type.h>
#include <NBO/NBO/PercentFraction_Type.h>
#include <NBO/NBO/PointDetector_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 PhotoMultiplierTube.
*
* A Photomultiplier Tube (PMT) is a photoemissive device in which the absorption of a photon results in the emission of an electron and it is used for the detection of very weak signals. These Detectors work by amplifying the electrons generated by a photocathode exposed to a photon flux. The higher the supplied voltage (PMTVoltage setting), the greater the amplification of the current (PMTGain setting) and thus sensitivity, but also the higher the noise in the acquired image. The amplifier offset (PMTOffset setting) defines black level setting of the image. A PMT has no inherent spatial information of the image.
*/
class NBO_EXPORT PhotoMultiplierTube : public PointDetector_Type {

public:
	
	PhotoMultiplierTube();
	~PhotoMultiplierTube();

	/*!
	* \brief Cast a NBOBaseClass to a PhotoMultiplierTube.
	*
	* \param base The base class to cast
	* \return The casted element, or nullptr if the cast fails
	*/
	static std::shared_ptr<PhotoMultiplierTube> 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 CollectionEfficiency attribute.
	*
	* This field measures the probability that photoelectrons will land on the effective area of the first dynode of the photomultiplier stage. While there might be dispersion at the second and later dynodes, this tends to have less of an effect on the total collection efficiency as the number of emitted electrons increases greatly.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setCollectionEfficiency(const Inscoper::NBO::PercentFraction_TypePtr& value, bool validate = true);

	/*!
	* \brief Returns the value of the CollectionEfficiency attribute.
	*
	* This field measures the probability that photoelectrons will land on the effective area of the first dynode of the photomultiplier stage. While there might be dispersion at the second and later dynodes, this tends to have less of an effect on the total collection efficiency as the number of emitted electrons increases greatly.
	*
	* \return The value of the attribute
	*/
	PercentFraction_TypePtr getCollectionEfficiency() const;

	/*!
	* \brief Resets the CollectionEfficiency attribute to an unset state.
	*
	* This field measures the probability that photoelectrons will land on the effective area of the first dynode of the photomultiplier stage. While there might be dispersion at the second and later dynodes, this tends to have less of an effect on the total collection efficiency as the number of emitted electrons increases greatly.
	*/
	void resetCollectionEfficiency();

	/*!
	* \brief Checks whether the optional CollectionEfficiency attribute is present.
	*
	* This field measures the probability that photoelectrons will land on the effective area of the first dynode of the photomultiplier stage. While there might be dispersion at the second and later dynodes, this tends to have less of an effect on the total collection efficiency as the number of emitted electrons increases greatly.
	*
	* \return true if the optional attribute has been set, false otherwise
	*/
	bool hasCollectionEfficiency() const;

	/*!
	* \brief Sets the value of the Multianode attribute.
	*
	* This field records whether (True) or not (False) this is Photo Multiplier Tube is composed of an array of multiple 
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setMultianode(const bool& value, bool validate = true);

	/*!
	* \brief Returns the value of the Multianode attribute.
	*
	* This field records whether (True) or not (False) this is Photo Multiplier Tube is composed of an array of multiple 
	*
	* \return The value of the attribute
	*/
	bool getMultianode() const;

	/*!
	* \brief Resets the Multianode attribute to an unset state.
	*
	* This field records whether (True) or not (False) this is Photo Multiplier Tube is composed of an array of multiple 
	*/
	void resetMultianode();

	/*!
	* \brief Checks whether the Multianode attribute is present.
	*
	* This field records whether (True) or not (False) this is Photo Multiplier Tube is composed of an array of multiple 
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasMultianode() const;

	/*!
	* \brief Sets the value of the MultianodeChannelNr attribute.
	*
	* In case this Detector is a Multianode composed of an array of multiple Photomultiplier Tubes, this field records the number of Channels it consists of.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setMultianodeChannelNr(const long long& value, bool validate = true);

	/*!
	* \brief Returns the value of the MultianodeChannelNr attribute.
	*
	* In case this Detector is a Multianode composed of an array of multiple Photomultiplier Tubes, this field records the number of Channels it consists of.
	*
	* \return The value of the attribute
	*/
	long long getMultianodeChannelNr() const;

	/*!
	* \brief Resets the MultianodeChannelNr attribute to an unset state.
	*
	* In case this Detector is a Multianode composed of an array of multiple Photomultiplier Tubes, this field records the number of Channels it consists of.
	*/
	void resetMultianodeChannelNr();

	/*!
	* \brief Checks whether the MultianodeChannelNr attribute is present.
	*
	* In case this Detector is a Multianode composed of an array of multiple Photomultiplier Tubes, this field records the number of Channels it consists of.
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasMultianodeChannelNr() const;

	/*!
	* \brief Sets the value of the MultianodeArrangement attribute.
	*
	* In case this Detector is a Multianode composed of an array of multiple Photomultiplier Tubes, this field records the arrangement of the individual Photomultiplier Tubes.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setMultianodeArrangement(const Inscoper::NBO::MultianodeArrangement_TypePtr& value, bool validate = true);

	/*!
	* \brief Returns the value of the MultianodeArrangement attribute.
	*
	* In case this Detector is a Multianode composed of an array of multiple Photomultiplier Tubes, this field records the arrangement of the individual Photomultiplier Tubes.
	*
	* \return The value of the attribute
	*/
	MultianodeArrangement_TypePtr getMultianodeArrangement() const;

	/*!
	* \brief Resets the MultianodeArrangement attribute to an unset state.
	*
	* In case this Detector is a Multianode composed of an array of multiple Photomultiplier Tubes, this field records the arrangement of the individual Photomultiplier Tubes.
	*/
	void resetMultianodeArrangement();

	/*!
	* \brief Checks whether the optional MultianodeArrangement attribute is present.
	*
	* In case this Detector is a Multianode composed of an array of multiple Photomultiplier Tubes, this field records the arrangement of the individual Photomultiplier Tubes.
	*
	* \return true if the optional attribute has been set, false otherwise
	*/
	bool hasMultianodeArrangement() const;

	/*!
	* \brief Sets the value of the HeadOn attribute.
	*
	* This is True if the Photocathode is positioned at either end of the vacuum tube. This is False if the photocathode element is located on the side of the vacuum tube (side-on geometry).
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setHeadOn(const bool& value, bool validate = true);

	/*!
	* \brief Returns the value of the HeadOn attribute.
	*
	* This is True if the Photocathode is positioned at either end of the vacuum tube. This is False if the photocathode element is located on the side of the vacuum tube (side-on geometry).
	*
	* \return The value of the attribute
	*/
	bool getHeadOn() const;

	/*!
	* \brief Resets the HeadOn attribute to an unset state.
	*
	* This is True if the Photocathode is positioned at either end of the vacuum tube. This is False if the photocathode element is located on the side of the vacuum tube (side-on geometry).
	*/
	void resetHeadOn();

	/*!
	* \brief Checks whether the HeadOn attribute is present.
	*
	* This is True if the Photocathode is positioned at either end of the vacuum tube. This is False if the photocathode element is located on the side of the vacuum tube (side-on geometry).
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasHeadOn() const;


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

	PercentFraction_TypePtr CollectionEfficiency = nullptr; // Required attribute
    std::optional<bool> Multianode; // Required attribute
    std::optional<long long> MultianodeChannelNr; // Optional attribute
	MultianodeArrangement_TypePtr MultianodeArrangement = nullptr; // Optional attribute
    std::optional<bool> HeadOn; // Optional attribute
};

/*! Shared pointer for PhotoMultiplierTube*/
typedef std::shared_ptr<PhotoMultiplierTube> PhotoMultiplierTubePtr;

} // namespace Inscoper::NBO

#endif // PHOTOMULTIPLIERTUBE_HPP_INCLUDED