#ifndef CAMERASETTINGS_HPP_INCLUDED
#define CAMERASETTINGS_HPP_INCLUDED

#include <iostream>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <vector>
#include <NBO/NBO/Binning_Type.h>
#include <NBO/NBO/CMOSSensorExposureMode_Type.h>
#include <NBO/NBO/DetectorSettings_Type.h>
#include <NBO/NBO/PositiveInt_Type.h>
#include <NBO/NBO/UnitsFrequency_Type.h>
#include <NBO/NBO/UnitsTemperature_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 CameraSettings.
*
* This element refers to the Camera used to acquire this Channel and it holds the Settings that were applied to the Camera during this Acquisition.
*/
class NBO_EXPORT CameraSettings : public DetectorSettings_Type {

public:
	
	CameraSettings();
	~CameraSettings();

	/*!
	* \brief Cast a NBOBaseClass to a CameraSettings.
	*
	* \param base The base class to cast
	* \return The casted element, or nullptr if the cast fails
	*/
	static std::shared_ptr<CameraSettings> 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 Binning attribute.
	*
	* This field represents the number of adjacent pixels whose electric charge is combined in the resulting Image (e.g. binning = 2x2). Generally, binning increases read-out rates, signal-to-noise ratio, and relative sensitivity, while it reduces the spatial resolution.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setBinning(const Inscoper::NBO::Binning_TypePtr& value, bool validate = true);

	/*!
	* \brief Returns the value of the Binning attribute.
	*
	* This field represents the number of adjacent pixels whose electric charge is combined in the resulting Image (e.g. binning = 2x2). Generally, binning increases read-out rates, signal-to-noise ratio, and relative sensitivity, while it reduces the spatial resolution.
	*
	* \return The value of the attribute
	*/
	Binning_TypePtr getBinning() const;

	/*!
	* \brief Resets the Binning attribute to an unset state.
	*
	* This field represents the number of adjacent pixels whose electric charge is combined in the resulting Image (e.g. binning = 2x2). Generally, binning increases read-out rates, signal-to-noise ratio, and relative sensitivity, while it reduces the spatial resolution.
	*/
	void resetBinning();

	/*!
	* \brief Checks whether the optional Binning attribute is present.
	*
	* This field represents the number of adjacent pixels whose electric charge is combined in the resulting Image (e.g. binning = 2x2). Generally, binning increases read-out rates, signal-to-noise ratio, and relative sensitivity, while it reduces the spatial resolution.
	*
	* \return true if the optional attribute has been set, false otherwise
	*/
	bool hasBinning() const;

	/*!
	* \brief Sets the value of the PixelReadOutRate attribute.
	*
	* This represents the effective Pixel Readout Rate used for the Acquisition of this Channel. This value is defined as the inverse of the time required to digitize a single pixel (also referred to as serial conversion time). Pixel readout rate can be considered similar to a baud rate as it depends on the bytes per second that can be read from the detector and written on disk. Readout rates are usually given in pixels/second (e.g., 500 kilopixels/second).
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setPixelReadOutRate(const float& value, bool validate = true);

	/*!
	* \brief Returns the value of the PixelReadOutRate attribute.
	*
	* This represents the effective Pixel Readout Rate used for the Acquisition of this Channel. This value is defined as the inverse of the time required to digitize a single pixel (also referred to as serial conversion time). Pixel readout rate can be considered similar to a baud rate as it depends on the bytes per second that can be read from the detector and written on disk. Readout rates are usually given in pixels/second (e.g., 500 kilopixels/second).
	*
	* \return The value of the attribute
	*/
	float getPixelReadOutRate() const;

	/*!
	* \brief Resets the PixelReadOutRate attribute to an unset state.
	*
	* This represents the effective Pixel Readout Rate used for the Acquisition of this Channel. This value is defined as the inverse of the time required to digitize a single pixel (also referred to as serial conversion time). Pixel readout rate can be considered similar to a baud rate as it depends on the bytes per second that can be read from the detector and written on disk. Readout rates are usually given in pixels/second (e.g., 500 kilopixels/second).
	*/
	void resetPixelReadOutRate();

	/*!
	* \brief Checks whether the PixelReadOutRate attribute is present.
	*
	* This represents the effective Pixel Readout Rate used for the Acquisition of this Channel. This value is defined as the inverse of the time required to digitize a single pixel (also referred to as serial conversion time). Pixel readout rate can be considered similar to a baud rate as it depends on the bytes per second that can be read from the detector and written on disk. Readout rates are usually given in pixels/second (e.g., 500 kilopixels/second).
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasPixelReadOutRate() const;

	/*!
	* \brief Sets the value of the PixelReadOutRateUnit attribute.
	*
	* 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 setPixelReadOutRateUnit(const Inscoper::NBO::UnitsFrequency_TypePtr& value, bool validate = true);

	/*!
	* \brief Returns the value of the PixelReadOutRateUnit attribute.
	*
	* No description available in the XSD standard.
	*
	* \return The value of the attribute
	*/
	UnitsFrequency_TypePtr getPixelReadOutRateUnit() const;

