#pragma once

#include "data/config/SensorSpecificSettings.h"

namespace inertia
{

struct PowerManagementConfig;
struct PowerManagementCapability;
typedef std::shared_ptr<PowerManagementConfig> PowerManagementConfigPtr;
typedef std::shared_ptr<PowerManagementCapability> PowerManagementCapabilityPtr;


enum PowerManagementDescriptorID : uint8_t {
	PM_UNIPOLAR_SUPPLY = 0,
	PM_BIPOLAR_SUPPLY = 1,
	PM_CHARGING = 2,
	PM_DESCR_LAST
};


struct INERTIA_API PowerManagementSettings
	: SpecificSensorSettings
{
	std::vector<PowerManagementConfigPtr> pmConfigs;

	PowerManagementSettings();
	PowerManagementSettings(uint8_t const* in, const unsigned offset, const unsigned _length);
	PowerManagementSettings(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;
	const std::wstring ToSimpleString() const;
};


struct INERTIA_API PowerManagementConfig
{
private:
	uint8_t descrLength;
	PowerManagementDescriptorID descrID;

public:
	uint8_t instance;

	PowerManagementConfig(PowerManagementDescriptorID const _descrID);
	PowerManagementConfig(uint8_t const* in, const unsigned _length);
	PowerManagementConfig(std::wstring const& argString);

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

	PowerManagementDescriptorID GetDescrID() const;

	virtual unsigned GetLength() const;
	virtual void GetBytes(std::vector<uint8_t>& out) const;
	virtual const std::wstring ToString() const;
};


struct INERTIA_API PowerManagementConfigUniPolar
	: PowerManagementConfig
{
	bool enableSupply;
	bool useSupplyOnDemand;

	uint8_t dropoutVoltage;

	float outputVoltage;

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

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

	unsigned GetLength() const override;
	void GetBytes(std::vector<uint8_t>& out) const override;
	const std::wstring ToString() const override;
};


struct INERTIA_API PowerManagementConfigBiPolar
	: PowerManagementConfig
{
	bool enableSupply;
	bool useSupplyOnDemand;

	uint8_t dropoutVoltage;

	float posOutputVoltage;
	float negOutputVoltage;

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

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

	unsigned GetLength() const override;
	void GetBytes(std::vector<uint8_t>& out) const override;
	const std::wstring ToString() const override;
};


struct INERTIA_API PowerManagementConfigCharging
	: PowerManagementConfig
{
	bool enableCharger;
	bool enableTemperatureCompensation;

	uint16_t chargeCurrentLimit;

	std::vector<uint8_t> applicationData;

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

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

	unsigned GetLength() const override;
	void GetBytes(std::vector<uint8_t>& out) const override;
	const std::wstring ToString() const override;
};


// ------------- capabilities -------------


struct INERTIA_API PowerManagementCapabilities
	: SpecificSensorSettings
{
	std::vector<PowerManagementCapabilityPtr> pmCapabilities;

	PowerManagementCapabilities();
	PowerManagementCapabilities(uint8_t const* in, const unsigned offset, const unsigned _length);
	PowerManagementCapabilities(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;
	const std::wstring ToSimpleString() const;
};


struct INERTIA_API PowerManagementCapability
{
private:
	uint8_t descrLength;
	PowerManagementDescriptorID descrID;

public:
	uint8_t instance;

	PowerManagementCapability(PowerManagementDescriptorID const _descrID);
	PowerManagementCapability(uint8_t const* in, const unsigned _length);
	PowerManagementCapability(std::wstring const& argString);

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

	PowerManagementDescriptorID GetDescrID() const;

	virtual unsigned GetLength() const;
	virtual void GetBytes(std::vector<uint8_t>& out) const;
	virtual const std::wstring ToString() const;
};


struct INERTIA_API PowerManagementCapabilityUniPolar
	: PowerManagementCapability
{
	uint8_t hardwareID;
	uint8_t bitfield;
	uint8_t applicationID;

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

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

	unsigned GetLength() const override;
	void GetBytes(std::vector<uint8_t>& out) const override;
	const std::wstring ToString() const override;
};


struct INERTIA_API PowerManagementCapabilityBiPolar
	: PowerManagementCapability
{
	uint8_t hardwareID;
	uint8_t bitfield;
	uint8_t applicationID;

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

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

	unsigned GetLength() const override;
	void GetBytes(std::vector<uint8_t>& out) const override;
	const std::wstring ToString() const override;
};


struct INERTIA_API PowerManagementCapabilityCharging
	: PowerManagementCapability
{
	uint8_t hardwareID;
	uint16_t maxChargeCurrent;

	std::vector<uint8_t> applicationData;

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

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

	unsigned GetLength() const override;
	void GetBytes(std::vector<uint8_t>& out) const override;
	const std::wstring ToString() const override;
};

}
