#ifndef MISSION_DEVICES_MGMLIS3CUSTOMHANDLER_H_
#define MISSION_DEVICES_MGMLIS3CUSTOMHANDLER_H_

#include <fsfw_hal/devicehandlers/devicedefinitions/mgmLis3Helpers.h>

#include "fsfw/devicehandlers/DeviceHandlerBase.h"
#include "fsfw/globalfunctions/PeriodicOperationDivider.h"
#include "mission/acs/acsBoardPolling.h"

class PeriodicOperationDivider;

/**
 * @brief   Device handler object for the LIS3MDL 3-axis magnetometer
 *          by STMicroeletronics
 * @details
 * Datasheet can be found online by googling LIS3MDL.
 * Flight manual:
 * https://egit.irs.uni-stuttgart.de/redmine/projects/eive-flight-manual/wiki/LIS3MDL_MGM
 * @author  L. Loidold, R. Mueller
 */
class MgmLis3CustomHandler : public DeviceHandlerBase {
 public:
  static constexpr DeviceCommandId_t REQUEST = 0x70;
  static constexpr DeviceCommandId_t REPLY = 0x77;

  static const uint8_t INTERFACE_ID = CLASS_ID::MGM_LIS3MDL;
  static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::MGM_LIS3MDL;

  MgmLis3CustomHandler(uint32_t objectId, object_id_t deviceCommunication, CookieIF *comCookie,
                       uint32_t transitionDelay);
  virtual ~MgmLis3CustomHandler();

  void enablePeriodicPrintouts(bool enable, uint8_t divider);
  /**
   * Set the absolute limit for the values on the axis in microtesla. The dataset values will
   * be marked as invalid if that limit is exceeded
   * @param xLimit
   * @param yLimit
   * @param zLimit
   */
  void setAbsoluteLimits(float xLimit, float yLimit, float zLimit);
  void setToGoToNormalMode(bool enable);

 protected:
  /** DeviceHandlerBase overrides */
  void doShutDown() override;
  void doStartUp() override;
  virtual uint32_t getTransitionDelayMs(Mode_t from, Mode_t to) override;
  ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand, const uint8_t *commandData,
                                        size_t commandDataLen) override;
  ReturnValue_t buildTransitionDeviceCommand(DeviceCommandId_t *id) override;
  ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t *id) override;
  ReturnValue_t scanForReply(const uint8_t *start, size_t len, DeviceCommandId_t *foundId,
                             size_t *foundLen) override;
  /**
   * This implementation is tailored towards space applications and will flag values larger
   * than 100 microtesla on X,Y and 150 microtesla on Z as invalid
   * @param id
   * @param packet
   * @return
   */
  virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) override;
  void fillCommandAndReplyMap() override;
  void modeChanged(void) override;
  ReturnValue_t initializeLocalDataPool(localpool::DataPool &localDataPoolMap,
                                        LocalDataPoolManager &poolManager) override;
  LocalPoolDataSetBase *getDataSetHandle(sid_t sid) override;

 private:
  mgmLis3::MgmPrimaryDataset dataset;
  acs::MgmLis3Request request{};

  uint32_t transitionDelay;

  float absLimitX = 100;
  float absLimitY = 100;
  float absLimitZ = 150;

  uint8_t statusRegister = 0;
  bool goToNormalMode = false;

  enum class InternalState {
    NONE,
    STARTUP,
    SHUTDOWN,
  };

  InternalState internalState = InternalState::NONE;
  bool commandExecuted = false;

  PoolEntry<float> mgmXYZ = PoolEntry<float>(3);
  PoolEntry<float> temperature = PoolEntry<float>();
  /*------------------------------------------------------------------------*/
  /* Device specific commands and variables */
  /*------------------------------------------------------------------------*/

  bool periodicPrintout = false;
  PeriodicOperationDivider debugDivider = PeriodicOperationDivider(3);

  ReturnValue_t prepareRequest(acs::SimpleSensorMode mode);
};

#endif /* MISSION_DEVICES_MGMLIS3CUSTOMHANDLER_H_ */