#ifndef MISSION_DEVICES_GOMSPACEDEVICEHANDLER_H_
#define MISSION_DEVICES_GOMSPACEDEVICEHANDLER_H_

#include "fsfw/devicehandlers/DeviceHandlerBase.h"
#include "mission/devices/devicedefinitions/GomspaceDefinitions.h"
#include "returnvalues/classIds.h"

/**
 * @brief	This is the device handler class for all gomspace devices.
 *
 * @details
 * All gomspace devices are similar with respect to commanding. Thusmost of the functionality to
 * command a gomspace device can be accommodated in one class. For device specific functions, a new
 * class could be created by inheriting from the GomspaceDeviceHandler.
 *
 * Flight manual:
 * https://egit.irs.uni-stuttgart.de/redmine/projects/eive-flight-manual/wiki/Gomspace_PCDU_P60_System
 */
class GomspaceDeviceHandler: public DeviceHandlerBase {
public:

    static constexpr uint8_t CLASS_ID = CLASS_ID::GOM_SPACE_HANDLER;
    static const ReturnValue_t PACKET_TOO_LONG = HasReturnvaluesIF::makeReturnCode(CLASS_ID, 0);
    static const ReturnValue_t INVALID_TABLE_ID = HasReturnvaluesIF::makeReturnCode(CLASS_ID, 1);
    static const ReturnValue_t INVALID_ADDRESS = HasReturnvaluesIF::makeReturnCode(CLASS_ID, 2);
    static const ReturnValue_t INVALID_PARAM_SIZE = HasReturnvaluesIF::makeReturnCode(CLASS_ID, 3);
    static const ReturnValue_t INVALID_PAYLOAD_SIZE =
            HasReturnvaluesIF::makeReturnCode(CLASS_ID, 4);
    static const ReturnValue_t UNKNOWN_REPLY_ID = HasReturnvaluesIF::makeReturnCode(CLASS_ID, 5);

    /**
     * @brief	Constructor
     *
     * @param maxConfigTableAddress	The maximum memory address of the configu-
     * 								ration table of a gomspace device.
     * @param maxHkTableAddress	The maximum memory address of a value in the
     * 							houskeeping (telemetry) table of a gomspace
     * 							device.
     */
    GomspaceDeviceHandler(object_id_t objectId, object_id_t comIF,
            CookieIF * comCookie, uint16_t maxConfigTableAddress, uint16_t maxHkTableAddress,
            uint16_t hkTableReplySize, LocalPoolDataSetBase* hkTableDataset);
    virtual ~GomspaceDeviceHandler();

    /**
     * @brief   This function can be used to set a gomspace device to normal mode immediately after
     *          object creation.
     */
    void setModeNormal();

protected:

    static const uint8_t MAX_PACKET_LEN = 36;
    static const uint8_t PARAM_SET_OK = 1;
    static const uint8_t PING_REPLY_SIZE = 2;
    static const uint8_t CONFIG_TABLE_ID = 1;
    static const uint8_t HK_TABLE_ID = 4;

    uint8_t rememberRequestedSize = 0;
    uint8_t rememberCommandId = GOMSPACE::NONE;
    uint8_t cspPacket[MAX_PACKET_LEN];

    uint16_t maxConfigTableAddress;
    uint16_t maxHkTableAddress;

    /** The size of the reply following a full hk table request.*/
    uint16_t hkTableReplySize;

    LocalPoolDataSetBase* hkTableDataset = nullptr;

    void doStartUp() override;
    void doShutDown() override;
    virtual 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;
    /**
     * @brief   The command to generate a request to receive the full housekeeping table is device
     *          specific. Thus the child has to build this command.
     */
    virtual ReturnValue_t generateRequestFullHkTableCmd(uint16_t hkTableSize);

    /**
     * This command handles printing the HK table to the console. This is useful for debugging
     * purposes
     * @return
     */
    virtual ReturnValue_t printStatus(DeviceCommandId_t cmd);

    /**
     * @brief	Because housekeeping tables are device specific the handling of the reply is
     * 			given to the child class.
     * @param id	The id of the command which initiates the full table request.
     * @param packet	Pointer to the reply containing the hk table.
     */
    virtual void letChildHandleHkReply(DeviceCommandId_t id, const uint8_t *packet) = 0;

    virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override;

private:

    /**
     * @brief	Function to generate the command to set a parameter. Command
     * 			will be sent to the ComIF over the rawPacket buffer.
     */
    ReturnValue_t generateSetParamCommand(const uint8_t * commandData,
            size_t commandDataLen);

    /**
     * @brief	Function to generate the command to get a parameter from a
     * 			gomspace device. Command will be sent to the ComIF over the
     * 			rawPacket buffer.
     */
    ReturnValue_t generateGetParamCommand(const uint8_t * commandData,
            size_t commandDataLen);

    /**
     * @brief	Function to generate the ping command for the ComIF.
     */
    ReturnValue_t generatePingCommand(const uint8_t * commandData,
            size_t commandDataLen);

    /**
     * @brief	Function to generate the command to reboot a gomspace device
     * 			via the ComIF.
     */
    void generateRebootCommand();

    /**
     * @brief	Function to generate the command to force a ground watchdog
     * 			reset in a gomspace device.
     */
    ReturnValue_t generateResetWatchdogCmd();

};

#endif /* MISSION_DEVICES_GOMSPACEDEVICEHANDLER_H_ */