#pragma once

namespace inertia
{

/** Type of Orientation Algorithm */
enum OrientationAlgorithm : unsigned
{
	ORIENTATION_MADGWICK = 0, ///< Madgwick Orientation Algorithm.
	ORIENTATION_VALENTI = 1,  ///< Valenti Orientation Algorithm.
	ORIENTATION_KALMAN = 2,   ///< Extended Kalman Orientation Algorithm.
	ORIENTATION_VQF = 3       ///< Versatile Quaternion-based Filter Algorithm.
};


/** @brief Madgwick Orientation Algorithm Settings
 *
 *  Struct containing settings for Madgwick orientation algorithm.
 */
struct INERTIA_API MadgwickAlgorithmSettings
{
	double gainBeta; ///< Adjust the influence of the gyroscope (higher) versus accelerometer (lower)  (0 <= value <= 1), default is 0.1.

	/** Default constructor.
	 */
	MadgwickAlgorithmSettings();

	/** Constructor with string argument.
	 *  Creates MadgwickAlgorithmSettings from a string.
	 *  @param argString string with arguments
	 */
	MadgwickAlgorithmSettings(std::wstring const& argString);

#ifdef WITH_BOOST_PROGRAM_OPTIONS
	/** Get the possible command-line arguments for MadgwickAlgorithmSettings.
	 *  Only available when \a WITH_BOOST_PROGRAM_OPTIONS is defined.
	 *  @return the option description
	 */
	static const po::options_description GetOptionDescription();
#endif

	/** Get a string representation of this MadgwickAlgorithmSettings.
	 *  The string is compatible with GetOptionDescription() and MadgwickAlgorithmSettings(std::wstring const&).
	 *  @return the string
	 */
	std::wstring const ToString() const;
};


/** @brief Valenti Orientation Algorithm Settings
 *
 *  Struct containing settings for Valenti orientation algorithm.
 */
struct INERTIA_API ValentiAlgorithmSettings
{
	double accelGain;          ///< Influence of accelerometer (0 <= value <= 1), default is 0.0005.
	double compassGain;        ///< Influence of compass (0 <= value <= 1), default is 0.001.
	bool enableAdaptiveGain;   ///< Enable automatic accelerometer gain adjustment, default is true.

	/** Default constructor.
	 */
	ValentiAlgorithmSettings();

	/** Constructor with string argument.
	 *  Creates ValentiAlgorithmSettings from a string.
	 *  @param argString string with arguments
	 */
	ValentiAlgorithmSettings(std::wstring const& argString);

#ifdef WITH_BOOST_PROGRAM_OPTIONS
	/** Get the possible command-line arguments for ValentiAlgorithmSettings.
	 *  Only available when \a WITH_BOOST_PROGRAM_OPTIONS is defined.
	 *  @return the option description
	 */
	static const po::options_description GetOptionDescription();
#endif

	/** Get a string representation of this ValentiAlgorithmSettings.
	 *  The string is compatible with GetOptionDescription() and ValentiAlgorithmSettings(std::wstring const&).
	 *  @return the string
	 */
	std::wstring const ToString() const;
};


/** @brief Extended Kalman Orientation Algorithm Settings
 *
 *  Struct containing settings for Extended Kalman orientation algorithm.
 */
struct INERTIA_API KalmanAlgorithmSettings
{
	double accNoise;              ///< Accelerometer noise, default 0.07.
	double compNoise;             ///< Compass noise, default 0.0205.
	double gyroNoise;             ///< Gyroscope noise, default 0.0038.
	double gyroBiasNoise;         ///< Gyroscope bias noise, default 0.0038.
	bool adjustToSamplingRate;    ///< Adjust the noise level to the sampling rate (defaults are for 200Hz), default true.
	double accMagnitudeThreshold; ///< Ignore accelerometer above this magnitude threshold, default 20.

	/** Default constructor.
	 */
	KalmanAlgorithmSettings();

