#pragma once

#include "data/command/InertiaCommand.h"
#include "data/Sample.h"

namespace inertia
{

/** ServiceCommands */
enum ServiceCommands : uint8_t {
	ServiceSetRTC = 1,
	ServiceGetRTC,
	ServiceGetUptime,
	ServiceStoreConfig,
	ServiceRestoreConfig,
	ServiceSendEvent,
	ServiceRadio,
	ServiceStatus,
	ServicePowerDown,
	ServiceReboot,
	ServiceSetOperatingMode,
	ServiceGetOperatingMode,
	ServiceGetOperatingModeLevels,
	ServiceSetTimeZone,
	ServiceStatusV2,
	ServiceSendWOR,
	ServiceLast
};


enum ServiceOperatingMode : uint8_t {
	ServiceOperatingModeActive = 0,
	ServiceOperatingModeStandby = 1,
	ServiceOperatingModeSleep = 2,
	ServiceOperatingModeDeepSleep = 3,
	ServiceOperatingModeTEDS = 4,
};


struct INERTIA_API ServiceCommand
	: InertiaCommand
{
protected:
	ServiceCommand();
	ServiceCommand(const uint8_t* packet, const unsigned max_size);
	ServiceCommand(std::wstring const& argString);

public:
	InertiaCommandGroups GetGroup() const override;
	static std::wstring GetName(ServiceCommands const command);

	static InertiaCommandPtr Parse(const uint8_t* in, unsigned const packetSize);
	static InertiaCommandPtr Parse(std::wstring const& argString);
};


struct INERTIA_API RTCValue
{
protected:
	RTCValue();
	RTCValue(const uint8_t* packet, const unsigned max_size);
	RTCValue(std::wstring const& argString);

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

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

public:
	uint32_t timestamp;
};


struct INERTIA_API ServiceSetRTCRequest
	: ServiceCommand
	, RTCValue
{
	ServiceSetRTCRequest();
	ServiceSetRTCRequest(const uint8_t* packet, const unsigned max_size);
	ServiceSetRTCRequest(std::wstring const& argString);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServiceSetRTCResponse
	: ServiceCommand
	, BoolValue
{
	ServiceSetRTCResponse(const uint8_t* packet, const unsigned max_size);
	ServiceSetRTCResponse(std::wstring const& argString);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServiceGetRTCRequest
	: ServiceCommand
{
	ServiceGetRTCRequest();
	ServiceGetRTCRequest(const uint8_t* packet, const unsigned max_size);
	ServiceGetRTCRequest(std::wstring const& argString);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServiceGetRTCResponse
	: ServiceCommand
	, RTCValue
{
	ServiceGetRTCResponse(const uint8_t* packet, const unsigned max_size);
	ServiceGetRTCResponse(std::wstring const& argString);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServiceGetUptimeRequest
	: ServiceCommand
{
	ServiceGetUptimeRequest();
	ServiceGetUptimeRequest(const uint8_t* packet, const unsigned max_size);
	ServiceGetUptimeRequest(std::wstring const& argString);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServiceGetUptimeResponse
	: ServiceCommand
	, RTCValue
{
	ServiceGetUptimeResponse(const uint8_t* packet, const unsigned max_size);
	ServiceGetUptimeResponse(std::wstring const& argString);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServiceStoreConfigRequest
	: ServiceCommand
{
	ServiceStoreConfigRequest();
	ServiceStoreConfigRequest(const uint8_t* packet, const unsigned max_size);
	ServiceStoreConfigRequest(std::wstring const& argString);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServiceStoreConfigResponse
	: ServiceCommand
	, BoolValue
{
	ServiceStoreConfigResponse(const uint8_t* packet, const unsigned max_size);
	ServiceStoreConfigResponse(std::wstring const& argString);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServiceRestoreConfigRequest
	: ServiceCommand
{
	ServiceRestoreConfigRequest();
	ServiceRestoreConfigRequest(const uint8_t* packet, const unsigned max_size);
	ServiceRestoreConfigRequest(std::wstring const& argString);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServiceRestoreConfigResponse
	: ServiceCommand
	, BoolValue
{
	ServiceRestoreConfigResponse(const uint8_t* packet, const unsigned max_size);
	ServiceRestoreConfigResponse(std::wstring const& argString);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServiceSendEventRequest
	: ServiceCommand
{
	uint8_t sampler, event;
	int16_t param1, param2;

	ServiceSendEventRequest();
	ServiceSendEventRequest(const uint8_t* packet, const unsigned max_size);
	ServiceSendEventRequest(std::wstring const& argString);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServiceSendEventResponse
	: ServiceCommand
	, BoolValue
{
	ServiceSendEventResponse(const uint8_t* packet, const unsigned max_size);
	ServiceSendEventResponse(std::wstring const& argString);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServiceRadioRequest
	: ServiceCommand
{
	uint8_t setting;

	ServiceRadioRequest();
	ServiceRadioRequest(const uint8_t* packet, const unsigned max_size);
	ServiceRadioRequest(std::wstring const& argString);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServiceRadioResponse
	: ServiceCommand
	, BoolValue
{
	ServiceRadioResponse(const uint8_t* packet, const unsigned max_size);
	ServiceRadioResponse(std::wstring const& argString);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServiceStatusRequest
	: ServiceCommand
{
private:
	ServiceCommands type; // ServiceStatus, ServiceStatusV2

public:
	ServiceStatusRequest(ServiceCommands const cmdType = ServiceStatus);
	ServiceStatusRequest(const uint8_t* packet, const unsigned max_size, ServiceCommands const cmdType = ServiceStatus);
	ServiceStatusRequest(std::wstring const& argString, ServiceCommands const cmdType = ServiceStatus);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServiceStatusResponse
	: ServiceCommand
{
private:
	ServiceCommands type; // ServiceStatus, ServiceStatusV2

public:
	std::map<StatusMeasurementID, StatusValue> status;

	bool IsValid() const;

	ServiceStatusResponse(const uint8_t* packet, const unsigned max_size, ServiceCommands const cmdType = ServiceStatus);
	ServiceStatusResponse(std::wstring const& argString, ServiceCommands const cmdType = ServiceStatus);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServicePowerDownRequest
	: ServiceCommand
{
	ServicePowerDownRequest();
	ServicePowerDownRequest(const uint8_t* packet, const unsigned max_size);
	ServicePowerDownRequest(std::wstring const& argString);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServicePowerDownResponse
	: ServiceCommand
	, BoolValue
{
	ServicePowerDownResponse(const uint8_t* packet, const unsigned max_size);
	ServicePowerDownResponse(std::wstring const& argString);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServiceRebootRequest
	: ServiceCommand
{
	ServiceRebootRequest();
	ServiceRebootRequest(const uint8_t* packet, const unsigned max_size);
	ServiceRebootRequest(std::wstring const& argString);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServiceRebootResponse
	: ServiceCommand
	, BoolValue
{
	ServiceRebootResponse(const uint8_t* packet, const unsigned max_size);
	ServiceRebootResponse(std::wstring const& argString);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServiceSetOperatingModeRequest
	: ServiceCommand
{
	ServiceOperatingMode operatingMode;

	ServiceSetOperatingModeRequest(ServiceOperatingMode const& operatingMode = ServiceOperatingModeActive);
	ServiceSetOperatingModeRequest(const uint8_t* packet, const unsigned max_size);
	ServiceSetOperatingModeRequest(std::wstring const& argString);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServiceSetOperatingModeResponse
	: ServiceCommand
	, BoolValue
{
	ServiceSetOperatingModeResponse(const uint8_t* packet, const unsigned max_size);
	ServiceSetOperatingModeResponse(std::wstring const& argString);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServiceGetOperatingModeRequest
	: ServiceCommand
{
	ServiceGetOperatingModeRequest();
	ServiceGetOperatingModeRequest(const uint8_t* packet, const unsigned max_size);
	ServiceGetOperatingModeRequest(std::wstring const& argString);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServiceGetOperatingModeResponse
	: ServiceCommand
{
	ServiceOperatingMode operatingMode;

	ServiceGetOperatingModeResponse(const uint8_t* packet, const unsigned max_size);
	ServiceGetOperatingModeResponse(std::wstring const& argString);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServiceGetOperatingModeLevelsRequest
	: ServiceCommand
{
	ServiceGetOperatingModeLevelsRequest();
	ServiceGetOperatingModeLevelsRequest(const uint8_t* packet, const unsigned max_size);
	ServiceGetOperatingModeLevelsRequest(std::wstring const& argString);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServiceGetOperatingModeLevelsResponse
	: ServiceCommand
{
	std::vector<ServiceOperatingMode> operatingModes;

	ServiceGetOperatingModeLevelsResponse(const uint8_t* packet, const unsigned max_size);
	ServiceGetOperatingModeLevelsResponse(std::wstring const& argString);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServiceSetTimeZoneRequest
	: ServiceCommand
{
	std::wstring timezone;

	ServiceSetTimeZoneRequest();
	ServiceSetTimeZoneRequest(const uint8_t* packet, const unsigned max_size);
	ServiceSetTimeZoneRequest(std::wstring const& argString);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServiceSetTimeZoneResponse
	: ServiceCommand
	, BoolValue
{
	ServiceSetTimeZoneResponse(const uint8_t* packet, const unsigned max_size);
	ServiceSetTimeZoneResponse(std::wstring const& argString);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServiceWakeOnRadioRequest
	: ServiceCommand
{
	uint8_t slot;

	ServiceWakeOnRadioRequest();
	ServiceWakeOnRadioRequest(const uint8_t* packet, const unsigned max_size);
	ServiceWakeOnRadioRequest(std::wstring const& argString);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};


struct INERTIA_API ServiceWakeOnRadioResponse
	: ServiceCommand
	, BoolValue
{
	ServiceWakeOnRadioResponse(const uint8_t* packet, const unsigned max_size);
	ServiceWakeOnRadioResponse(std::wstring const& argString);

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

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

	uint8_t GetType() const override;
	bool IsResponse() const override;
};

}
