#pragma once

#include "data/command/InertiaCommand.h"
#include "data/config/IOConfigSettings.h"

namespace inertia
{

/** IOCommands */
enum IOCommands : uint8_t {
	CommandIOSpecific = 0,
	CommandIOCommon = 1,
	CommandIOError = 255
};


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

public:
	InertiaCommandGroups GetGroup() const override;

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

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


struct INERTIA_API IOConfigCommonCommand
	: IOConfigCommand
{
	IOCommonModeID commonID;
	IOCommonMessageID messageID;

protected:
	IOConfigCommonCommand(IOCommonModeID const& _commonID, IOCommonMessageID const& _messageID);
	IOConfigCommonCommand(const uint8_t* packet, const unsigned max_size);
	IOConfigCommonCommand(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;
};


struct INERTIA_API IOConfigSpecificCommand
	: IOConfigCommand
{
	uint8_t ioID;
	IOModeID modeID;
	IOMessageID messageID;

protected:
	IOConfigSpecificCommand(uint8_t const& _ioID, IOModeID const& _modeID, IOMessageID const& _messageID);
	IOConfigSpecificCommand(const uint8_t* packet, const unsigned max_size);
	IOConfigSpecificCommand(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;
};


struct INERTIA_API IOCommandUnsupportedResponse
	: IOConfigCommand
{
	IOCommandUnsupportedResponse(const uint8_t* packet, const unsigned max_size);
	IOCommandUnsupportedResponse(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 IOConfigTriggerOutputForceRequest
	: IOConfigSpecificCommand
{
	bool forceState;

	IOConfigTriggerOutputForceRequest(uint8_t const& ioID, bool const _forceState);
	IOConfigTriggerOutputForceRequest(const uint8_t* packet, const unsigned max_size);
	IOConfigTriggerOutputForceRequest(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

	bool IsResponse() const override;
};


struct INERTIA_API IOConfigTriggerOutputForceResponse
	: IOConfigSpecificCommand
{
	uint32_t frameNumber;

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

	bool IsResponse() const override;
};


struct INERTIA_API IOConfigTriggerOutputEvent
	: IOConfigSpecificCommand
{
	IOConfigTriggerOutputEvent(const uint8_t* packet, const unsigned max_size);
	IOConfigTriggerOutputEvent(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

	bool IsResponse() const override;
};


struct INERTIA_API IOConfigTriggerInputEvent
	: IOConfigSpecificCommand
{
	uint32_t frameNumber;
	float phaseShift;

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

	bool IsResponse() const override;
};


struct INERTIA_API IOConfigInputReadRequest
	: IOConfigSpecificCommand
{
	IOConfigInputReadRequest(uint8_t const& ioID);
	IOConfigInputReadRequest(const uint8_t* packet, const unsigned max_size);
	IOConfigInputReadRequest(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

	bool IsResponse() const override;
};


struct INERTIA_API IOConfigInputReadResponse
	: IOConfigSpecificCommand
{
	bool state;
	bool error;

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

	bool IsResponse() const override;
};


struct INERTIA_API IOConfigOutputWriteRequest
	: IOConfigSpecificCommand
{
	bool state;

	IOConfigOutputWriteRequest(uint8_t const& ioID, bool const _state);
	IOConfigOutputWriteRequest(const uint8_t* packet, const unsigned max_size);
	IOConfigOutputWriteRequest(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

	bool IsResponse() const override;
};


struct INERTIA_API IOConfigOutputWriteResponse
	: IOConfigSpecificCommand
{
	bool success;

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

	bool IsResponse() const override;
};

}
