#pragma once

#include "data/config/AbstractConfig.h"

namespace inertia
{
enum ValueType : unsigned;

/** SingleAxisSensors */
enum SingleAxisSensors : uint8_t {
	BAROMETER_LPS25H = 0, ///< Barometer configuration ID
	TEMP_MPU9250,         ///< Temperature configuration ID
	NEXODAQ_CHANNEL,      ///< NexoDAQ Channel configuration ID
	BAROMETER_LPS27HH,    ///< Barometer configuration ID
	TEMP_ICM42605,        ///< Temperature configuration ID
	TEMP_LSM6DSR,         ///< Temperature configuration ID
	TEMP_LSM6DSV320X,     ///< Temperature configuration ID
	TEMP_ICM45686,        ///< Temperature configuration ID
	SINGLE_AXIS_LAST,
	NEXODAQ_USER_GPIO,    ///< internal ID
	NEXODAQ_MONITOR       ///< internal ID
};


/** DualAxisSensors */
enum DualAxisSensors : uint8_t {
	DUAL_AXIS_LAST = 0
};


/** TripleAxisSensors */
enum TripleAxisSensors : uint8_t {
	ACCEL_MPU9250 = 0,   ///< Accelerometer configuration ID
	GYRO_MPU9250,        ///< Gyroscope configuration ID
	COMPASS_AK8963,      ///< Compass configuration ID
	ACCELHG_H3LIS331DL,  ///< High-G Accelerometer configuration ID
	TRIPLE_TESTSENS,     ///< Test sensor
	ACCEL_ICM42605,      ///< Accelerometer configuration ID
	GYRO_ICM42605,       ///< Gyroscope configuration ID
	COMPASS_LIS3MDL,     ///< Compass configuration ID
	ACCEL_LSM6DSR,       ///< Accelerometer configuration ID
	GYRO_LSM6DSR,        ///< Gyroscope configuration ID
	ACCEL_LSM6DSV320X,   ///< Accelerometer configuration ID
	GYRO_LSM6DSV320X,    ///< Gyroscope configuration ID
	ACCELHG_LSM6DSV320X, ///< High-G Accelerometer configuration ID
	ACCEL_ICM45686,      ///< Accelerometer configuration ID
	GYRO_ICM45686,       ///< Gyroscope configuration ID
	TRIPLE_AXIS_LAST
};


/** QuadAxisSensors */
enum QuadAxisSensors : uint8_t {
	QUATERNION_MPU9250 = 0, ///< Quaternion configuration ID
	QUATERNION_SOFTWARE,    ///< Quaternion configuration ID
	QUAD_AXIS_LAST
};


/** OtherAxisSensors */
enum OtherAxisSensors : uint8_t {
	OTHER_POWER_MGMT = 0, ///< Power Management configuration ID
	OTHER_INPUT_OUTPUT,   ///< Input/Output (I/O) configuration ID
	OTHER_GPS,            ///< GPS configuration ID
	OTHER_SCHEDULER,      ///< Scheduler configuration ID
	OTHER_VL53L8CX = 10,  ///< ToF configuration ID
	OTHER_AXIS_LAST
};


struct INERTIA_API SpecificSensorSettings
{
protected:
	SpecificSensorSettings();

public:
	virtual void GetBytes(std::vector<uint8_t>& out, const size_t bitfieldOffset) const = 0;
	virtual const std::wstring ToString() const = 0;

