#include "ewsdr_dmr.h"

#include <mbelib.h>
#include <stdlib.h>
#include <string.h>

struct ewsdr_dmr_mbe {
  mbe_parms current;
  mbe_parms previous;
  mbe_parms previous_enhanced;
  int uv_quality;
};

uint32_t ewsdr_dmr_abi_version(void)
{
  return EWSDR_DMR_ABI_VERSION;
}

void ewsdr_dmr_mbe_reset(ewsdr_dmr_mbe *decoder)
{
  if (decoder == NULL)
    return;
  mbe_initMbeParms(&decoder->current, &decoder->previous,
                   &decoder->previous_enhanced);
}

ewsdr_dmr_mbe *ewsdr_dmr_mbe_create(int uv_quality)
{
  ewsdr_dmr_mbe *decoder = calloc(1, sizeof(*decoder));
  if (decoder == NULL)
    return NULL;
  if (uv_quality < 1)
    uv_quality = 1;
  if (uv_quality > 64)
    uv_quality = 64;
  decoder->uv_quality = uv_quality;
  ewsdr_dmr_mbe_reset(decoder);
  return decoder;
}

void ewsdr_dmr_mbe_destroy(ewsdr_dmr_mbe *decoder)
{
  if (decoder == NULL)
    return;
  memset(decoder, 0, sizeof(*decoder));
  free(decoder);
}

int ewsdr_dmr_mbe_decode(ewsdr_dmr_mbe *decoder,
                         const uint8_t ambe_bits[EWSDR_DMR_AMBE_BITS],
                         float pcm_out[EWSDR_DMR_PCM_SAMPLES],
                         ewsdr_dmr_mbe_result *result)
{
  char frame[4][24];
  char data[49];
  char error_text[64];
  int errors_c0 = 0;
  int errors_total = 0;
  size_t row;
  size_t col;

  if (decoder == NULL || ambe_bits == NULL || pcm_out == NULL)
    return -1;

  for (row = 0; row < 4; ++row) {
    for (col = 0; col < 24; ++col) {
      const uint8_t bit = ambe_bits[row * 24 + col];
      if (bit > 1)
        return -2;
      frame[row][col] = (char)bit;
    }
  }

  memset(data, 0, sizeof(data));
  memset(error_text, 0, sizeof(error_text));
  mbe_processAmbe3600x2450Framef(
      pcm_out, &errors_c0, &errors_total, error_text, frame, data,
      &decoder->current, &decoder->previous, &decoder->previous_enhanced,
      decoder->uv_quality);

  if (result != NULL) {
    result->errors_c0 = errors_c0;
    result->errors_total = errors_total;
  }
  return 0;
}
