#pragma once

#include "data/command/InertiaCommand.h"

namespace inertia
{

/** LoggingCommands */
enum LoggingCommands : uint8_t {
	LoggingStart = 1,
	LoggingStop = 2,
	LoggingGetFirst = 3,
	LoggingState = 4,
	LoggingReadRange = 5,
	LoggingOpen = 6,
	LoggingClose = 7,
	LoggingMonMode = 8,
	LoggingLast
};


/** LoggingSearchType */
enum LoggingSearchType {
	LoggingSearchFrameNumber = 0,
	LoggingSearchTimestamp = 1,
	LoggingSearchNone = 255 // get first file of sequence with specified ID
};


/** SearchCondition */
enum SearchCondition {
	SearchConditionAny = 0,
	SearchConditionLowerEqual = 1,
	SearchConditionHigherEqual = 2,
	SearchConditionEqual = 3
};


/** ReadRangeStatusCode */
enum ReadRangeStatusCode {
	ReadRangeStatusOK = 0,
	ReadRangeStatusInvalid = 1,
	ReadRangeStatusEOF = 2
};


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

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

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


struct INERTIA_API LoggingStartRequest
	: LoggingCommand
{
	LoggingStartRequest();
	LoggingStartRequest(const uint8_t* packet, const unsigned max_size);
	LoggingStartRequest(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 LoggingStartResponse
	: LoggingCommand
	, BoolValue
{
	LoggingStartResponse(const uint8_t* packet, const unsigned max_size);
	LoggingStartResponse(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 LoggingStopRequest
	: LoggingCommand
{
	LoggingStopRequest();
	LoggingStopRequest(const uint8_t* packet, const unsigned max_size);
	LoggingStopRequest(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 LoggingStopResponse
	: LoggingCommand
	, BoolValue
{
	LoggingStopResponse(const uint8_t* packet, const unsigned max_size);
	LoggingStopResponse(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 LoggingGetFirstRequest
	: LoggingCommand
{
	LoggingSearchType searchType;
	uint8_t sequenceID; // file sequence to search in, 0xff when not used
	uint32_t searchParam; // timestamp or frame
	SearchCondition condition; // any/before/after/equal timestamp

	LoggingGetFirstRequest();
	LoggingGetFirstRequest(const uint8_t* packet, const unsigned max_size);
	LoggingGetFirstRequest(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 LoggingGetFirstResponse
	: LoggingCommand
{
	bool result; // success or failure
	uint8_t sequenceID;
	uint32_t filePointer;

	LoggingGetFirstResponse(const uint8_t* packet, const unsigned max_size);
	LoggingGetFirstResponse(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 LoggingStateRequest
	: LoggingCommand
{
	LoggingStateRequest();
	LoggingStateRequest(const uint8_t* packet, const unsigned max_size);
	LoggingStateRequest(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 LoggingStateResponse
	: LoggingCommand
{
	bool loggingActive;

	LoggingStateResponse(const uint8_t* packet, const unsigned max_size);
	LoggingStateResponse(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 LoggingReadRangeRequest
	: LoggingCommand
{
	std::vector<std::pair<uint32_t, uint32_t> > frameRanges;

	LoggingReadRangeRequest();
	LoggingReadRangeRequest(const uint8_t* packet, const unsigned max_size);
	LoggingReadRangeRequest(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 LoggingReadRangeResponse
	: LoggingCommand
{
	ReadRangeStatusCode statusCode;
	std::vector<uint8_t> rawdata;

	LoggingReadRangeResponse(const uint8_t* packet, const unsigned max_size);
	LoggingReadRangeResponse(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 LoggingOpenRequest
	: LoggingCommand
{
	std::wstring filename;

	LoggingOpenRequest();
	LoggingOpenRequest(const uint8_t* packet, const unsigned max_size);
	LoggingOpenRequest(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 LoggingOpenResponse
	: LoggingCommand
	, BoolValue
{
	LoggingOpenResponse(const uint8_t* packet, const unsigned max_size);
	LoggingOpenResponse(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 LoggingCloseRequest
	: LoggingCommand
{
	LoggingCloseRequest();
	LoggingCloseRequest(const uint8_t* packet, const unsigned max_size);
	LoggingCloseRequest(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 LoggingCloseResponse
	: LoggingCommand
	, BoolValue
{
	LoggingCloseResponse(const uint8_t* packet, const unsigned max_size);
	LoggingCloseResponse(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 LoggingMonitoringModeRequest
	: LoggingCommand
{
	bool forceEnable;

	LoggingMonitoringModeRequest();
	LoggingMonitoringModeRequest(const uint8_t* packet, const unsigned max_size);
	LoggingMonitoringModeRequest(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 LoggingMonitoringModeResponse
	: LoggingCommand
	, BoolValue
{
	LoggingMonitoringModeResponse(const uint8_t* packet, const unsigned max_size);
	LoggingMonitoringModeResponse(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;
};

}
