#ifndef MISSION_DEVICES_SUSHANDLER_H_
#define MISSION_DEVICES_SUSHANDLER_H_

#include <fsfw/devicehandlers/DeviceHandlerBase.h>

#include "devicedefinitions/SusDefinitions.h"
#include "events/subsystemIdRanges.h"
#include "fsfw/globalfunctions/PeriodicOperationDivider.h"
#include "mission/devices/max1227.h"
#include "returnvalues/classIds.h"

/**
 * @brief	This is the device handler class for the SUS sensor based on the MAX1227 ADC.
 *
 * @details
 * Datasheet of MAX1227: https://datasheets.maximintegrated.com/en/ds/MAX1227-MAX1231.pdf
 * Details about the SUS electronic can be found at
 * https://egit.irs.uni-stuttgart.de/eive/eive_dokumente/src/branch/master/400_Raumsegment/443_SunSensorDocumentation/release
 *
 * @note    When adding a SusHandler to the polling sequence table make sure to add a slot with
 *          the executionStep FIRST_WRITE. Otherwise the communication sequence will never be
 *          started.
 *
 * @author	J. Meier
 */
class SusHandler : public DeviceHandlerBase {
 public:
  enum ClkModes { INT_CLOCKED, EXT_CLOCKED, EXT_CLOCKED_WITH_TEMP };

  static const uint8_t FIRST_WRITE = 7;

  SusHandler(object_id_t objectId, uint8_t susIdx, object_id_t comIF, CookieIF* comCookie);
  virtual ~SusHandler();

  void enablePeriodicPrintout(bool enable, uint8_t divider);

  void setToGoToNormalMode(bool enable);

 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;
  uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) override;
  ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
                                        LocalDataPoolManager& poolManager) override;

 private:
  static const uint8_t INTERFACE_ID = CLASS_ID::SUS_HANDLER;

  static const ReturnValue_t ERROR_UNLOCK_MUTEX = MAKE_RETURN_CODE(0xA0);
  static const ReturnValue_t ERROR_LOCK_MUTEX = MAKE_RETURN_CODE(0xA1);

  enum class ComStates {
    IDLE,
    WRITE_SETUP,
    EXT_CLOCKED_CONVERSIONS,
    EXT_CLOCKED_TEMP,
    START_INT_CLOCKED_CONVERSIONS,
    READ_INT_CLOCKED_CONVERSIONS
  };

  bool periodicPrintout = false;
  PeriodicOperationDivider divider;
  bool goToNormalModeImmediately = false;
  bool commandExecuted = false;

  SUS::SusDataset dataset;
  // Read temperature in each alternating communication step when using
  // externally clocked mode
  ClkModes clkMode = ClkModes::INT_CLOCKED;
  PoolEntry<float> tempC = PoolEntry<float>({0.0});
  PoolEntry<uint16_t> channelVec = PoolEntry<uint16_t>({0, 0, 0, 0, 0, 0});

  uint8_t susIdx = 0;
  uint8_t cmdBuffer[SUS::MAX_CMD_SIZE];
  ComStates comState = ComStates::IDLE;

  MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
  uint32_t timeoutMs = 20;
  void printDataset();

  MutexIF* spiMutex = nullptr;
};

#endif /* MISSION_DEVICES_SUSHANDLER_H_ */