#ifndef DETECTORSETTINGS_TYPE_HPP_INCLUDED
#define DETECTORSETTINGS_TYPE_HPP_INCLUDED

#include <iostream>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <vector>
#include <NBO/NBO/DetectorID_Type.h>
#include <NBO/NBO/DetectorOffsetMode_Type.h>
#include <NBO/NBO/DigitizerType_Type.h>
#include <NBO/NBO/Settings_Type.h>
#include <NBO/NBO/ENBOType.h>
#include <NBO/NBOGlobal.h>
#include <NBO/Shared/Base/NBOBaseClass.h>


namespace Inscoper::NBO {

/*!
* \brief Represents the XML complex type DetectorSettings.
*
* This element holds the Setting applied to the Detector used for the Acquisition of this Channel as well as a reference to the Detector (the ID attribute) in question.
*/
class NBO_EXPORT DetectorSettings_Type : public Settings_Type {

public:
	
	DetectorSettings_Type();
	~DetectorSettings_Type();

	/*!
	* \brief Cast a NBOBaseClass to a DetectorSettings_Type.
	*
	* \param base The base class to cast
	* \return The casted element, or nullptr if the cast fails
	*/
	static std::shared_ptr<DetectorSettings_Type> fromBase(NBOBaseClassPtr base);

	/*!
	* \brief Returns the class type name.
	*
	* \return The class type name
	*/
	virtual 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::DetectorID_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
	*/
	DetectorID_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 EffectiveBitDepth attribute.
	*
	* If selectable, this field reports the Effective Bit Depth that was used by the Detector's Analog to Digital Converter (ADC; also referred to as Digitizer) for the Acquisition of this Channel.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setEffectiveBitDepth(const Inscoper::NBO::DigitizerType_TypePtr& value, bool validate = true);

	/*!
	* \brief Returns the value of the EffectiveBitDepth attribute.
	*
	* If selectable, this field reports the Effective Bit Depth that was used by the Detector's Analog to Digital Converter (ADC; also referred to as Digitizer) for the Acquisition of this Channel.
	*
	* \return The value of the attribute
	*/
	DigitizerType_TypePtr getEffectiveBitDepth() const;

	/*!
	* \brief Resets the EffectiveBitDepth attribute to an unset state.
	*
	* If selectable, this field reports the Effective Bit Depth that was used by the Detector's Analog to Digital Converter (ADC; also referred to as Digitizer) for the Acquisition of this Channel.
	*/
	void resetEffectiveBitDepth();

	/*!
	* \brief Checks whether the optional EffectiveBitDepth attribute is present.
	*
	* If selectable, this field reports the Effective Bit Depth that was used by the Detector's Analog to Digital Converter (ADC; also referred to as Digitizer) for the Acquisition of this Channel.
	*
	* \return true if the optional attribute has been set, false otherwise
	*/
	bool hasEffectiveBitDepth() const;

	/*!
	* \brief Sets the value of the AnalogGain attribute.
	*
	* This field reports the Analog Gain (also known as Inherent Gain or simply as Gain) that was applied during the Acquisition of this Image. The Analog Gain is a property Inherent to the Detector and it specifies how many electrons correspond to 1 signal unit (photon) detected. Gain is reported in terms of electrons/ADU (analog-to-digital unit). A gain of 8 means that the Detector digitizes the light signal so that each ADU corresponds to 8 photoelectrons. NOTE: In the case of Point Detectors the value of Analog Gain can be set freely by the user. Conversely, in the case of Cameras, it is common for the Gain to be preset by the Manufacturer to minimize noise. In this case, either the Analog Gain cannot be changed or the user is given the choice of selecting between a few preset Analog Gains values upon Acquisition. Finally, several Cameras might have so-called Automatic Gain Control (AGC or AutoGain) that will automatically adjusts so the full range of the Analog-to-Digital Converter (ADC) is used. Unless you can turn off the AGC, the use of these Cameras are highly discouraged for quantitative work. 
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setAnalogGain(const float& value, bool validate = true);

	/*!
	* \brief Returns the value of the AnalogGain attribute.
	*
	* This field reports the Analog Gain (also known as Inherent Gain or simply as Gain) that was applied during the Acquisition of this Image. The Analog Gain is a property Inherent to the Detector and it specifies how many electrons correspond to 1 signal unit (photon) detected. Gain is reported in terms of electrons/ADU (analog-to-digital unit). A gain of 8 means that the Detector digitizes the light signal so that each ADU corresponds to 8 photoelectrons. NOTE: In the case of Point Detectors the value of Analog Gain can be set freely by the user. Conversely, in the case of Cameras, it is common for the Gain to be preset by the Manufacturer to minimize noise. In this case, either the Analog Gain cannot be changed or the user is given the choice of selecting between a few preset Analog Gains values upon Acquisition. Finally, several Cameras might have so-called Automatic Gain Control (AGC or AutoGain) that will automatically adjusts so the full range of the Analog-to-Digital Converter (ADC) is used. Unless you can turn off the AGC, the use of these Cameras are highly discouraged for quantitative work. 
	*
	* \return The value of the attribute
	*/
	float getAnalogGain() const;

