#pragma once
#include "dll/LogColumns.h"
#include "data/GPSSample.h"
#include "data/config/ConfigChannel.h"

namespace inertia
{
enum StatusMeasurementID : unsigned;


/** @brief Status value.
 *
 *  Contains values for status samples.
 */
struct INERTIA_API StatusValue
{
	uint8_t version;  ///< version
	double value;     ///< converted value
	uint32_t rawData; ///< raw data

	/** Default constructor. */
	StatusValue()
		: version(0)
		, value(0)
		, rawData(0)
	{}

	/** Constructor with parameters.
	 *  @param _version version
	 *  @param _value converted value
	 *  @param _rawData raw data
	 */
	StatusValue(uint8_t const& _version, double const& _value, uint32_t const& _rawData)
		: version(_version)
		, value(_value)
		, rawData(_rawData)
	{}
};

/** @brief AxisData.
 *
 *  Struct to store data of additional sensors.
 */
struct INERTIA_API AxisData
{
	ConfigType configType;      ///< configuration type of data
	uint8_t sensorID;           ///< sensorID of data
	std::vector<double> values; ///< the data values

	/** Default constructor. */
	AxisData()
		: configType(CONFIG_IGNORE)
		, sensorID((uint8_t)-1)
	{}

	/** Constructor with parameters.
	 *  @param _configType the configuration type
	 *  @param _sensorID the sensorID
	 *  @param _values the data values
	 */
	AxisData(ConfigType const& _configType, uint8_t const& _sensorID, std::vector<double> const& _values)
		: configType(_configType)
		, sensorID(_sensorID)
		, values(_values)
	{}
};

/** @brief Sensor data.
 *
 *  This struct contains all the sensor data measured at, or calculated for, a specific timestamp.
 */
struct INERTIA_API Sample
{
	bool hasTimestamp;               ///< The sample has a valid timestamp.
	double timestamp;                ///< Synchronized timestamp (seconds) relative to start time of gateway (when sampling synchronous).

	unsigned lostSamples;            ///< Lost samples since previous sample.

	bool hasAccel;                   ///< The sample has accelerometer values.
	double ax;                       ///< Accelerometer X (m/s2).
	double ay;                       ///< Accelerometer Y (m/s2).
	double az;                       ///< Accelerometer Z (m/s2).

	bool hasCompass;                 ///< The sample has compass values.
	double cx;                       ///< Compass X (gauss).
	double cy;                       ///< Compass Y (gauss).
	double cz;                       ///< Compass Z (gauss).

	bool hasGyro;                    ///< The sample has gyroscope values.
	double gx;                       ///< Gyroscope X (deg/s).
	double gy;                       ///< Gyroscope Y (deg/s).
	double gz;                       ///< Gyroscope Z (deg/s).

	bool hasAccelHighG;              ///< The sample has high-g accelerometer values.
	double axhg;                     ///< High-g accelerometer X (m/s2).
	double ayhg;                     ///< High-g accelerometer Y (m/s2).
	double azhg;                     ///< High-g accelerometer Z (m/s2).

	bool hasPressure;                ///< The sample has a pressure value.
	double pressure;                 ///< Barometric pressure (hPa).

	bool hasTemp;                    ///< The sample has a temperature value.
	double temp;                     ///< Temperature (deg Celsius) inside device.

	bool hasRSSI;                    ///< The sample has a RSSI value.
	double rssi;                     ///< Radio signal strength (dBm).

	bool hasRTC;                     ///< The sample has a RTC value.
	unsigned rtc;                    ///< Real time clock (seconds).

	bool hasOrientation;             ///< The sample has an orientation.
	Quaternion orientation;          ///< Orientation represented in a quaternion.

	bool hasEulerAngles;             ///< The sample has Euler angles (converted from orientation quaternion).
	double roll;                     ///< Roll angle (degrees) around X-axis.
	double pitch;                    ///< Pitch angle (degrees) around Y-axis.
	double yaw;                      ///< Yaw angle (degrees) around Z-axis.

	unsigned sampleNumber;           ///< Sample number.
	unsigned sn;                     ///< Frame number of the sample.
	unsigned index;                  ///< Index within the frame.
	unsigned slot;                   ///< Radio slot position.

	std::vector<double> ima;         ///< IMA (Integral measurement of Accelerometer) values.

	/// Map containing ADC values per analog input.
	std::map<unsigned, double> adc;

	/// Map containing I/O command response values (from Advanced Inertia Gateway), per I/O-port number.
	std::map<unsigned, double> ioCmd;

	/// Map containing data of custom sampling channels.
	std::map<unsigned, std::vector<double> > custom;

	/// Pointer to GPSsample, initialized when there is GPS data.
	std::shared_ptr<GPSsample> gps;

	/// Map containing status values.
	std::map<StatusMeasurementID, StatusValue> status;

	/// Vector with data per sensorID
	std::vector<AxisData> axisData;

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

	/** Get the average values of the samples.
	 *  Note: gpsSample will not be averaged.
	 *  @param samples a vector with samples
	 *  @param start the index within the vector of the first sample to use
	 *  @param end the index within the vector of the last sample to use
	 *  @return a sample with averaged values
	 */
	static const Sample Average(std::vector<Sample> const& samples, const unsigned start, const unsigned end);
};

}