	/*!
	* \brief Resets the PixelReadOutRateUnit attribute to an unset state.
	*
	* No description available in the XSD standard.
	*/
	void resetPixelReadOutRateUnit();

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

	/*!
	* \brief Sets the value of the SensorExposureMode attribute.
	*
	* In case of a CMOS Camera and if selectable, this field reports the sensor Exposure modality used for the Acquisition of this Channel. In the Rolling Exposure mode adjacent rows of the array are exposed at slightly different times as the readout 'waves' sweep through each half of the sensor. In the Global Exposure mode (i.e., 'Snapshot' exposure mode) all pixels of the array are exposed simultaneously, thus enabling 'freeze frame' capture of fast moving or fast changing events. In this modality the CMOS Camera behaves like an interline CCD sensor.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setSensorExposureMode(const Inscoper::NBO::CMOSSensorExposureMode_TypePtr& value, bool validate = true);

	/*!
	* \brief Returns the value of the SensorExposureMode attribute.
	*
	* In case of a CMOS Camera and if selectable, this field reports the sensor Exposure modality used for the Acquisition of this Channel. In the Rolling Exposure mode adjacent rows of the array are exposed at slightly different times as the readout 'waves' sweep through each half of the sensor. In the Global Exposure mode (i.e., 'Snapshot' exposure mode) all pixels of the array are exposed simultaneously, thus enabling 'freeze frame' capture of fast moving or fast changing events. In this modality the CMOS Camera behaves like an interline CCD sensor.
	*
	* \return The value of the attribute
	*/
	CMOSSensorExposureMode_TypePtr getSensorExposureMode() const;

	/*!
	* \brief Resets the SensorExposureMode attribute to an unset state.
	*
	* In case of a CMOS Camera and if selectable, this field reports the sensor Exposure modality used for the Acquisition of this Channel. In the Rolling Exposure mode adjacent rows of the array are exposed at slightly different times as the readout 'waves' sweep through each half of the sensor. In the Global Exposure mode (i.e., 'Snapshot' exposure mode) all pixels of the array are exposed simultaneously, thus enabling 'freeze frame' capture of fast moving or fast changing events. In this modality the CMOS Camera behaves like an interline CCD sensor.
	*/
	void resetSensorExposureMode();

	/*!
	* \brief Checks whether the optional SensorExposureMode attribute is present.
	*
	* In case of a CMOS Camera and if selectable, this field reports the sensor Exposure modality used for the Acquisition of this Channel. In the Rolling Exposure mode adjacent rows of the array are exposed at slightly different times as the readout 'waves' sweep through each half of the sensor. In the Global Exposure mode (i.e., 'Snapshot' exposure mode) all pixels of the array are exposed simultaneously, thus enabling 'freeze frame' capture of fast moving or fast changing events. In this modality the CMOS Camera behaves like an interline CCD sensor.
	*
	* \return true if the optional attribute has been set, false otherwise
	*/
	bool hasSensorExposureMode() const;

	/*!
	* \brief Sets the value of the Integration attribute.
	*
	* This field represents the number of sequential frames that have been averaged to obtain this image, to improve the overall signal-to-noise ratio.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setIntegration(const Inscoper::NBO::PositiveInt_TypePtr& value, bool validate = true);

	/*!
	* \brief Returns the value of the Integration attribute.
	*
	* This field represents the number of sequential frames that have been averaged to obtain this image, to improve the overall signal-to-noise ratio.
	*
	* \return The value of the attribute
	*/
	PositiveInt_TypePtr getIntegration() const;

	/*!
	* \brief Resets the Integration attribute to an unset state.
	*
	* This field represents the number of sequential frames that have been averaged to obtain this image, to improve the overall signal-to-noise ratio.
	*/
	void resetIntegration();

	/*!
	* \brief Checks whether the optional Integration attribute is present.
	*
	* This field represents the number of sequential frames that have been averaged to obtain this image, to improve the overall signal-to-noise ratio.
	*
	* \return true if the optional attribute has been set, false otherwise
	*/
	bool hasIntegration() const;