	/*!
	* \brief Resets the AnalogGain attribute to an unset state.
	*
	* This field reports the Analog Gain (also known as Inherent Gain or simply as Gain) that was applied during the Acquisition of this Image. The Analog Gain is a property Inherent to the Detector and it specifies how many electrons correspond to 1 signal unit (photon) detected. Gain is reported in terms of electrons/ADU (analog-to-digital unit). A gain of 8 means that the Detector digitizes the light signal so that each ADU corresponds to 8 photoelectrons. NOTE: In the case of Point Detectors the value of Analog Gain can be set freely by the user. Conversely, in the case of Cameras, it is common for the Gain to be preset by the Manufacturer to minimize noise. In this case, either the Analog Gain cannot be changed or the user is given the choice of selecting between a few preset Analog Gains values upon Acquisition. Finally, several Cameras might have so-called Automatic Gain Control (AGC or AutoGain) that will automatically adjusts so the full range of the Analog-to-Digital Converter (ADC) is used. Unless you can turn off the AGC, the use of these Cameras are highly discouraged for quantitative work. 
	*/
	void resetAnalogGain();

	/*!
	* \brief Checks whether the AnalogGain attribute is present.
	*
	* This field reports the Analog Gain (also known as Inherent Gain or simply as Gain) that was applied during the Acquisition of this Image. The Analog Gain is a property Inherent to the Detector and it specifies how many electrons correspond to 1 signal unit (photon) detected. Gain is reported in terms of electrons/ADU (analog-to-digital unit). A gain of 8 means that the Detector digitizes the light signal so that each ADU corresponds to 8 photoelectrons. NOTE: In the case of Point Detectors the value of Analog Gain can be set freely by the user. Conversely, in the case of Cameras, it is common for the Gain to be preset by the Manufacturer to minimize noise. In this case, either the Analog Gain cannot be changed or the user is given the choice of selecting between a few preset Analog Gains values upon Acquisition. Finally, several Cameras might have so-called Automatic Gain Control (AGC or AutoGain) that will automatically adjusts so the full range of the Analog-to-Digital Converter (ADC) is used. Unless you can turn off the AGC, the use of these Cameras are highly discouraged for quantitative work. 
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasAnalogGain() const;

	/*!
	* \brief Sets the value of the AmplificationGain attribute.
	*
	* This field reports the Amplification Gain (i.e., electronic gain as apposed to the inherent Gain) that was set during the Acquisition of this Image. Amplification Gain in general measures of the ability of a Detector to add energy to the input light signal therefore increasing its power or amplitude. Higher Amplification Gain levels amplify the signal and result in greater brightness, contrast and background signal. Examples include: 1) the Electron Multiplication (EM) gain (as opposed to the inherent Analog Gain) for an EMCCD camera. 2) The Gain introduced by the Micro-Channel Plate in an Intensified CCD or CMOS camera. 3) The amplification of the electron current provided by a Photomultiplier Tube, and measured as the ratio of the input photoelectron current emitted by the photocatode and the current reaching the anode. 4) The signal amplification provided by an Avalache Photo Diode (APD).
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setAmplificationGain(const float& value, bool validate = true);

	/*!
	* \brief Returns the value of the AmplificationGain attribute.
	*
	* This field reports the Amplification Gain (i.e., electronic gain as apposed to the inherent Gain) that was set during the Acquisition of this Image. Amplification Gain in general measures of the ability of a Detector to add energy to the input light signal therefore increasing its power or amplitude. Higher Amplification Gain levels amplify the signal and result in greater brightness, contrast and background signal. Examples include: 1) the Electron Multiplication (EM) gain (as opposed to the inherent Analog Gain) for an EMCCD camera. 2) The Gain introduced by the Micro-Channel Plate in an Intensified CCD or CMOS camera. 3) The amplification of the electron current provided by a Photomultiplier Tube, and measured as the ratio of the input photoelectron current emitted by the photocatode and the current reaching the anode. 4) The signal amplification provided by an Avalache Photo Diode (APD).
	*
	* \return The value of the attribute
	*/
	float getAmplificationGain() const;

	/*!
	* \brief Resets the AmplificationGain attribute to an unset state.
	*
	* This field reports the Amplification Gain (i.e., electronic gain as apposed to the inherent Gain) that was set during the Acquisition of this Image. Amplification Gain in general measures of the ability of a Detector to add energy to the input light signal therefore increasing its power or amplitude. Higher Amplification Gain levels amplify the signal and result in greater brightness, contrast and background signal. Examples include: 1) the Electron Multiplication (EM) gain (as opposed to the inherent Analog Gain) for an EMCCD camera. 2) The Gain introduced by the Micro-Channel Plate in an Intensified CCD or CMOS camera. 3) The amplification of the electron current provided by a Photomultiplier Tube, and measured as the ratio of the input photoelectron current emitted by the photocatode and the current reaching the anode. 4) The signal amplification provided by an Avalache Photo Diode (APD).
	*/
	void resetAmplificationGain();