	static ValueType GetType(Channel const& channel);
	static ValueType GetType(ConfigType const configType, unsigned const sensorID);
	static std::vector<unsigned> GetSensorIDs(ValueType const valueType);
	static ConfigType GetConfigType(ValueType const valueType);
	static std::wstring SensorIdToName(ConfigType const configType, unsigned const sensorID, unsigned const subID = 0);
};

typedef std::shared_ptr<SpecificSensorSettings> SpecificSensorSettingsPtr; ///< Pointer to a SpecificSensorSettings.


/** SensorMode */
enum SensorMode {
	SENSOR_MODE_NORMAL = 0,
	SENSOR_MODE_LOW_POWER = 1,
	SENSOR_MODE_SELF_TEST = 2,
	SENSOR_MODE_WAKE_ON_MOTION = 3,
	SENSOR_MODE_GYRO_TEMP_COMP = 4,
	SENSOR_MODE_AUTO_ZERO = 4
};

/** SensorWakeOnMotionMode */
enum SensorWakeOnMotionMode {
	WOM_MODE_NORMAL = 0,
	WOM_MODE_LOW_POWER = 1
};

/** BaroDifferentialMode */
enum BaroDifferentialMode {
	BARO_ABSOLUTE_MEASUREMENT = 0,
	BARO_DIFFERENCE_MEASUREMENT = 1
};

/** AccelHighPassFilter */
enum AccelHighPassFilter {
	ACCEL_HPF_48 = 0,
	ACCEL_HPF_96 = 1,
	ACCEL_HPF_192 = 2,
	ACCEL_HPF_384 = 3
};

/** AccelCompare */
enum AccelCompare {
	ACCEL_COMPARE_DISABLED = 0,
	ACCEL_COMPARE_CHANNEL_A_HIGH = 1,
	ACCEL_COMPARE_CHANNEL_A_LOW = 2,
	ACCEL_COMPARE_CHANNEL_B_HIGH = 3,
	ACCEL_COMPARE_CHANNEL_B_LOW = 4
};

/** AccelCompareMode */
enum AccelCompareMode {
	ACCEL_COMPARE_AND = 0,
	ACCEL_COMPARE_OR = 1
};


struct INERTIA_API BarometerSpecificSettings
	: SpecificSensorSettings
{
	SensorMode sensorMode;	// only normal (0), low-power (1), wake on motion (3) and auto-zero mode (4)
	BaroDifferentialMode diffMode;
	SensorWakeOnMotionMode womMode;
	uint16_t womThreshold;
	bool interpolation;

	BarometerSpecificSettings();
	BarometerSpecificSettings(uint8_t const* in, const unsigned offset, const unsigned _length);
	BarometerSpecificSettings(std::wstring const& argString);

#ifdef WITH_BOOST_PROGRAM_OPTIONS
	static const po::options_description GetOptionDescription();
#endif

	void GetBytes(std::vector<uint8_t>& out, const size_t bitfieldOffset) const override;
	const std::wstring ToString() const override;
};


struct INERTIA_API TemperatureMPUSpecificSettings
	: SpecificSensorSettings
{
	TemperatureMPUSpecificSettings();
	TemperatureMPUSpecificSettings(uint8_t const* in, const unsigned offset, const unsigned _length);
	TemperatureMPUSpecificSettings(std::wstring const& argString);

#ifdef WITH_BOOST_PROGRAM_OPTIONS
	static const po::options_description GetOptionDescription();
#endif

	void GetBytes(std::vector<uint8_t>& out, const size_t bitfieldOffset) const override;
	const std::wstring ToString() const override;
};


struct INERTIA_API AccelSpecificSettings
	: SpecificSensorSettings
{
	SensorMode sensorMode;	// only normal (0), low-power (1), self-test (2) and wake on motion (3)
	uint16_t selfTestX;
	uint16_t selfTestY;
	uint16_t selfTestZ;
	SensorWakeOnMotionMode womMode;
	uint16_t womThreshold;

	AccelSpecificSettings();
	AccelSpecificSettings(uint8_t const* in, const unsigned offset, const unsigned _length);
	AccelSpecificSettings(std::wstring const& argString);

#ifdef WITH_BOOST_PROGRAM_OPTIONS
	static const po::options_description GetOptionDescription();
#endif

	void GetBytes(std::vector<uint8_t>& out, const size_t bitfieldOffset) const override;
	const std::wstring ToString() const override;
};


struct INERTIA_API GyroSpecificSettings
	: SpecificSensorSettings
{
	SensorMode sensorMode;	// only normal (0) and selftest (2)
	bool tempCompensation;
	uint16_t selfTestX;
	uint16_t selfTestY;
	uint16_t selfTestZ;

	GyroSpecificSettings();
	GyroSpecificSettings(uint8_t const* in, const unsigned offset, const unsigned _length);
	GyroSpecificSettings(std::wstring const& argString);

#ifdef WITH_BOOST_PROGRAM_OPTIONS
	static const po::options_description GetOptionDescription();
#endif

	void GetBytes(std::vector<uint8_t>& out, const size_t bitfieldOffset) const override;
	const std::wstring ToString() const override;
};


struct INERTIA_API CompassSpecificSettings
	: SpecificSensorSettings
{
	SensorMode sensorMode;	// only normal (0) and selftest (2)

	CompassSpecificSettings();
	CompassSpecificSettings(uint8_t const* in, const unsigned offset, const unsigned _length);
	CompassSpecificSettings(std::wstring const& argString);

#ifdef WITH_BOOST_PROGRAM_OPTIONS
	static const po::options_description GetOptionDescription();
#endif

	void GetBytes(std::vector<uint8_t>& out, const size_t bitfieldOffset) const override;
	const std::wstring ToString() const override;
};


struct INERTIA_API AccelHighGSpecificSettings
	: SpecificSensorSettings
{
	SensorMode sensorMode;	// only normal (0), low-power (1) and wake on motion (3)
	AccelHighPassFilter highPassFilter;
	bool enableHPF;
	bool restoreCalibration;
	SensorWakeOnMotionMode womMode;
	AccelCompare compareX;
	AccelCompare compareY;
	AccelCompare compareZ;
	bool channelAEnable;
	bool channelBEnable;
	AccelCompareMode channelAMode;
	AccelCompareMode channelBMode;
	uint8_t channelAThreshold;
	uint8_t channelBThreshold;
	uint8_t channelADuration;
	uint8_t channelBDuration;

	AccelHighGSpecificSettings();
	AccelHighGSpecificSettings(uint8_t const* in, const unsigned offset, const unsigned _length);
	AccelHighGSpecificSettings(std::wstring const& argString);

#ifdef WITH_BOOST_PROGRAM_OPTIONS
	static const po::options_description GetOptionDescription();
#endif

	void GetBytes(std::vector<uint8_t>& out, const size_t bitfieldOffset) const override;
	const std::wstring ToString() const override;
};

}