	/*!
	* \brief Sets the value of the FrameRate attribute.
	*
	* Frame Rate is the inverse of the time needed for the CCD to acquire a single Frame (or Plane) and then completely read that image out. Frame Rate is typically expressed in frames per second (fps). Often, the Frame Rate can be approximately calculated from the total number of pixels and the readout rate, combined with the total exposure time. This field represents the effective Frame Rate used for the Acquisition of this Image.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setFrameRate(const float& value, bool validate = true);

	/*!
	* \brief Returns the value of the FrameRate attribute.
	*
	* Frame Rate is the inverse of the time needed for the CCD to acquire a single Frame (or Plane) and then completely read that image out. Frame Rate is typically expressed in frames per second (fps). Often, the Frame Rate can be approximately calculated from the total number of pixels and the readout rate, combined with the total exposure time. This field represents the effective Frame Rate used for the Acquisition of this Image.
	*
	* \return The value of the attribute
	*/
	float getFrameRate() const;

	/*!
	* \brief Resets the FrameRate attribute to an unset state.
	*
	* Frame Rate is the inverse of the time needed for the CCD to acquire a single Frame (or Plane) and then completely read that image out. Frame Rate is typically expressed in frames per second (fps). Often, the Frame Rate can be approximately calculated from the total number of pixels and the readout rate, combined with the total exposure time. This field represents the effective Frame Rate used for the Acquisition of this Image.
	*/
	void resetFrameRate();

	/*!
	* \brief Checks whether the FrameRate attribute is present.
	*
	* Frame Rate is the inverse of the time needed for the CCD to acquire a single Frame (or Plane) and then completely read that image out. Frame Rate is typically expressed in frames per second (fps). Often, the Frame Rate can be approximately calculated from the total number of pixels and the readout rate, combined with the total exposure time. This field represents the effective Frame Rate used for the Acquisition of this Image.
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasFrameRate() const;

	/*!
	* \brief Sets the value of the FrameRateUnit attribute.
	*
	* 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 setFrameRateUnit(const Inscoper::NBO::UnitsFrequency_TypePtr& value, bool validate = true);

	/*!
	* \brief Returns the value of the FrameRateUnit attribute.
	*
	* No description available in the XSD standard.
	*
	* \return The value of the attribute
	*/
	UnitsFrequency_TypePtr getFrameRateUnit() const;

	/*!
	* \brief Resets the FrameRateUnit attribute to an unset state.
	*
	* No description available in the XSD standard.
	*/
	void resetFrameRateUnit();

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

	/*!
	* \brief Sets the value of the OperatingTemperature attribute.
	*
	* This field represents the effective temperature the sensor was kept at during the Acquisition of this image.
	*
	* \param value The value to set
	* \param validate If true, validates constraints on value. Default is true.
	*/
	void setOperatingTemperature(const float& value, bool validate = true);

	/*!
	* \brief Returns the value of the OperatingTemperature attribute.
	*
	* This field represents the effective temperature the sensor was kept at during the Acquisition of this image.
	*
	* \return The value of the attribute
	*/
	float getOperatingTemperature() const;

	/*!
	* \brief Resets the OperatingTemperature attribute to an unset state.
	*
	* This field represents the effective temperature the sensor was kept at during the Acquisition of this image.
	*/
	void resetOperatingTemperature();

	/*!
	* \brief Checks whether the OperatingTemperature attribute is present.
	*
	* This field represents the effective temperature the sensor was kept at during the Acquisition of this image.
	*
	* \return true if the attribute has been set, false otherwise
	*/
	bool hasOperatingTemperature() const;

	/*!
	* \brief Sets the value of the OperatingTemperatureUnit attribute.
	*
	* 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 setOperatingTemperatureUnit(const Inscoper::NBO::UnitsTemperature_TypePtr& value, bool validate = true);

	/*!
	* \brief Returns the value of the OperatingTemperatureUnit attribute.
	*
	* No description available in the XSD standard.
	*
	* \return The value of the attribute
	*/
	UnitsTemperature_TypePtr getOperatingTemperatureUnit() const;

	/*!
	* \brief Resets the OperatingTemperatureUnit attribute to an unset state.
	*
	* No description available in the XSD standard.
	*/
	void resetOperatingTemperatureUnit();

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


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

	Binning_TypePtr Binning = nullptr; // Required attribute
    std::optional<float> PixelReadOutRate; // Required attribute
	UnitsFrequency_TypePtr PixelReadOutRateUnit = nullptr; // Optional attribute
	CMOSSensorExposureMode_TypePtr SensorExposureMode = nullptr; // Required attribute
	PositiveInt_TypePtr Integration = nullptr; // Required attribute
    std::optional<float> FrameRate; // Required attribute
	UnitsFrequency_TypePtr FrameRateUnit = nullptr; // Optional attribute
    std::optional<float> OperatingTemperature; // Optional attribute
	UnitsTemperature_TypePtr OperatingTemperatureUnit = nullptr; // Optional attribute
};

/*! Shared pointer for CameraSettings*/
typedef std::shared_ptr<CameraSettings> CameraSettingsPtr;

} // namespace Inscoper::NBO

#endif // CAMERASETTINGS_HPP_INCLUDED