#include <mission/acs/str/ArcsecDatalinkLayer.h>

ArcsecDatalinkLayer::ArcsecDatalinkLayer() : decodeRingBuf(BUFFER_LENGTHS, true) { slipInit(); }

ArcsecDatalinkLayer::~ArcsecDatalinkLayer() {}

ReturnValue_t ArcsecDatalinkLayer::checkRingBufForFrame(const uint8_t** decodedFrame,
                                                        size_t& frameLen) {
  size_t currentLen = decodeRingBuf.getAvailableReadData();
  if (currentLen == 0) {
    return DEC_IN_PROGRESS;
  }
  decodeRingBuf.readData(rxAnalysisBuffer, currentLen);
  for (size_t idx = 0; idx < currentLen; idx++) {
    enum arc_dec_result decResult =
        arc_transport_decode_body(rxAnalysisBuffer[idx], &slipInfo, decodedRxFrame, &rxFrameSize);
    switch (decResult) {
      case ARC_DEC_INPROGRESS: {
        break;
      }
      case ARC_DEC_ERROR_FRAME_SHORT: {
        decodeRingBuf.deleteData(idx);
        return REPLY_TOO_SHORT;
      }
      case ARC_DEC_ERROR_CHECKSUM:
        decodeRingBuf.deleteData(idx);
        return CRC_FAILURE;
      case ARC_DEC_ASYNC:
      case ARC_DEC_SYNC: {
        // Reset length of SLIP struct for next frame
        slipInfo.length = 0;
        if (decodedFrame != nullptr) {
          *decodedFrame = decodedRxFrame;
        }
        frameLen = rxFrameSize;
        decodeRingBuf.deleteData(idx);
        return returnvalue::OK;
      }
      default:
        sif::debug << "ArcsecDatalinkLayer::decodeFrame: Unknown result code" << std::endl;
        break;
        return returnvalue::FAILED;
    }
  }
  decodeRingBuf.deleteData(currentLen);
  return DEC_IN_PROGRESS;
}

ReturnValue_t ArcsecDatalinkLayer::feedData(const uint8_t* rawData, size_t rawDataLen) {
  if (rawDataLen > 4096) {
    sif::error << "ArcsecDatalinklayer: Can not write more than 4096 bytes to ring buffer"
               << std::endl;
    return returnvalue::FAILED;
  }
  return decodeRingBuf.writeData(rawData, rawDataLen);
}

void ArcsecDatalinkLayer::reset() {
  slipInit();
  decodeRingBuf.clear();
}

void ArcsecDatalinkLayer::slipInit() {
  slip_decode_init(rxBufferArc, sizeof(rxBufferArc), &slipInfo);
}

void ArcsecDatalinkLayer::encodeFrame(const uint8_t* data, size_t length, const uint8_t** txFrame,
                                      size_t& size) {
  arc_transport_encode_body(data, length, txEncoded, &size);
  if (txFrame != nullptr) {
    *txFrame = txEncoded;
  }
}