#ifndef MISSION_DEVICES_PLOCMEMORYDUMPER_H_
#define MISSION_DEVICES_PLOCMEMORYDUMPER_H_

#include <bsp_q7s/devices/devicedefinitions/PlocMemDumpDefinitions.h>
#include <bsp_q7s/devices/devicedefinitions/PlocSupervisorDefinitions.h>
#include "OBSWConfig.h"
#include "fsfw/action/CommandActionHelper.h"
#include "fsfw/action/ActionHelper.h"
#include "fsfw/action/HasActionsIF.h"
#include "fsfw/action/CommandsActionsIF.h"
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
#include "fsfw/tasks/ExecutableObjectIF.h"
#include "fsfw/objectmanager/SystemObject.h"
#include "bsp_q7s/memory/SdCardManager.h"
#include "linux/fsfwconfig/objects/systemObjectList.h"
#include "fsfw/tmtcpacket/SpacePacket.h"


/**
 * @brief   Because the buffer of the linux tty driver is limited to 2 x 65535 bytes, this class is
 *          created to perform large dumps of PLOC memories.
 *
 * @details Currently the PLOC supervisor only implements the functionality to dump the MRAM.
 *
 * @author  J. Meier
 */
class PlocMemoryDumper : public SystemObject,
        public HasActionsIF,
        public ExecutableObjectIF,
        public HasReturnvaluesIF,
        public CommandsActionsIF {
public:

    static const ActionId_t NONE = 0;
    static const ActionId_t DUMP_MRAM = 1;

    PlocMemoryDumper(object_id_t objectId);
    virtual ~PlocMemoryDumper();

    ReturnValue_t performOperation(uint8_t operationCode = 0) override;
    ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
            const uint8_t* data, size_t size);
    MessageQueueId_t getCommandQueue() const;
    ReturnValue_t initialize() override;
    MessageQueueIF* getCommandQueuePtr() override;
    void stepSuccessfulReceived(ActionId_t actionId, uint8_t step) override;
    void stepFailedReceived(ActionId_t actionId, uint8_t step, ReturnValue_t returnCode) override;
    void dataReceived(ActionId_t actionId, const uint8_t* data, uint32_t size) override;
    void completionSuccessfulReceived(ActionId_t actionId) override;
    void completionFailedReceived(ActionId_t actionId, ReturnValue_t returnCode) override;

private:

    static const uint32_t QUEUE_SIZE = 10;

    static const uint8_t INTERFACE_ID = CLASS_ID::PLOC_MEMORY_DUMPER;

    //! [EXPORT] : [COMMENT] The capacity of the MRAM amounts to 512 kB. Thus the maximum address must not be higher than 0x7d000.
    static const ReturnValue_t MRAM_ADDRESS_TOO_HIGH = MAKE_RETURN_CODE(0xA0);
    //! [EXPORT] : [COMMENT] The specified end address is lower than the start address
    static const ReturnValue_t MRAM_INVALID_ADDRESS_COMBINATION = MAKE_RETURN_CODE(0xA1);

    static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PLOC_MEMORY_DUMPER;

    //! [EXPORT] : [COMMENT] Failed to send mram dump command to supervisor handler
    //! P1: Return value of commandAction function
    //! P2: Start address of MRAM to dump with this command
    static const Event SEND_MRAM_DUMP_FAILED = MAKE_EVENT(0, severity::LOW);
    //! [EXPORT] : [COMMENT] Received completion failure report form PLOC supervisor handler
    //! P1: MRAM start address of failing dump command
    static const Event MRAM_DUMP_FAILED = MAKE_EVENT(1, severity::LOW);
    //! [EXPORT] : [COMMENT] MRAM dump finished successfully
    static const Event MRAM_DUMP_FINISHED = MAKE_EVENT(2, severity::LOW);

    // Maximum size of mram dump which can be retrieved with one command
    static const uint32_t MAX_MRAM_DUMP_SIZE = 100000;
    static const uint32_t MAX_MRAM_ADDRESS = 0x7d000;

    MessageQueueIF* commandQueue = nullptr;

    CommandActionHelper commandActionHelper;

    ActionHelper actionHelper;

    enum class State: uint8_t {
        IDLE,
        COMMAND_FIRST_MRAM_DUMP,
        COMMAND_CONSECUTIVE_MRAM_DUMP,
        EXECUTING_MRAM_DUMP
    };

    State state = State::IDLE;

    ActionId_t pendingCommand = NONE;

    typedef struct MemoryInfo {
        // Stores the start address of the next memory range to dump
        uint32_t startAddress;
        uint32_t endAddress;
        // Stores the start address of the last sent dump command
        uint32_t lastStartAddress;
    } MemoryInfo_t;

    MemoryInfo_t mram = {0, 0, 0};

    void readCommandQueue();
    void doStateMachine();

    /**
     * @brief   Sends the next mram dump command to the PLOC supervisor handler.
     */
    void commandNextMramDump(ActionId_t dumpCommand);
};

#endif /* MISSION_DEVICES_PLOCMEMORYDUMPER_H_ */