	/** Constructor with string argument.
	 *  Creates KalmanAlgorithmSettings from a string.
	 *  @param argString string with arguments
	 */
	KalmanAlgorithmSettings(std::wstring const& argString);

#ifdef WITH_BOOST_PROGRAM_OPTIONS
	/** Get the possible command-line arguments for KalmanAlgorithmSettings.
	 *  Only available when \a WITH_BOOST_PROGRAM_OPTIONS is defined.
	 *  @return the option description
	 */
	static const po::options_description GetOptionDescription();
#endif

	/** Get a string representation of this KalmanAlgorithmSettings.
	 *  The string is compatible with GetOptionDescription() and KalmanAlgorithmSettings(std::wstring const&).
	 *  @return the string
	 */
	std::wstring const ToString() const;
};


/** @brief Versatile Quaternion-based Filter Algorithm Settings
 *
 *  Struct containing settings for Versatile Quaternion-based Filter algorithm.
 */
struct INERTIA_API VQFAlgorithmSettings
{
	double tauAcc;                       ///< Time constant for accelerometer low-pass filtering in seconds, default 3.0.
	double tauMag;                       ///< Time constant for magnetometer update in seconds, default 9.0.
	bool motionBiasEstEnabled;           ///< Enables gyroscope bias estimation during motion phases, default true.
	bool restBiasEstEnabled;             ///< Enables rest detection and gyroscope bias estimation during rest phases, default true.
	bool magDistRejectionEnabled;        ///< Enables magnetic disturbance detection and magnetic disturbance rejection, default true.

	double biasSigmaInit;                ///< Standard deviation of the initial bias estimation uncertainty (in degrees per second), default 0.5.
	double biasForgettingTime;           ///< Time in which the bias estimation uncertainty increases from 0 °/s to 0.1 °/s (in seconds), default 100.
	double biasClip;                     ///< Maximum expected gyroscope bias (in degrees per second), default 2.0.
	double biasSigmaMotion;              ///< Standard deviation of the converged bias estimation uncertainty during motion (in degrees per second), default 0.1.
	double biasVerticalForgettingFactor; ///< Forgetting factor for unobservable bias in vertical direction during motion, default 0.0001.
	double biasSigmaRest;                ///< Standard deviation of the converged bias estimation uncertainty during rest (in degrees per second), default 0.03.

	double restMinTh;                    ///< Time threshold for rest detection (in seconds), default 1.5.
	double restFilterTau;                ///< Time constant for the low-pass filter used in rest detection (in seconds), default 0.5.
	double restThGyr;                    ///< Angular velocity threshold for rest detection (in °/s), default 2.0.
	double restThAcc;                    ///< Acceleration threshold for rest detection (in m/s²), default 0.5.

	double magCurrentTau;                ///< Time constant for current norm/dip value in magnetic disturbance detection (in seconds), default 0.05.
	double magRefTau;                    ///< Time constant for the adjustment of the magnetic field reference (in seconds), default 20.
	double magNormTh;                    ///< Relative threshold for the magnetic field strength for magnetic disturbance detection, default 0.1 (10%).
	double magDipTh;                     ///< Threshold for the magnetic field dip angle for magnetic disturbance detection (in degrees), default 10.
	double magNewTime;                   ///< Duration after which to accept a different homogeneous magnetic field (in seconds), default 20.
	double magNewFirstTime;              ///< Duration after which to accept a homogeneous magnetic field for the first time (in seconds), default 5.
	double magNewMinGyr;                 ///< Minimum angular velocity needed in order to count time for new magnetic field acceptance (in °/s), default 20.
	double magMinUndisturbedTime;        ///< Minimum duration within thresholds after which to regard the field as undisturbed again (in seconds), default 0.5.
	double magMaxRejectionTime;          ///< Maximum duration of full magnetic disturbance rejection (in seconds), default 60.
	double magRejectionFactor;           ///< Factor by which to slow the heading correction during long disturbed phases, default 2.

	/** Default constructor.
	 */
	VQFAlgorithmSettings();

	/** Constructor with string argument.
	 *  Creates VQFAlgorithmSettings from a string.
	 *  @param argString string with arguments
	 */
	VQFAlgorithmSettings(std::wstring const& argString);

#ifdef WITH_BOOST_PROGRAM_OPTIONS
	/** Get the possible command-line arguments for VQFAlgorithmSettings.
	 *  Only available when \a WITH_BOOST_PROGRAM_OPTIONS is defined.
	 *  @return the option description
	 */
	static const po::options_description GetOptionDescription();
#endif