	/*!
	* \brief Checks whether the AmplificationGain attribute is present.
	*
	* This field reports the Amplification Gain (i.e., electronic gain as apposed to the inherent Gain) that was set during the Acquisition of this Image. Amplification Gain in general measures of the ability of a Detector to add energy to the input light signal therefore increasing its power or amplitude. Higher Amplification Gain levels amplify the signal and result in greater brightness, contrast and background signal. Examples include: 1) the Electron Multiplication (EM) gain (as opposed to the inherent Analog Gain) for an EMCCD camera. 2) The Gain introduced by the Micro-Channel Plate in an Intensified CCD or CMOS camera. 3) The amplification of the electron current provided by a Photomultiplier Tube, and measured as the ratio of the input photoelectron current emitted by the photocatode and the current reaching the anode. 4) The signal amplification provided by an Avalache Photo Diode (APD).
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasAmplificationGain() const;

	/*!
	* \brief Sets the value of the Offset attribute.
	*
	* If available, this field reports the actual Offset that was set for this Detector during the Acquisition of this Channel. Offset is an electronic baseline added to the output signal generated by the sensor to ensure that the resulting signal level always correspond to a positive number of counts. Offset defines the black level setting of the image and it should be adjusted so that the lowest signals are near the detection threshold. NOTE: Please note that most modern Cameras do not have the possibility of setting the Offset.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setOffset(const float& value, bool validate = true);

	/*!
	* \brief Returns the value of the Offset attribute.
	*
	* If available, this field reports the actual Offset that was set for this Detector during the Acquisition of this Channel. Offset is an electronic baseline added to the output signal generated by the sensor to ensure that the resulting signal level always correspond to a positive number of counts. Offset defines the black level setting of the image and it should be adjusted so that the lowest signals are near the detection threshold. NOTE: Please note that most modern Cameras do not have the possibility of setting the Offset.
	*
	* \return The value of the attribute
	*/
	float getOffset() const;

	/*!
	* \brief Resets the Offset attribute to an unset state.
	*
	* If available, this field reports the actual Offset that was set for this Detector during the Acquisition of this Channel. Offset is an electronic baseline added to the output signal generated by the sensor to ensure that the resulting signal level always correspond to a positive number of counts. Offset defines the black level setting of the image and it should be adjusted so that the lowest signals are near the detection threshold. NOTE: Please note that most modern Cameras do not have the possibility of setting the Offset.
	*/
	void resetOffset();

	/*!
	* \brief Checks whether the Offset attribute is present.
	*
	* If available, this field reports the actual Offset that was set for this Detector during the Acquisition of this Channel. Offset is an electronic baseline added to the output signal generated by the sensor to ensure that the resulting signal level always correspond to a positive number of counts. Offset defines the black level setting of the image and it should be adjusted so that the lowest signals are near the detection threshold. NOTE: Please note that most modern Cameras do not have the possibility of setting the Offset.
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasOffset() const;

	/*!
	* \brief Sets the value of the OffsetMode attribute.
	*
	* This field describes the way in which the Voltage Offset of the Detector is reported. It typically is expressed as an Arbitrary-units number, a Scaled percent (-100 to 100), or a a Voltage.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setOffsetMode(const Inscoper::NBO::DetectorOffsetMode_TypePtr& value, bool validate = true);

	/*!
	* \brief Returns the value of the OffsetMode attribute.
	*
	* This field describes the way in which the Voltage Offset of the Detector is reported. It typically is expressed as an Arbitrary-units number, a Scaled percent (-100 to 100), or a a Voltage.
	*
	* \return The value of the attribute
	*/
	DetectorOffsetMode_TypePtr getOffsetMode() const;

	/*!
	* \brief Resets the OffsetMode attribute to an unset state.
	*
	* This field describes the way in which the Voltage Offset of the Detector is reported. It typically is expressed as an Arbitrary-units number, a Scaled percent (-100 to 100), or a a Voltage.
	*/
	void resetOffsetMode();

	/*!
	* \brief Checks whether the optional OffsetMode attribute is present.
	*
	* This field describes the way in which the Voltage Offset of the Detector is reported. It typically is expressed as an Arbitrary-units number, a Scaled percent (-100 to 100), or a a Voltage.
	*
	* \return true if the optional attribute has been set, false otherwise
	*/
	bool hasOffsetMode() const;


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

	DetectorID_TypePtr ID = nullptr; // Required attribute
	DigitizerType_TypePtr EffectiveBitDepth = nullptr; // Required attribute
    std::optional<float> AnalogGain; // Required attribute
    std::optional<float> AmplificationGain; // Required attribute
    std::optional<float> Offset; // Optional attribute
	DetectorOffsetMode_TypePtr OffsetMode = nullptr; // Optional attribute
};

/*! Shared pointer for DetectorSettings_Type*/
typedef std::shared_ptr<DetectorSettings_Type> DetectorSettings_TypePtr;

} // namespace Inscoper::NBO

#endif // DETECTORSETTINGS_TYPE_HPP_INCLUDED