#ifndef MISSION_DEVICES_RWHANDLER_H_
#define MISSION_DEVICES_RWHANDLER_H_

#include <fsfw/devicehandlers/DeviceHandlerBase.h>
#include <mission/devices/devicedefinitions/RwDefinitions.h>
#include <fsfw_hal/linux/gpio/LinuxLibgpioIF.h>
#include <string.h>

/**
 * @brief	This is the device handler for the reaction wheel from nano avionics.
 *
 * @details Datasheet: https://eive-cloud.irs.uni-stuttgart.de/index.php/apps/files/?dir=/EIVE_IRS/
 *                      Arbeitsdaten/08_Used%20Components/Nanoavionics_Reactionwheels&fileid=181622
 *
 * @note    Values are transferred in little endian format.
 *
 * @author	J. Meier
 */
class RwHandler: public DeviceHandlerBase {
public:

	/**
	 * @brief Constructor
	 *
	 * @param objectId
	 * @param comIF
	 * @param comCookie
	 * @param gpioComIF	Pointer to gpio communication interface
	 * @param enablePin 	GPIO connected to the enable pin of the reaction wheels. Must be pulled
	 * 						to high to enable the device.
	 */
	RwHandler(object_id_t objectId, object_id_t comIF, CookieIF * comCookie,
			LinuxLibgpioIF* gpioComIF, gpioId_t enableGpio);
	virtual ~RwHandler();

    static const uint8_t INTERFACE_ID = CLASS_ID::RW_HANDLER;

    static const ReturnValue_t SPI_WRITE_FAILURE = MAKE_RETURN_CODE(0xB0);
    //! [EXPORT] : [COMMENT] Used by the spi send function to tell a failing read call
    static const ReturnValue_t SPI_READ_FAILURE = MAKE_RETURN_CODE(0xB1);
    //! [EXPORT] : [COMMENT] Can be used by the HDLC decoding mechanism to inform about a missing start sign 0x7E
    static const ReturnValue_t MISSING_START_SIGN = MAKE_RETURN_CODE(0xB2);
    //! [EXPORT] : [COMMENT] Can be used by the HDLC decoding mechanism to inform about an invalid substitution combination
    static const ReturnValue_t INVALID_SUBSTITUTE = MAKE_RETURN_CODE(0xB3);
    //! [EXPORT] : [COMMENT] HDLC decoding mechanism never receives the end sign 0x7E
    static const ReturnValue_t MISSING_END_SIGN = MAKE_RETURN_CODE(0xB4);
    //! [EXPORT] : [COMMENT] Reaction wheel only responds with empty frames.
    static const ReturnValue_t NO_REPLY = MAKE_RETURN_CODE(0xB5);

protected:
	void doStartUp() override;
	void doShutDown() override;
	ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t * id) override;
	ReturnValue_t buildTransitionDeviceCommand(DeviceCommandId_t * id) override;
	void fillCommandAndReplyMap() override;
	ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand,
				const uint8_t * commandData,size_t commandDataLen) override;
	ReturnValue_t scanForReply(const uint8_t *start, size_t remainingSize,
			DeviceCommandId_t *foundId, size_t *foundLen) override;
	ReturnValue_t interpretDeviceReply(DeviceCommandId_t id,
			const uint8_t *packet) override;
	void setNormalDatapoolEntriesInvalid() override;
	uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) override;
	ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
            LocalDataPoolManager& poolManager) override;

private:

    static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::RW_HANDLER;

    //! [EXPORT] : [COMMENT] Action Message with invalid speed was received. Valid speeds must be in the range of [-65000; 1000] or [1000; 65000]
    static const ReturnValue_t INVALID_SPEED = MAKE_RETURN_CODE(0xA0);
    //! [EXPORT] : [COMMENT] Action Message with invalid ramp time was received.
    static const ReturnValue_t INVALID_RAMP_TIME = MAKE_RETURN_CODE(0xA1);
    //! [EXPORT] : [COMMENT] Received set speed command has invalid length. Should be 6.
    static const ReturnValue_t SET_SPEED_COMMAND_INVALID_LENGTH = MAKE_RETURN_CODE(0xA2);
    //! [EXPORT] : [COMMENT] Command execution failed
    static const ReturnValue_t EXECUTION_FAILED = MAKE_RETURN_CODE(0xA3);
    //! [EXPORT] : [COMMENT] Reaction wheel reply has invalid crc
    static const ReturnValue_t CRC_ERROR = MAKE_RETURN_CODE(0xA4);

    //! [EXPORT] : [COMMENT] Reaction wheel signals an error state
    static const Event ERROR_STATE = MAKE_EVENT(1, severity::HIGH);

    LinuxLibgpioIF* gpioComIF = nullptr;
	gpioId_t enableGpio = gpio::NO_GPIO;

    RwDefinitions::TemperatureSet temperatureSet;
    RwDefinitions::StatusSet statusSet;
    RwDefinitions::LastResetSatus lastResetStatusSet;
    RwDefinitions::TmDataset tmDataset;


	uint8_t commandBuffer[RwDefinitions::MAX_CMD_SIZE];

	enum class InternalState {
        GET_RESET_STATUS,
        CLEAR_RESET_STATUS,
        READ_TEMPERATURE,
        GET_RW_SATUS
    };

	InternalState internalState = InternalState::GET_RESET_STATUS;

	size_t sizeOfReply = 0;

	/**
	 * @brief   This function can be used to build commands which do not contain any data apart
	 *          from the command id and the CRC.
	 * @param commandId The command id of the command to build.
	 */
	void prepareSimpleCommand(DeviceCommandId_t id);

	/**
	 * @brief   This function checks if the receiced speed and ramp time to set are in a valid
	 *          range.
	 * @return  RETURN_OK if successful, otherwise error code.
	 */
	ReturnValue_t checkSpeedAndRampTime(const uint8_t * commandData, size_t commandDataLen);

	/**
	 * @brief   This function prepares the set speed command from the commandData received with
	 *          an action message.
	 */
	void prepareSetSpeedCmd(const uint8_t * commandData, size_t commandDataLen);

    /**
     * @brief   This function writes the last reset status retrieved with the get last reset status
     *          command into the reset status dataset.
     *
     * @param packet Pointer to the buffer holding the reply data.
     */
    void handleResetStatusReply(const uint8_t* packet);

	/**
	 * @brief   This function handles the reply of the get temperature command.
	 *
	 * @param packet    Pointer to the reply data
	 */
	void handleTemperatureReply(const uint8_t* packet);

	/**
	 * @brief   This function fills the status set with the data from the get-status-reply.
	 */
	void handleGetRwStatusReply(const uint8_t* packet);

	/**
	 * @brief   This function fills the tmDataset with the reply data requested with get telemetry
	 *          command.
	 */
	void handleGetTelemetryReply(const uint8_t* packet);
};

#endif /* MISSION_DEVICES_RWHANDLER_H_ */