	/** Get a string representation of this VQFAlgorithmSettings.
	 *  The string is compatible with GetOptionDescription() and VQFAlgorithmSettings(std::wstring const&).
	 *  @return the string
	 */
	std::wstring const ToString() const;
};



/** @brief Bias Estimation Algorithm Settings
 *
 *  Struct containing settings for Bias Estimation Algorithm.
 */
struct INERTIA_API BiasEstimationSettings
{
	bool enableBiasEstimation; ///< Enable gyroscope bias estimation, default is true.
	double biasAlpha;          ///< Set how fast bias is updated (0 <= value <= 1), default is 0.01.
	double gyroThreshold;      ///< Gyroscope absolute threshold (from bias), default is 0.015.
	double gyroDeltaThreshold; ///< Gyroscope relative threshold (from previous value), default is 0.015.
	double accelThreshold;     ///< Accelerometer absolute threshold (from zero), default is 0.015.

	bool useFixedBias;         ///< Use a fixed gyroscope bias, enableBiasEstimation should be enabled.
	double gxFixedBias;        ///< The fixed gyroscope X-axis bias.
	double gyFixedBias;        ///< The fixed gyroscope Y-axis bias.
	double gzFixedBias;        ///< The fixed gyroscope Z-axis bias.

	/** Default constructor.
	 */
	BiasEstimationSettings();

	/** Constructor with string argument.
	 *  Creates BiasEstimationSettings from a string.
	 *  @param argString string with arguments
	 */
	BiasEstimationSettings(std::wstring const& argString);

#ifdef WITH_BOOST_PROGRAM_OPTIONS
	/** Get the possible command-line arguments for BiasEstimationSettings.
	 *  Only available when \a WITH_BOOST_PROGRAM_OPTIONS is defined.
	 *  @return the option description
	 */
	static const po::options_description GetOptionDescription();
#endif

	/** Get a string representation of this BiasEstimationSettings.
	 *  The string is compatible with GetOptionDescription() and BiasEstimationSettings(std::wstring const&).
	 *  @return the string
	 */
	std::wstring const ToString() const;
};


/** @brief Orientation Settings
 *
 *  Struct containing settings for orientation algorithm.
 */
struct INERTIA_API OrientationSettings
{
	OrientationAlgorithm algorithm; ///< Orientation algorithm to use.
	bool useCompass;                ///< Use data from the compass for orientation calculation.
	bool resetInRest;               ///< Reset the orientation when the node stops rotating.
	double initialYaw;              ///< The initial yaw angle, irrelevant when compass is used.

	MadgwickAlgorithmSettings madgwickSettings; ///< Specific settings of the Madgwick Orientation Algorithm.
	ValentiAlgorithmSettings valentiSettings;   ///< Specific settings of the Valenti Orientation Algorithm.
	KalmanAlgorithmSettings kalmanSettings;     ///< Specific settings of the Extended Kalman Orientation Algorithm.
	VQFAlgorithmSettings vqfSettings;           ///< Specific settings of the Versatile Quaternion-based Filter Algorithm.
	BiasEstimationSettings biasSettings;        ///< Specific settings of the Bias Estimation Algorithm.

	/** Default constructor.
	 */
	OrientationSettings();

	/** Constructor with string argument.
	 *  Creates OrientationSettings from a string.
	 *  @param argString string with arguments
	 */
	OrientationSettings(std::wstring const& argString);

#ifdef WITH_BOOST_PROGRAM_OPTIONS
	/** Get the possible command-line arguments for OrientationSettings.
	 *  Only available when \a WITH_BOOST_PROGRAM_OPTIONS is defined.
	 *  @return the option description
	 */
	static const po::options_description GetOptionDescription();
#endif

	/** Get a string representation of this OrientationSettings.
	 *  The string is compatible with GetOptionDescription() and OrientationSettings(std::wstring const&).
	 *  @return the string
	 */
	std::wstring const ToString() const;
};

}
