#pragma once

#include <fsfw/container/DynamicFIFO.h>
#include <fsfw/container/SimpleRingBuffer.h>
#include <fsfw/devicehandlers/DeviceCommunicationIF.h>
#include <fsfw/globalfunctions/DleEncoder.h>
#include <fsfw/objectmanager/SystemObject.h>
#include <fsfw/tasks/ExecutableObjectIF.h>
#include <fsfw/timemanager/Countdown.h>
#include <linux/payload/ScexDleParser.h>
#include <termios.h>  // Contains POSIX terminal control definitions

class SemaphoreIF;
class MutexIF;

class ScexUartReader : public SystemObject,
                       public ExecutableObjectIF,
                       public DeviceCommunicationIF {
  friend class UartTestClass;

 public:
  enum class States { NOT_READY, IDLE, RUNNING, FINISH };
  ScexUartReader(object_id_t objectId);

  void reset();
  ReturnValue_t finish();
  void setDebugMode(bool enable);

 private:
  SemaphoreIF *semaphore;
  bool debugMode = false;
  MutexIF *lock;
  int serialPort = 0;
  States state = States::IDLE;
  struct termios tty = {};
  bool doFinish = false;
  DleEncoder dleEncoder = DleEncoder();
  SimpleRingBuffer decodeRingBuf;

  std::array<uint8_t, 256> cmdbuf = {};
  std::array<uint8_t, 4096> recBuf = {};
  std::array<uint8_t, 4096> encodedBuf = {};
  std::array<uint8_t, 4096> decodedBuf = {};
  std::array<uint8_t, 4096> ipcBuffer = {};
  SimpleRingBuffer ipcRingBuf;
  DynamicFIFO<size_t> ipcQueue;
  ScexDleParser dleParser;

  static void foundDlePacketHandler(const DleParser::Context &ctx);
  void handleFoundDlePacket(uint8_t *packet, size_t len);
  ReturnValue_t tryDleParsing();

  ReturnValue_t performOperation(uint8_t operationCode = 0) override;

  // DeviceCommunicationIF implementation
  ReturnValue_t initializeInterface(CookieIF *cookie) override;
  ReturnValue_t sendMessage(CookieIF *cookie, const uint8_t *sendData, size_t sendLen) override;
  ReturnValue_t getSendSuccess(CookieIF *cookie) override;
  ReturnValue_t requestReceiveMessage(CookieIF *cookie, size_t requestLen) override;
  ReturnValue_t readReceivedMessage(CookieIF *cookie, uint8_t **buffer, size_t *size) override;
};