#ifndef BSP_Q7S_DEVICES_ARCSECDATALINKLAYER_H_
#define BSP_Q7S_DEVICES_ARCSECDATALINKLAYER_H_

#include <fsfw/container/SimpleRingBuffer.h>
#include <fsfw/devicehandlers/CookieIF.h>
#include <mission/acs/str/strHelpers.h>

#include "eive/resultClassIds.h"
#include "fsfw/returnvalues/returnvalue.h"

extern "C" {
#include <wire/common/SLIP.h>
}

/**
 * @brief   Helper class to handle the datalinklayer of replies from the star tracker of arcsec.
 */
class ArcsecDatalinkLayer {
 public:
  static const uint8_t INTERFACE_ID = CLASS_ID::STR_HANDLER;

  //! [EXPORT] : [COMMENT] More data required to complete frame
  static const ReturnValue_t DEC_IN_PROGRESS = MAKE_RETURN_CODE(0xA0);
  //! [EXPORT] : [COMMENT] Data too short to represent a valid frame
  static const ReturnValue_t REPLY_TOO_SHORT = MAKE_RETURN_CODE(0xA1);
  //! [EXPORT] : [COMMENT] Detected CRC failure in received frame
  static const ReturnValue_t CRC_FAILURE = MAKE_RETURN_CODE(0xA2);
  static const ReturnValue_t SLIP_OVERFLOW_RETVAL = MAKE_RETURN_CODE(0xA3);
  static const ReturnValue_t SLIP_ID_MISSMATCH_RETVAL = MAKE_RETURN_CODE(0xA4);

  static const uint8_t STATUS_OK = 0;

  static constexpr size_t BUFFER_LENGTHS = 4096;

  ArcsecDatalinkLayer();
  virtual ~ArcsecDatalinkLayer();

  /**
   * Feed received data to the internal ring buffer.
   * @param rawData
   * @param rawDataLen
   * @return
   */
  ReturnValue_t feedData(const uint8_t* rawData, size_t rawDataLen);

  /**
   * Runs the arcsec datalink layer decoding algorithm on the data in the ring buffer, decoding
   * frames in the process.
   * @param decodedFrame
   * @param frameLen
   * @return
   *   - returnvalue::OK if a frame was found
   *   - DEC_IN_PROGRESS if frame decoding is in progress
   *   - Anything else is a decoding error
   */
  ReturnValue_t checkRingBufForFrame(const uint8_t** decodedFrame, size_t& frameLen);

  /**
   * @brief   SLIP encodes data pointed to by data pointer.
   *
   * @param data   Pointer to data to encode
   * @param length Length of buffer to encode
   */
  void encodeFrame(const uint8_t* data, size_t length, const uint8_t** txFrame, size_t& frameLen);

  void reset();

 private:
  static const uint8_t ID_OFFSET = 1;
  static const uint8_t STATUS_OFFSET = 2;

  // User to buffer and analyse data and allow feeding and checking for frames asychronously.
  SimpleRingBuffer decodeRingBuf;
  uint8_t rxAnalysisBuffer[BUFFER_LENGTHS];

  // Used by arcsec slip decoding function to process received data. This should only be written
  // to or read from by arcsec functions!
  uint8_t rxBufferArc[startracker::MAX_FRAME_SIZE];
  // Decoded frame will be copied to this buffer
  uint8_t decodedRxFrame[startracker::MAX_FRAME_SIZE];
  // Size of decoded frame
  size_t rxFrameSize = 0;

  // Buffer where encoded frames will be stored. First byte of encoded frame represents type of
  // reply
  uint8_t txEncoded[startracker::MAX_FRAME_SIZE * 2 + 2];
  // Size of encoded frame
  uint32_t txFrameSize = 0;

  // slip_decode_state slipInfo;

  void slipInit();
};

#endif /* BSP_Q7S_DEVICES_ARCSECDATALINKLAYER_H_ */