#include "TmFunnelBase.h"

#include <fsfw/tmtcservices/TmTcMessage.h>

#include <atomic>
#include <filesystem>
#include <fstream>

#include "fsfw/ipc/QueueFactory.h"

TmFunnelBase::TmFunnelBase(FunnelCfg cfg)
    : SystemObject(cfg.objectId),
      name(cfg.name),
      tmStore(cfg.tmStore),
      ipcStore(cfg.ipcStore),
      tmQueue(QueueFactory::instance()->createMessageQueue(cfg.tmMsgDepth)),
      liveDemux(*tmQueue),
      sdcMan(cfg.sdcMan),
      sequenceCounterFilename(cfg.sequenceCounterFilename),
      saveSequenceCount(cfg.saveSequenceCount) {}

ReturnValue_t TmFunnelBase::demultiplexLivePackets(store_address_t origStoreId,
                                                   const uint8_t *tmData, size_t tmSize) {
  return liveDemux.demultiplexPackets(tmStore, origStoreId, tmData, tmSize);
}

TmFunnelBase::~TmFunnelBase() { QueueFactory::instance()->deleteMessageQueue(tmQueue); }

MessageQueueId_t TmFunnelBase::getReportReceptionQueue(uint8_t virtualChannel) const {
  return tmQueue->getId();
}

void TmFunnelBase::addLiveDestination(const char *name,
                                      const AcceptsTelemetryIF &downlinkDestination, uint8_t vcid) {
  liveDemux.addDestination(name, downlinkDestination, vcid);
}

ReturnValue_t TmFunnelBase::initialize() {
  using namespace std::filesystem;
  // The filesystem should always be available at the start.. Let's assume it always is, otherwise
  // we just live with a regular 0 initialization. It simplifies a lot.
  std::error_code e;
  path filePath =
      path(path(sdcMan.getCurrentMountPrefix()) / path("conf") / path(sequenceCounterFilename));
  if (exists(filePath, e)) {
    std::ifstream ifile(filePath);
    if (ifile.bad()) {
      sif::error << "TmFunnelBase::initialize: Faulty file open for sequence counter initialization"
                 << std::endl;
      return returnvalue::OK;
    }
    if (not(ifile >> sourceSequenceCount)) {
      // Initialize to 0 in any case if reading a number failed.
      sourceSequenceCount = 0;
    }
  }
  return returnvalue::OK;
}

ReturnValue_t TmFunnelBase::saveSequenceCountToFile() {
  using namespace std::filesystem;
  std::error_code e;
  path filePath =
      path(path(sdcMan.getCurrentMountPrefix()) / path("conf") / path(sequenceCounterFilename));
  std::ofstream ofile(filePath);
  if (ofile.bad()) {
    return returnvalue::FAILED;
  }
  ofile << sourceSequenceCount << "\n";
  return returnvalue::OK;
}