#ifndef MISSION_DEVICES_PLOCMEMORYDUMPER_H_
#define MISSION_DEVICES_PLOCMEMORYDUMPER_H_

#include <linux/payload/plocMemDumpDefs.h>
#include <linux/payload/plocSupvDefs.h>

#include "OBSWConfig.h"

#ifdef XIPHOS_Q7S
#include "bsp_q7s/fs/SdCardManager.h"
#endif

#include "eive/eventSubsystemIds.h"
#include "fsfw/action/ActionHelper.h"
#include "fsfw/action/CommandActionHelper.h"
#include "fsfw/action/CommandsActionsIF.h"
#include "fsfw/action/HasActionsIF.h"
#include "fsfw/objectmanager/SystemObject.h"
#include "fsfw/returnvalues/returnvalue.h"
#include "fsfw/tasks/ExecutableObjectIF.h"
#include "objects/systemObjectList.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 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_ */