#include "VirtualChannel.h"

#include <fsfw/tasks/TaskFactory.h>

VirtualChannel::VirtualChannel(object_id_t objectId, uint8_t vcId, const char* vcName, PtmeIF& ptme,
                               const std::atomic_bool& txOn)
    : SystemObject(objectId), ptme(ptme), vcId(vcId), vcName(vcName), txOn(txOn) {}

ReturnValue_t VirtualChannel::initialize() { return returnvalue::OK; }

ReturnValue_t VirtualChannel::sendNextTm(const uint8_t* data, size_t size, size_t& writtenSize) {
  return write(data, size, writtenSize);
}

ReturnValue_t VirtualChannel::write(const uint8_t* data, size_t size, size_t& writtenSize) {
  if (!ptme.containsVc(vcId)) {
    return CHANNEL_DOES_NOT_EXIST;
  }
  return ptme.getVirtChannel(vcId)->write(data, size, writtenSize);
}

uint8_t VirtualChannel::getVcid() const { return vcId; }

ReturnValue_t VirtualChannel::advanceWrite(size_t& writtenSize) {
  if (!ptme.containsVc(vcId)) {
    return CHANNEL_DOES_NOT_EXIST;
  }
  return ptme.getVirtChannel(vcId)->advanceWrite(writtenSize);
}

bool VirtualChannel::writeActive() const {
  if (!ptme.containsVc(vcId)) {
    return CHANNEL_DOES_NOT_EXIST;
  }
  return ptme.getVirtChannel(vcId)->writeActive();
}

const char* VirtualChannel::getName() const { return vcName.c_str(); }

bool VirtualChannel::isBusy() const {
  if (!ptme.containsVc(vcId)) {
    return CHANNEL_DOES_NOT_EXIST;
  }
  return ptme.getVirtChannel(vcId)->isBusy();
}

void VirtualChannel::cancelTransfer() {
  if (!ptme.containsVc(vcId)) {
    return;
  }
  ptme.getVirtChannel(vcId)->cancelTransfer();
}

bool VirtualChannel::isTxOn() const { return txOn; }

ReturnValue_t VirtualChannel::handleWriteCompletionSynchronously(size_t& writtenSize,
                                                                 unsigned maxCompletionTimeMs) {
  unsigned delayMs = 0;
  while (true) {
    if (isBusy()) {
      if (delayMs >= maxCompletionTimeMs) {
        break;
      }
      TaskFactory::delayTask(10);
      delayMs += 10;
      continue;
    }
    ReturnValue_t result = advanceWrite(writtenSize);
    if (result == returnvalue::OK) {
      // Transfer complete
      return result;
    } else if (result != PARTIALLY_WRITTEN) {
      // Some error where we can not or should not continue the transfer.
      return result;
    }
  }
  // Timeout. Cancel the transfer
  cancelTransfer();
  return TIMEOUT;
}