#pragma once

#include "data/command/InertiaCommand.h"

namespace inertia
{

/** RemoteIOCommands */
enum RemoteIOCommands : uint8_t {
	RemoteIOport = 1, // set port I/O pin directions
	RemoteIOset = 2, // set state of I/O pins
	RemoteIOget = 3, // get state of I/O pins
	RemoteIOgetADC = 4, // get ADC value of a pin
	RemoteIOLast
};


/** RemoteIOsetting */
enum RemoteIOsetting {
	RemoteIOsettingKeep = 0, // no change
	RemoteIOsettingInput, // set to input
	RemoteIOsettingOutput, // set to output
	RemoteIOsettingADC // assign to ADC
};


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

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

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


struct INERTIA_API RemoteIOportRequest
	: RemoteIOCommand
{
	std::vector<RemoteIOsetting> setting; // max 8

	RemoteIOportRequest();
	RemoteIOportRequest(const uint8_t* packet, const unsigned max_size);
	RemoteIOportRequest(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 RemoteIOportResponse
	: RemoteIOCommand
	, BoolValue
{
	RemoteIOportResponse(const uint8_t* packet, const unsigned max_size);
	RemoteIOportResponse(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 RemoteIOsetRequest
	: RemoteIOCommand
{
	uint8_t setting;

	RemoteIOsetRequest();
	RemoteIOsetRequest(const uint8_t* packet, const unsigned max_size);
	RemoteIOsetRequest(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 RemoteIOsetResponse
	: RemoteIOCommand
	, BoolValue
{
	RemoteIOsetResponse(const uint8_t* packet, const unsigned max_size);
	RemoteIOsetResponse(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 RemoteIOgetRequest
	: RemoteIOCommand
{
	RemoteIOgetRequest();
	RemoteIOgetRequest(const uint8_t* packet, const unsigned max_size);
	RemoteIOgetRequest(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 RemoteIOgetResponse
	: RemoteIOCommand
{
	uint8_t setting;

	RemoteIOgetResponse(const uint8_t* packet, const unsigned max_size);
	RemoteIOgetResponse(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 RemoteIOgetADCRequest
	: RemoteIOCommand
{
	RemoteIOgetADCRequest();
	RemoteIOgetADCRequest(const uint8_t* packet, const unsigned max_size);
	RemoteIOgetADCRequest(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 RemoteIOgetADCResponse
	: RemoteIOCommand
{
	int16_t value;

	RemoteIOgetADCResponse(const uint8_t* packet, const unsigned max_size);
	RemoteIOgetADCResponse(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;
};

}
